Added command line or dialog certificate handling.

This commit is contained in:
Armin Novak 2019-08-29 15:17:59 +02:00
parent 81c60631a9
commit 1a322bb98b
2 changed files with 158 additions and 65 deletions

View File

@ -58,15 +58,17 @@
#define TAG CLIENT_TAG("windows")
static int wf_create_console(void)
static BOOL wf_create_console(void)
{
if (!AttachConsole(ATTACH_PARENT_PROCESS))
return 1;
return FALSE;
freopen("CONOUT$", "w", stdout);
freopen("CONOUT$", "w", stderr);
WLog_INFO(TAG, "Debug console created.");
return 0;
return TRUE;
}
static BOOL wf_end_paint(rdpContext* context)
@ -397,16 +399,15 @@ static BOOL wf_post_connect(freerdp* instance)
return TRUE;
}
static BOOL wf_post_disconnect(freerdp* instance)
static void wf_post_disconnect(freerdp* instance)
{
wfContext* wfc;
if (!instance || !instance->context || !instance->settings)
return FALSE;
return;
wfc = (wfContext*) instance->context;
free(wfc->window_title);
return TRUE;
}
static CREDUI_INFOA wfUiInfo =
@ -433,8 +434,8 @@ static BOOL wf_authenticate_raw(freerdp* instance, const char* title,
ZeroMemory(Password, sizeof(Password));
dwFlags = CREDUI_FLAGS_DO_NOT_PERSIST | CREDUI_FLAGS_EXCLUDE_CERTIFICATES;
status = CredUIPromptForCredentialsA(&wfUiInfo, title, NULL, 0,
UserName, CREDUI_MAX_USERNAME_LENGTH + 1,
Password, CREDUI_MAX_PASSWORD_LENGTH + 1, &fSave, dwFlags);
UserName, CREDUI_MAX_USERNAME_LENGTH + 1,
Password, CREDUI_MAX_PASSWORD_LENGTH + 1, &fSave, dwFlags);
if (status != NO_ERROR)
{
@ -494,64 +495,149 @@ static BOOL wf_gw_authenticate(freerdp* instance,
return wf_authenticate_raw(instance, tmp, username, password, domain);
}
static DWORD wf_verify_certificate(freerdp* instance,
const char* common_name,
const char* subject,
const char* issuer,
const char* fingerprint,
BOOL host_mismatch)
static WCHAR* wf_format_text(const WCHAR* fmt, ...)
{
#if 0
DWORD mode;
int read_size;
DWORD read_count;
TCHAR answer[2];
TCHAR* read_buffer;
HANDLE input_handle;
#endif
WLog_INFO(TAG, "Certificate details:");
WLog_INFO(TAG, "\tCommonName: %s", common_name);
WLog_INFO(TAG, "\tSubject: %s", subject);
WLog_INFO(TAG, "\tIssuer: %s", issuer);
WLog_INFO(TAG, "\tThumbprint: %s", fingerprint);
WLog_INFO(TAG, "\tHostMismatch: %s", host_mismatch ? "Yes" : "No");
WLog_INFO(TAG,
"The above X.509 certificate could not be verified, possibly because you do not have "
"the CA certificate in your certificate store, or the certificate has expired. "
"Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
/* TODO: ask for user validation */
#if 0
input_handle = GetStdHandle(STD_INPUT_HANDLE);
GetConsoleMode(input_handle, &mode);
mode |= ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT;
SetConsoleMode(input_handle, mode);
#endif
/* return 1 to accept and store a certificate, 2 to accept
* a certificate only for this session, 0 otherwise */
return 2;
int rc;
size_t size = 1024;
WCHAR* buffer = calloc(size, sizeof(WCHAR));
if (!buffer)
return NULL;
do
{
WCHAR* tmp;
va_list ap;
va_start(ap, fmt);
rc = vswprintf_s(buffer, size, fmt, ap);
va_end(ap);
if (rc <= 0)
goto fail;
if ((size_t)rc < size)
return buffer;
size = (size_t)rc + 1;
tmp = realloc(buffer, size * sizeof(WCHAR));
if (!tmp)
goto fail;
buffer = tmp;
}
while(TRUE);
fail:
free(buffer);
return NULL;
}
static DWORD wf_verify_changed_certificate(freerdp* instance,
const char* common_name,
const char* subject, const char* issuer,
const char* fingerprint,
const char* old_subject, const char* old_issuer,
const char* old_fingerprint)
static DWORD wf_verify_certificate_ex(freerdp* instance,
const char* host,
UINT16 port,
const char* common_name,
const char* subject,
const char* issuer,
const char* fingerprint,
DWORD flags)
{
WLog_ERR(TAG, "!!! Certificate has changed !!!");
WLog_ERR(TAG, "New Certificate details:");
WLog_ERR(TAG, "\tSubject: %s", subject);
WLog_ERR(TAG, "\tIssuer: %s", issuer);
WLog_ERR(TAG, "\tThumbprint: %s", fingerprint);
WLog_ERR(TAG, "Old Certificate details:");
WLog_ERR(TAG, "\tSubject: %s", old_subject);
WLog_ERR(TAG, "\tIssuer: %s", old_issuer);
WLog_ERR(TAG, "\tThumbprint: %s", old_fingerprint);
WLog_ERR(TAG,
"The above X.509 certificate does not match the certificate used for previous connections. "
"This may indicate that the certificate has been tampered with."
"Please contact the administrator of the RDP server and clarify.");
return 0;
WCHAR* buffer;
WCHAR* caption;
int what = IDCANCEL;
buffer = wf_format_text(L"Certificate details:\n"
L"\tCommonName: %S\n"
L"\tSubject: %S\n"
L"\tIssuer: %S\n"
L"\tThumbprint: %S\n"
L"\tHostMismatch: %S\n"
L"\n"
L"The above X.509 certificate could not be verified, possibly because you do not have "
L"the CA certificate in your certificate store, or the certificate has expired. "
L"Please look at the OpenSSL documentation on how to add a private CA to the store.\n"
L"\n"
L"YES\tAccept permanently\n"
L"NO\tAccept for this session only\n"
L"CANCEL\tAbort connection\n",
common_name, subject, issuer, fingerprint, flags & VERIFY_CERT_FLAG_MISMATCH ? "Yes" : "No");
caption = wf_format_text(L"Verify certificate for %S:%hu", host, port);
if (!buffer || !caption)
goto fail;
what = MessageBoxW(NULL, buffer, caption, MB_YESNOCANCEL);
fail:
free(buffer);
free(caption);
/* return 1 to accept and store a certificate, 2 to accept
* a certificate only for this session, 0 otherwise */
switch(what)
{
case IDOK:
return 1;
case IDNO:
return 2;
default:
return 0;
}
}
static DWORD wf_verify_changed_certificate_ex(freerdp* instance,
const char* host,
UINT16 port,
const char* common_name,
const char* subject,
const char* issuer,
const char* new_fingerprint,
const char* old_subject,
const char* old_issuer,
const char* old_fingerprint,
DWORD flags)
{
WCHAR* buffer;
WCHAR* caption;
int what = IDCANCEL;
buffer = wf_format_text( L"New Certificate details:\n"
L"\tCommonName: %S\n"
L"\tSubject: %S\n"
L"\tIssuer: %S\n"
L"\tThumbprint: %S\n"
L"\tHostMismatch: %S\n"
L"\n"
L"Old Certificate details:\n"
L"\tSubject: %S\n"
L"\tIssuer: %S\n"
L"\tThumbprint: %S"
L"The above X.509 certificate could not be verified, possibly because you do not have "
L"the CA certificate in your certificate store, or the certificate has expired. "
L"Please look at the OpenSSL documentation on how to add a private CA to the store.\n"
L"\n"
L"YES\tAccept permanently\n"
L"NO\tAccept for this session only\n"
L"CANCEL\tAbort connection\n",
common_name, subject, issuer, new_fingerprint, flags & VERIFY_CERT_FLAG_MISMATCH ? "Yes" : "No",
old_subject, old_issuer, old_fingerprint);
caption = wf_format_text(L"Verify certificate change for %S:%hu", host, port);
if (!buffer || !caption)
goto fail;
what = MessageBoxW(NULL, buffer, caption, MB_YESNOCANCEL);
fail:
free(buffer);
free(caption);
/* return 1 to accept and store a certificate, 2 to accept
* a certificate only for this session, 0 otherwise */
switch(what)
{
case IDOK:
return 1;
case IDNO:
return 2;
default:
return 0;
}
}
static DWORD WINAPI wf_input_thread(LPVOID arg)
@ -917,7 +1003,6 @@ static BOOL wfreerdp_client_global_init(void)
WSAStartup(0x101, &wsaData);
wf_create_console();
freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0);
return TRUE;
}
@ -929,6 +1014,12 @@ static void wfreerdp_client_global_uninit(void)
static BOOL wfreerdp_client_new(freerdp* instance, rdpContext* context)
{
wfContext* wfc = (wfContext*)context;
if (!wfc)
return FALSE;
wfc->isConsole = wf_create_console();
if (!(wfreerdp_client_global_init()))
return FALSE;
@ -937,8 +1028,9 @@ static BOOL wfreerdp_client_new(freerdp* instance, rdpContext* context)
instance->PostDisconnect = wf_post_disconnect;
instance->Authenticate = wf_authenticate;
instance->GatewayAuthenticate = wf_gw_authenticate;
instance->VerifyCertificate = wf_verify_certificate;
instance->VerifyChangedCertificate = wf_verify_changed_certificate;
instance->VerifyCertificateEx = wf_verify_certificate_ex;
instance->VerifyChangedCertificateEx = wf_verify_changed_certificate_ex;
return TRUE;
}

View File

@ -132,6 +132,7 @@ struct wf_context
RailClientContext* rail;
wHashTable* railWindows;
BOOL isConsole;
};
/**