-
Notifications
You must be signed in to change notification settings - Fork 135
Add password prompting support & EVP_read_pw_string #2419
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
070a228
44dd2a4
ea4c7a2
39bbfbc
f8a9683
f736fde
a033226
ec77da4
634337a
9dae8f1
ee55385
fa2e7d8
62d4dbd
96a869c
66c1c44
46a4745
b4f77f0
e3e655d
f534da3
efbbacb
2326f88
bf0c1ea
3ba16be
cb9db66
96feba4
0f7e7e2
d9811a6
a86543e
eb4a1a3
e381e37
1a49aa6
beb95bb
517d5b6
bcceaff
78ed56b
99c3bfc
abaf497
2b893cd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,335 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 OR ISC | ||
|
||
#include <assert.h> | ||
#include <ctype.h> | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include <signal.h> | ||
#include <errno.h> | ||
|
||
#include <openssl/buf.h> | ||
#include <openssl/err.h> | ||
#include <openssl/evp.h> | ||
#include <openssl/pem.h> | ||
#include <openssl/x509.h> | ||
|
||
#include "internal.h" | ||
#include "../internal.h" | ||
|
||
|
||
// We support two types of terminal interface: | ||
// - termios for Linux/Unix | ||
// - WIN32 Console for Windows | ||
#if !defined(OPENSSL_WINDOWS) | ||
#include <termios.h> | ||
#define DEV_TTY "/dev/tty" | ||
#define TTY_STRUCT struct termios | ||
#define TTY_FLAGS c_lflag | ||
#define TTY_get(tty,data) tcgetattr(tty, data) | ||
#define TTY_set(tty,data) tcsetattr(tty, TCSANOW, data) | ||
#else /* OPENSSL_WINDOWS */ | ||
#include <windows.h> | ||
#endif | ||
|
||
#define NUM_SIG 32 | ||
|
||
static volatile sig_atomic_t intr_signal; | ||
static struct CRYPTO_STATIC_MUTEX console_global_mutex = CRYPTO_STATIC_MUTEX_INIT; | ||
|
||
#if !defined(OPENSSL_WINDOWS) | ||
static struct sigaction savsig[NUM_SIG]; | ||
#else | ||
static void (*savsig[NUM_SIG]) (int); | ||
#endif | ||
|
||
#if defined(OPENSSL_WINDOWS) | ||
DWORD tty_orig, tty_new; | ||
#else | ||
TTY_STRUCT tty_orig, tty_new; | ||
#endif | ||
|
||
FILE *tty_in, *tty_out; | ||
int is_a_tty; | ||
|
||
|
||
static void popsig(void) { | ||
#if !defined(OPENSSL_WINDOWS) | ||
for (int i = 1; i < NUM_SIG; i++) { | ||
if (i == SIGUSR1 || i == SIGUSR2 || i == SIGKILL) { | ||
continue; | ||
} | ||
sigaction(i, &savsig[i], NULL); | ||
} | ||
#else | ||
signal(SIGABRT, savsig[SIGABRT]); | ||
signal(SIGFPE, savsig[SIGFPE]); | ||
signal(SIGILL, savsig[SIGILL]); | ||
signal(SIGINT, savsig[SIGINT]); | ||
signal(SIGSEGV, savsig[SIGSEGV]); | ||
signal(SIGTERM, savsig[SIGTERM]); | ||
#endif | ||
} | ||
|
||
static void recsig(int signal) { | ||
intr_signal = signal; | ||
} | ||
|
||
static int discard_line_remainder(FILE *in) { | ||
char buf[5]; | ||
|
||
do { | ||
if (!fgets(buf, 4, in)) { | ||
if (ferror(in)) { | ||
OPENSSL_PUT_ERROR(PEM, PEM_R_PROBLEMS_GETTING_PASSWORD); | ||
ERR_add_error_data(2, "System error: ", strerror(errno)); | ||
clearerr(tty_in); | ||
smittals2 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} else if(feof(in)) { | ||
return 1; | ||
} | ||
return 0; | ||
} | ||
} while (strchr(buf, '\n') == NULL); | ||
return 1; | ||
} | ||
|
||
/* Signal handling functions */ | ||
static void pushsig(void) { | ||
#if !defined(OPENSSL_WINDOWS) | ||
struct sigaction sa; | ||
OPENSSL_cleanse(&sa, sizeof(sa)); | ||
|
||
sa.sa_handler = recsig; | ||
|
||
for (int i = 1; i < NUM_SIG; i++) { | ||
if (i == SIGUSR1 || i == SIGUSR2 || i == SIGKILL) { | ||
continue; | ||
} | ||
sigaction(i, &sa, &savsig[i]); | ||
} | ||
#else // Specific error codes for windows | ||
savsig[SIGABRT] = signal(SIGABRT, recsig); | ||
savsig[SIGFPE] = signal(SIGFPE, recsig); | ||
savsig[SIGILL] = signal(SIGILL, recsig); | ||
savsig[SIGINT] = signal(SIGINT, recsig); | ||
savsig[SIGSEGV] = signal(SIGSEGV, recsig); | ||
savsig[SIGTERM] = signal(SIGTERM, recsig); | ||
#endif | ||
|
||
// set SIGWINCH handler to default so our workflow is not | ||
// triggered on user resizing of window | ||
#if defined(SIGWINCH) && defined(SIG_DFL) | ||
signal(SIGWINCH, SIG_DFL); | ||
#endif | ||
} | ||
|
||
/* Console management functions */ | ||
void openssl_console_acquire_mutex(void) { | ||
CRYPTO_STATIC_MUTEX_lock_write(&console_global_mutex); | ||
} | ||
|
||
void openssl_console_release_mutex(void) { | ||
CRYPTO_STATIC_MUTEX_unlock_write(&console_global_mutex); | ||
} | ||
|
||
int openssl_console_open(void) { | ||
is_a_tty = 1; | ||
assert(CRYPTO_STATIC_MUTEX_is_write_locked(&console_global_mutex)); | ||
|
||
#if !defined(OPENSSL_WINDOWS) | ||
if ((tty_in = fopen(DEV_TTY, "r")) == NULL) { | ||
tty_in = stdin; | ||
} | ||
if ((tty_out = fopen(DEV_TTY, "w")) == NULL) { | ||
tty_out = stderr; | ||
} | ||
if (TTY_get(fileno(tty_in), &tty_orig) == -1) { | ||
if (errno == ENOTTY || errno == EINVAL || errno == ENXIO || errno == EIO | ||
|| errno == EPERM || errno == ENODEV) { | ||
is_a_tty = 0; | ||
} else { | ||
OPENSSL_PUT_ERROR(PEM, ERR_R_INTERNAL_ERROR); | ||
return 0; | ||
} | ||
} | ||
#else | ||
DWORD console_mode; | ||
HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); | ||
|
||
// Check if console (equivalent to checking for /dev/tty on Linux) | ||
if (GetConsoleMode(hStdIn, &console_mode)) { | ||
// It's a real console, use conin$ and conout$ to bypass any redirection | ||
if ((tty_in = fopen("conin$", "r")) == NULL) { | ||
tty_in = stdin; | ||
} | ||
if ((tty_out = fopen("conout$", "w")) == NULL) { | ||
tty_out = stderr; | ||
} | ||
|
||
tty_orig = console_mode; | ||
} else { | ||
// Not a console, use stdin/stderr | ||
tty_in = stdin; | ||
tty_out = stderr; | ||
is_a_tty = 0; | ||
} | ||
#endif | ||
return 1; | ||
} | ||
|
||
int openssl_console_close(void) { | ||
assert(CRYPTO_STATIC_MUTEX_is_write_locked(&console_global_mutex)); | ||
if (tty_in != stdin) { | ||
fclose(tty_in); | ||
} | ||
if (tty_out != stderr) { | ||
fclose(tty_out); | ||
} | ||
|
||
return 1; | ||
} | ||
|
||
static int openssl_console_echo_disable(void) { | ||
#if !defined(OPENSSL_WINDOWS) | ||
OPENSSL_memcpy(&(tty_new), &(tty_orig), sizeof(tty_orig)); | ||
tty_new.TTY_FLAGS &= ~ECHO; | ||
|
||
if (is_a_tty && (TTY_set(fileno(tty_in), &tty_new) == -1)) { | ||
OPENSSL_PUT_ERROR(PEM, ERR_R_INTERNAL_ERROR); | ||
return 0; | ||
} | ||
#else | ||
if (is_a_tty) { | ||
tty_new = tty_orig; | ||
tty_new &= ~ENABLE_ECHO_INPUT; | ||
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), tty_new); | ||
} | ||
#endif | ||
|
||
return 1; | ||
} | ||
|
||
static int openssl_console_echo_enable(void) { | ||
#if !defined(OPENSSL_WINDOWS) | ||
OPENSSL_memcpy(&(tty_new), &(tty_orig), sizeof(tty_orig)); | ||
if (is_a_tty && (TTY_set(fileno(tty_in), &tty_new) == -1)) { | ||
OPENSSL_PUT_ERROR(PEM, ERR_R_INTERNAL_ERROR); | ||
return 0; | ||
} | ||
#else | ||
if (is_a_tty) { | ||
tty_new = tty_orig; | ||
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), tty_new); | ||
} | ||
#endif | ||
return 1; | ||
} | ||
|
||
int openssl_console_write(const char *str) { | ||
assert(CRYPTO_STATIC_MUTEX_is_write_locked(&console_global_mutex)); | ||
if (fputs(str, tty_out) < 0 || fflush(tty_out) != 0) { | ||
OPENSSL_PUT_ERROR(PEM, PEM_R_PROBLEMS_GETTING_PASSWORD); | ||
if (ferror(tty_out)) { | ||
ERR_add_error_data(2, "System error: ", strerror(errno)); | ||
clearerr(tty_out); | ||
} | ||
return 0; | ||
} | ||
|
||
return 1; | ||
} | ||
|
||
// returns 0 on success, -1 on error, -2 if interrupt signal received | ||
int openssl_console_read(char *buf, int minsize, int maxsize, int echo) { | ||
int ok = 0; | ||
char *p = NULL; | ||
int echo_eol = !echo; | ||
smittals2 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
intr_signal = 0; | ||
int phase = 0; | ||
|
||
if (!buf || maxsize < minsize) { | ||
return -1; | ||
} | ||
|
||
assert(CRYPTO_STATIC_MUTEX_is_write_locked(&console_global_mutex)); | ||
|
||
pushsig(); | ||
phase = 1; | ||
|
||
if (!echo && !openssl_console_echo_disable()) { | ||
goto error; | ||
} | ||
phase = 2; | ||
|
||
buf[0] = '\0'; | ||
#if defined(OPENSSL_WINDOWS) | ||
if (is_a_tty) { | ||
DWORD numread; | ||
// for now assuming UTF-8.... | ||
WCHAR wresult[BUFSIZ]; | ||
smittals2 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
OPENSSL_cleanse(wresult, sizeof(wresult)); | ||
|
||
if (ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), | ||
wresult, maxsize, &numread, NULL)) { | ||
if (numread >= 2 && wresult[numread-2] == L'\r' && | ||
wresult[numread-1] == L'\n') { | ||
wresult[numread-2] = L'\n'; | ||
numread--; | ||
} | ||
wresult[numread] = L'\0'; | ||
if (WideCharToMultiByte(CP_UTF8, 0, wresult, -1, buf, maxsize + 1, NULL, 0) > 0) { | ||
p = buf; | ||
} | ||
OPENSSL_cleanse(wresult, sizeof(wresult)); | ||
} | ||
} else { | ||
p = fgets(buf, maxsize, tty_in); | ||
} | ||
#else | ||
p = fgets(buf, maxsize, tty_in); | ||
#endif | ||
if (p == NULL || feof(tty_in) || ferror(tty_in)) { | ||
OPENSSL_PUT_ERROR(PEM, PEM_R_PROBLEMS_GETTING_PASSWORD); | ||
if (ferror(tty_in)) { | ||
ERR_add_error_data(2, "System error: ", strerror(errno)); | ||
clearerr(tty_in); | ||
} | ||
ok = -1; | ||
goto error; | ||
} | ||
|
||
// check if we see a new line, otherwise clear out remaining input buffer | ||
if ((p = strchr(buf, '\n')) != NULL) { | ||
*p = '\0'; | ||
} else if (!discard_line_remainder(tty_in)) { | ||
ok = -1; | ||
goto error; | ||
} | ||
|
||
// Validate that input meets the minimum length requirement. We accept buffers |buf| of any size | ||
// but enforce a maximum password length of 1024 characters for compatibility with OpenSSL. | ||
// Unlike OpenSSL's higher-level APIs which silently truncate buffers exceeding this limit, | ||
// we explicitly check the password length after reading it from the user. This approach maintains | ||
// OpenSSL compatibility while avoiding silent truncation. | ||
size_t input_len = strlen(buf); | ||
if (input_len < (size_t)minsize || input_len > (size_t)MAX_PASSWORD_LENGTH) { | ||
ok = -1; | ||
} | ||
|
||
error: | ||
if (intr_signal == SIGINT) { | ||
ok = -2; // interrupted | ||
} | ||
if (echo_eol) { | ||
fprintf(tty_out, "\n"); | ||
smittals2 marked this conversation as resolved.
Show resolved
Hide resolved
smittals2 marked this conversation as resolved.
Show resolved
Hide resolved
justsmth marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: Call to function 'fprintf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'fprintf_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling] fprintf(tty_out, "\n");
^ Additional contextcrypto/console/console.c:324: Call to function 'fprintf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'fprintf_s' in case of C11 fprintf(tty_out, "\n");
^ |
||
} | ||
if (phase >= 2 && !echo && !openssl_console_echo_enable()) { | ||
ok = -1; // general errors | ||
} | ||
if (phase >= 1) { | ||
popsig(); | ||
} | ||
|
||
return ok; | ||
} |
Uh oh!
There was an error while loading. Please reload this page.