From 4e049e2c3658ee2bc6e63e696a3779d2f9eed377 Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Sat, 1 Jul 2017 12:39:51 +0200 Subject: [PATCH] Add UI functions to set result with explicit length and to retrieve the length This allows completely arbitrary passphrases to be entered, including NUL bytes. Reviewed-by: Ben Kaduk (Merged from https://github.com/openssl/openssl/pull/3821) --- crypto/err/openssl.txt | 2 ++ crypto/ui/ui_err.c | 3 +++ crypto/ui/ui_lib.c | 58 ++++++++++++++++++++++++++++++++++------- crypto/ui/ui_locl.h | 1 + crypto/ui/ui_util.c | 2 +- doc/man3/UI_STRING.pod | 23 ++++++++++++---- doc/man3/UI_new.pod | 9 +++++-- include/openssl/ui.h | 3 +++ include/openssl/uierr.h | 2 ++ util/libcrypto.num | 3 +++ 10 files changed, 89 insertions(+), 17 deletions(-) diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 4b3c55b010..253e0ab29c 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -1355,9 +1355,11 @@ UI_F_UI_DUP_INPUT_STRING:103:UI_dup_input_string UI_F_UI_DUP_USER_DATA:118:UI_dup_user_data UI_F_UI_DUP_VERIFY_STRING:106:UI_dup_verify_string UI_F_UI_GET0_RESULT:107:UI_get0_result +UI_F_UI_GET_RESULT_LENGTH:119:UI_get_result_length UI_F_UI_NEW_METHOD:104:UI_new_method UI_F_UI_PROCESS:113:UI_process UI_F_UI_SET_RESULT:105:UI_set_result +UI_F_UI_SET_RESULT_EX:120:UI_set_result_ex X509V3_F_A2I_GENERAL_NAME:164:a2i_GENERAL_NAME X509V3_F_ADDR_VALIDATE_PATH_INTERNAL:166:addr_validate_path_internal X509V3_F_ASIDENTIFIERCHOICE_CANONIZE:161:ASIdentifierChoice_canonize diff --git a/crypto/ui/ui_err.c b/crypto/ui/ui_err.c index 6a44f7a81b..e69163c470 100644 --- a/crypto/ui/ui_err.c +++ b/crypto/ui/ui_err.c @@ -33,9 +33,12 @@ static const ERR_STRING_DATA UI_str_functs[] = { {ERR_PACK(ERR_LIB_UI, UI_F_UI_DUP_VERIFY_STRING, 0), "UI_dup_verify_string"}, {ERR_PACK(ERR_LIB_UI, UI_F_UI_GET0_RESULT, 0), "UI_get0_result"}, + {ERR_PACK(ERR_LIB_UI, UI_F_UI_GET_RESULT_LENGTH, 0), + "UI_get_result_length"}, {ERR_PACK(ERR_LIB_UI, UI_F_UI_NEW_METHOD, 0), "UI_new_method"}, {ERR_PACK(ERR_LIB_UI, UI_F_UI_PROCESS, 0), "UI_process"}, {ERR_PACK(ERR_LIB_UI, UI_F_UI_SET_RESULT, 0), "UI_set_result"}, + {ERR_PACK(ERR_LIB_UI, UI_F_UI_SET_RESULT_EX, 0), "UI_set_result_ex"}, {0, NULL} }; diff --git a/crypto/ui/ui_lib.c b/crypto/ui/ui_lib.c index 5b3eaff121..4727d56b82 100644 --- a/crypto/ui/ui_lib.c +++ b/crypto/ui/ui_lib.c @@ -441,6 +441,19 @@ const char *UI_get0_result(UI *ui, int i) return UI_get0_result_string(sk_UI_STRING_value(ui->strings, i)); } +int UI_get_result_length(UI *ui, int i) +{ + if (i < 0) { + UIerr(UI_F_UI_GET_RESULT_LENGTH, UI_R_INDEX_TOO_SMALL); + return -1; + } + if (i >= sk_UI_STRING_num(ui->strings)) { + UIerr(UI_F_UI_GET_RESULT_LENGTH, UI_R_INDEX_TOO_LARGE); + return -1; + } + return UI_get_result_string_length(sk_UI_STRING_value(ui->strings, i)); +} + static int print_error(const char *str, size_t len, UI *ui) { UI_STRING uis; @@ -796,6 +809,21 @@ const char *UI_get0_result_string(UI_STRING *uis) return NULL; } +int UI_get_result_string_length(UI_STRING *uis) +{ + switch (uis->type) { + case UIT_PROMPT: + case UIT_VERIFY: + return uis->result_len; + case UIT_NONE: + case UIT_BOOLEAN: + case UIT_INFO: + case UIT_ERROR: + break; + } + return -1; +} + const char *UI_get0_test_string(UI_STRING *uis) { switch (uis->type) { @@ -843,8 +871,18 @@ int UI_get_result_maxsize(UI_STRING *uis) int UI_set_result(UI *ui, UI_STRING *uis, const char *result) { - int l = strlen(result); +#if 0 + /* + * This is placed here solely to preserve UI_F_UI_SET_RESULT + * To be removed for OpenSSL 1.2.0 + */ + UIerr(UI_F_UI_SET_RESULT, ERR_R_DISABLED); +#endif + return UI_set_result_ex(ui, uis, result, strlen(result)); +} +int UI_set_result_ex(UI *ui, UI_STRING *uis, const char *result, int len) +{ ui->flags &= ~UI_FLAG_REDOABLE; switch (uis->type) { @@ -859,16 +897,16 @@ int UI_set_result(UI *ui, UI_STRING *uis, const char *result) BIO_snprintf(number2, sizeof(number2), "%d", uis->_.string_data.result_maxsize); - if (l < uis->_.string_data.result_minsize) { + if (len < uis->_.string_data.result_minsize) { ui->flags |= UI_FLAG_REDOABLE; - UIerr(UI_F_UI_SET_RESULT, UI_R_RESULT_TOO_SMALL); + UIerr(UI_F_UI_SET_RESULT_EX, UI_R_RESULT_TOO_SMALL); ERR_add_error_data(5, "You must type in ", number1, " to ", number2, " characters"); return -1; } - if (l > uis->_.string_data.result_maxsize) { + if (len > uis->_.string_data.result_maxsize) { ui->flags |= UI_FLAG_REDOABLE; - UIerr(UI_F_UI_SET_RESULT, UI_R_RESULT_TOO_LARGE); + UIerr(UI_F_UI_SET_RESULT_EX, UI_R_RESULT_TOO_LARGE); ERR_add_error_data(5, "You must type in ", number1, " to ", number2, " characters"); return -1; @@ -876,19 +914,21 @@ int UI_set_result(UI *ui, UI_STRING *uis, const char *result) } if (uis->result_buf == NULL) { - UIerr(UI_F_UI_SET_RESULT, UI_R_NO_RESULT_BUFFER); + UIerr(UI_F_UI_SET_RESULT_EX, UI_R_NO_RESULT_BUFFER); return -1; } - OPENSSL_strlcpy(uis->result_buf, result, - uis->_.string_data.result_maxsize + 1); + memcpy(uis->result_buf, result, len); + if (len <= uis->_.string_data.result_maxsize) + uis->result_buf[len] = '\0'; + uis->result_len = len; break; case UIT_BOOLEAN: { const char *p; if (uis->result_buf == NULL) { - UIerr(UI_F_UI_SET_RESULT, UI_R_NO_RESULT_BUFFER); + UIerr(UI_F_UI_SET_RESULT_EX, UI_R_NO_RESULT_BUFFER); return -1; } diff --git a/crypto/ui/ui_locl.h b/crypto/ui/ui_locl.h index 1b0d596ccd..19b33b8fc6 100644 --- a/crypto/ui/ui_locl.h +++ b/crypto/ui/ui_locl.h @@ -71,6 +71,7 @@ struct ui_string_st { * Otherwise, it may be allocated by the UI * routine, meaning result_minsize is going * to be overwritten. */ + size_t result_len; union { struct { int result_minsize; /* Input: minimum required size of the diff --git a/crypto/ui/ui_util.c b/crypto/ui/ui_util.c index dbfeeccffb..7249a077d8 100644 --- a/crypto/ui/ui_util.c +++ b/crypto/ui/ui_util.c @@ -116,7 +116,7 @@ static int ui_read(UI *ui, UI_STRING *uis) result[len] = '\0'; if (len <= 0) return len; - if (UI_set_result(ui, uis, result) >= 0) + if (UI_set_result_ex(ui, uis, result, len) >= 0) return 1; return 0; } diff --git a/doc/man3/UI_STRING.pod b/doc/man3/UI_STRING.pod index 340d9b2ae2..5a464a37a5 100644 --- a/doc/man3/UI_STRING.pod +++ b/doc/man3/UI_STRING.pod @@ -4,9 +4,9 @@ UI_STRING, UI_string_types, UI_get_string_type, UI_get_input_flags, UI_get0_output_string, -UI_get0_action_string, UI_get0_result_string, +UI_get0_action_string, UI_get0_result_string, UI_get_result_string_length, UI_get0_test_string, UI_get_result_minsize, -UI_get_result_maxsize, UI_set_result +UI_get_result_maxsize, UI_set_result, UI_set_result_ex - User interface string parsing =head1 SYNOPSIS @@ -29,10 +29,12 @@ UI_get_result_maxsize, UI_set_result const char *UI_get0_output_string(UI_STRING *uis); const char *UI_get0_action_string(UI_STRING *uis); const char *UI_get0_result_string(UI_STRING *uis); + int UI_get_result_string_length(UI_STRING *uis); const char *UI_get0_test_string(UI_STRING *uis); int UI_get_result_minsize(UI_STRING *uis); int UI_get_result_maxsize(UI_STRING *uis); int UI_set_result(UI *ui, UI_STRING *uis, const char *result); + int UI_set_result_ex(UI *ui, UI_STRING *uis, const char *result, int len); =head1 DESCRIPTION @@ -60,9 +62,11 @@ associated with a B type B. For all other B types, NULL is returned. See L. -UI_get0_result_string() is used to retrieve the result of a prompt. +UI_get0_result_string() and UI_get_result_string_length() are used to +retrieve the result of a prompt and its length. This is only useful for B and B type strings. -For all other B types, NULL is returned. +For all other B types, UI_get0_result_string() returns NULL +and UI_get_result_string_length() returns -1. UI_get0_test_string() is used to retrieve the string to compare the prompt result with. @@ -74,7 +78,7 @@ retrieve the minimum and maximum required size of the result. This is only useful for B and B type strings. For all other B types, -1 is returned. -UI_set_result() is used to set the result value of a prompt. +UI_set_result_ex() is used to set the result value of a prompt and its length. For B and B type UI strings, this sets the result retrievable with UI_get0_result_string() by copying the contents of B if its length fits the minimum and maximum size @@ -88,6 +92,11 @@ set to the NUL char C<\0>. See L for more information on B and B. +UI_set_result() does the same thing as UI_set_result_ex(), but calculates +its length internally. +It expects the string to be terminated with a NUL byte, and is therefore +only useful with normal C strings. + =head1 RETURN VALUES UI_get_string_type() returns the UI string type. @@ -103,6 +112,10 @@ UI_get0_result_string() returns the UI string result buffer for B and B type UI strings, NULL for any other type. +UI_get_result_string_length() returns the UI string result buffer's +content length for B and B type UI strings, +-1 for any other type. + UI_get0_test_string() returns the UI string action description string for B type UI strings, NULL for any other type. diff --git a/doc/man3/UI_new.pod b/doc/man3/UI_new.pod index 469ea53a32..39b24daa3c 100644 --- a/doc/man3/UI_new.pod +++ b/doc/man3/UI_new.pod @@ -8,6 +8,7 @@ UI_add_verify_string, UI_dup_verify_string, UI_add_input_boolean, UI_dup_input_boolean, UI_add_info_string, UI_dup_info_string, UI_add_error_string, UI_dup_error_string, UI_construct_prompt, UI_add_user_data, UI_dup_user_data, UI_get0_user_data, UI_get0_result, +UI_get_result_length, UI_process, UI_ctrl, UI_set_default_method, UI_get_default_method, UI_get_method, UI_set_method, UI_OpenSSL, UI_null - user interface @@ -50,6 +51,7 @@ UI_get_method, UI_set_method, UI_OpenSSL, UI_null - user interface void *UI_get0_user_data(UI *ui); const char *UI_get0_result(UI *ui, int i); + int UI_get_result_length(UI *ui, int i); int UI_process(UI *ui); @@ -82,12 +84,12 @@ user-defined random data can be passed down to the underlying method through calls to UI_add_user_data() or UI_dup_user_data(). The default UI method doesn't care about these data, but other methods might. Finally, use UI_process() to actually perform the prompting and UI_get0_result() -to find the result to the prompt. +and UI_get_result_length() to find the result to the prompt and its length. A UI can contain more than one prompt, which are performed in the given sequence. Each prompt gets an index number which is returned by the UI_add and UI_dup functions, and has to be used to get the corresponding -result with UI_get0_result(). +result with UI_get0_result() and UI_get_result_length(). UI_process() can be called more than once on the same UI, thereby allowing a UI to have a long lifetime, but can just as well have a short lifetime. @@ -173,6 +175,9 @@ UI with UI_add_user_data() or UI_dup_user_data. UI_get0_result() returns a pointer to the result buffer associated with the information indexed by I. +UI_get_result_length() returns the length of the result buffer associated with +the information indexed by I. + UI_process() goes through the information given so far, does all the printing and prompting and returns the final status, which is -2 on out-of-band events (Interrupt, Cancel, ...), -1 on error and 0 on success. diff --git a/include/openssl/ui.h b/include/openssl/ui.h index 0f8c03f8ed..a0246745bf 100644 --- a/include/openssl/ui.h +++ b/include/openssl/ui.h @@ -175,6 +175,7 @@ void *UI_get0_user_data(UI *ui); /* Return the result associated with a prompt given with the index i. */ const char *UI_get0_result(UI *ui, int i); +int UI_get_result_length(UI *ui, int i); /* When all strings have been added, process the whole thing. */ int UI_process(UI *ui); @@ -340,6 +341,7 @@ const char *UI_get0_output_string(UI_STRING *uis); const char *UI_get0_action_string(UI_STRING *uis); /* Return the result of a prompt */ const char *UI_get0_result_string(UI_STRING *uis); +int UI_get_result_string_length(UI_STRING *uis); /* * Return the string to test the result against. Only useful with verifies. */ @@ -350,6 +352,7 @@ int UI_get_result_minsize(UI_STRING *uis); int UI_get_result_maxsize(UI_STRING *uis); /* Set the result of a UI_STRING. */ int UI_set_result(UI *ui, UI_STRING *uis, const char *result); +int UI_set_result_ex(UI *ui, UI_STRING *uis, const char *result, int len); /* A couple of popular utility functions */ int UI_UTIL_read_pw_string(char *buf, int length, const char *prompt, diff --git a/include/openssl/uierr.h b/include/openssl/uierr.h index 3550650ca7..f7c77f2ed1 100644 --- a/include/openssl/uierr.h +++ b/include/openssl/uierr.h @@ -37,9 +37,11 @@ int ERR_load_UI_strings(void); # define UI_F_UI_DUP_USER_DATA 118 # define UI_F_UI_DUP_VERIFY_STRING 106 # define UI_F_UI_GET0_RESULT 107 +# define UI_F_UI_GET_RESULT_LENGTH 119 # define UI_F_UI_NEW_METHOD 104 # define UI_F_UI_PROCESS 113 # define UI_F_UI_SET_RESULT 105 +# define UI_F_UI_SET_RESULT_EX 120 /* * UI reason codes. diff --git a/util/libcrypto.num b/util/libcrypto.num index 8a276b96cd..30cea8c15f 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4390,3 +4390,6 @@ EVP_aria_128_gcm 4333 1_1_1 EXIST::FUNCTION:ARIA EVP_aria_128_ccm 4334 1_1_1 EXIST::FUNCTION:ARIA EVP_aria_192_gcm 4335 1_1_1 EXIST::FUNCTION:ARIA CRYPTO_THREAD_glock_new 4336 1_1_1 EXIST::FUNCTION: +UI_get_result_length 4337 1_1_1 EXIST::FUNCTION: +UI_set_result_ex 4338 1_1_1 EXIST::FUNCTION: +UI_get_result_string_length 4339 1_1_1 EXIST::FUNCTION: -- 2.25.1