From eb04eb00087ddaa7d091edf7c060701f7714011e Mon Sep 17 00:00:00 2001 From: fifthdegree Date: Sun, 16 Oct 2022 15:54:59 -0400 Subject: [PATCH] Support using smartcard for gateway authentication --- client/common/client.c | 6 ++- client/common/smartcard_cli.c | 2 +- include/freerdp/client.h | 2 +- include/freerdp/freerdp.h | 3 +- include/freerdp/utils/smartcardlogon.h | 5 ++- libfreerdp/core/gateway/rdg.c | 61 ++++++++++++++++++++++---- libfreerdp/core/nla.c | 20 +-------- libfreerdp/core/smartcardlogon.c | 51 ++++++++++++++++++--- 8 files changed, 108 insertions(+), 42 deletions(-) diff --git a/client/common/client.c b/client/common/client.c index f0836121c..2f1a78562 100644 --- a/client/common/client.c +++ b/client/common/client.c @@ -518,7 +518,8 @@ BOOL client_cli_authenticate_ex(freerdp* instance, char** username, char** passw return client_cli_authenticate_raw(instance, reason, username, password, domain); } -BOOL client_cli_choose_smartcard(SmartcardCertInfo** cert_list, DWORD count, DWORD* choice) +BOOL client_cli_choose_smartcard(SmartcardCertInfo** cert_list, DWORD count, DWORD* choice, + BOOL gateway) { unsigned long answer; char* p = NULL; @@ -545,7 +546,8 @@ BOOL client_cli_choose_smartcard(SmartcardCertInfo** cert_list, DWORD count, DWO { char input[10] = { 0 }; - printf("\nChoose a smartcard to use (0 - %" PRIu32 "): ", count - 1); + printf("\nChoose a smartcard to use for %s (0 - %" PRIu32 "): ", + gateway ? "gateway authentication" : "logon", count - 1); fflush(stdout); if (!fgets(input, 10, stdin)) { diff --git a/client/common/smartcard_cli.c b/client/common/smartcard_cli.c index 67ccdb38f..5fcf98c3c 100644 --- a/client/common/smartcard_cli.c +++ b/client/common/smartcard_cli.c @@ -27,7 +27,7 @@ BOOL freerdp_smartcard_list(const rdpSettings* settings) SmartcardCertInfo** certs = NULL; DWORD i, count; - if (!smartcard_enumerateCerts(settings, &certs, &count)) + if (!smartcard_enumerateCerts(settings, &certs, &count, FALSE)) return FALSE; for (i = 0; i < count; i++) diff --git a/include/freerdp/client.h b/include/freerdp/client.h index c54fcdc96..d8c06d708 100644 --- a/include/freerdp/client.h +++ b/include/freerdp/client.h @@ -139,7 +139,7 @@ extern "C" char** domain, rdp_auth_reason reason); FREERDP_API BOOL client_cli_choose_smartcard(SmartcardCertInfo** cert_list, DWORD count, - DWORD* choice); + DWORD* choice, BOOL gateway); FREERDP_API void freerdp_client_OnChannelConnectedEventHandler(void* context, diff --git a/include/freerdp/freerdp.h b/include/freerdp/freerdp.h index 5d9954343..629806cb2 100644 --- a/include/freerdp/freerdp.h +++ b/include/freerdp/freerdp.h @@ -118,7 +118,8 @@ extern "C" char** domain); typedef BOOL (*pAuthenticateEx)(freerdp* instance, char** username, char** password, char** domain, rdp_auth_reason reason); - typedef BOOL (*pChooseSmartcard)(SmartcardCertInfo** cert_list, DWORD count, DWORD* choice); + typedef BOOL (*pChooseSmartcard)(SmartcardCertInfo** cert_list, DWORD count, DWORD* choice, + BOOL gateway); /** @brief Callback used if user interaction is required to accept * an unknown certificate. diff --git a/include/freerdp/utils/smartcardlogon.h b/include/freerdp/utils/smartcardlogon.h index e9f7f6ee8..80e4c79f3 100644 --- a/include/freerdp/utils/smartcardlogon.h +++ b/include/freerdp/utils/smartcardlogon.h @@ -43,8 +43,9 @@ typedef struct SmartcardCertInfo_st } SmartcardCertInfo; FREERDP_API BOOL smartcard_enumerateCerts(const rdpSettings* settings, SmartcardCertInfo*** scCerts, - DWORD* retCount); -FREERDP_API BOOL smartcard_getCert(const rdpContext* context, SmartcardCertInfo** cert); + DWORD* retCount, BOOL gateway); +FREERDP_API BOOL smartcard_getCert(const rdpContext* context, SmartcardCertInfo** cert, + BOOL gateway); FREERDP_API void smartcardCertInfo_Free(SmartcardCertInfo* pscCert); FREERDP_API void smartcardCertList_Free(SmartcardCertInfo** pscCert, DWORD count); diff --git a/libfreerdp/core/gateway/rdg.c b/libfreerdp/core/gateway/rdg.c index 12df09ffb..d284d41e1 100644 --- a/libfreerdp/core/gateway/rdg.c +++ b/libfreerdp/core/gateway/rdg.c @@ -26,10 +26,12 @@ #include #include #include +#include #include #include #include +#include #include "rdg.h" #include "../credssp_auth.h" @@ -193,6 +195,8 @@ struct rdp_rdg UINT16 extAuth; UINT16 reserved2; rdg_http_encoding_context transferEncoding; + + SmartcardCertInfo* smartcard; }; enum @@ -1550,11 +1554,11 @@ DWORD rdg_get_event_handles(rdpRdg* rdg, HANDLE* events, DWORD count) return nCount; } -static BOOL rdg_get_gateway_credentials(rdpContext* context) +static BOOL rdg_get_gateway_credentials(rdpContext* context, rdp_auth_reason reason) { freerdp* instance = context->instance; - auth_status rc = utils_authenticate_gateway(instance, GW_AUTH_RDG); + auth_status rc = utils_authenticate_gateway(instance, reason); switch (rc) { case AUTH_SUCCESS: @@ -1581,17 +1585,54 @@ static BOOL rdg_auth_init(rdpRdg* rdg, rdpTls* tls) if (!rdg->auth) return FALSE; - if (!rdg_get_gateway_credentials(context)) - return FALSE; - if (!credssp_auth_init(rdg->auth, AUTH_PKG, tls->Bindings)) return FALSE; - if (sspi_SetAuthIdentityA(&identity, settings->GatewayUsername, settings->GatewayDomain, - settings->GatewayPassword) < 0) - return FALSE; + if (freerdp_settings_get_bool(settings, FreeRDP_SmartcardLogon)) + { + if (!smartcard_getCert(context, &rdg->smartcard, TRUE)) + return FALSE; - if (!credssp_auth_setup_client(rdg->auth, "HTTP", settings->GatewayHostname, &identity, NULL)) + if (!rdg_get_gateway_credentials(context, AUTH_SMARTCARD_PIN)) + return FALSE; +#ifdef _WIN32 + { + CERT_CREDENTIAL_INFO certInfo = { sizeof(CERT_CREDENTIAL_INFO), { 0 } }; + LPSTR marshalledCredentials; + + memcpy(certInfo.rgbHashOfCert, rdg->smartcard->sha1Hash, + sizeof(certInfo.rgbHashOfCert)); + + if (!CredMarshalCredentialA(CertCredential, &certInfo, &marshalledCredentials)) + { + WLog_ERR(TAG, "error marshalling cert credentials"); + return FALSE; + } + + if (sspi_SetAuthIdentityA(&identity, marshalledCredentials, NULL, + settings->GatewayPassword) < 0) + return FALSE; + + CredFree(marshalledCredentials); + } +#else + if (sspi_SetAuthIdentityA(&identity, settings->GatewayUsername, settings->GatewayDomain, + settings->GatewayPassword) < 0) + return FALSE; +#endif + } + else + { + if (!rdg_get_gateway_credentials(context, GW_AUTH_RDG)) + return FALSE; + + if (sspi_SetAuthIdentityA(&identity, settings->GatewayUsername, settings->GatewayDomain, + settings->GatewayPassword) < 0) + return FALSE; + } + + if (!credssp_auth_setup_client(rdg->auth, "HTTP", settings->GatewayHostname, &identity, + rdg->smartcard ? rdg->smartcard->pkinitArgs : NULL)) { sspi_FreeAuthIdentity(&identity); return FALSE; @@ -2626,6 +2667,8 @@ void rdg_free(rdpRdg* rdg) Stream_Free(rdg->transferEncoding.context.websocket.responseStreamBuffer, TRUE); } + smartcardCertInfo_Free(rdg->smartcard); + free(rdg); } diff --git a/libfreerdp/core/nla.c b/libfreerdp/core/nla.c index a0832b558..1a8172d36 100644 --- a/libfreerdp/core/nla.c +++ b/libfreerdp/core/nla.c @@ -200,7 +200,7 @@ static BOOL nla_adjust_settings_from_smartcard(rdpNla* nla) smartcardCertInfo_Free(nla->smartcardCert); - if (!smartcard_getCert(nla->rdpcontext, &nla->smartcardCert)) + if (!smartcard_getCert(nla->rdpcontext, &nla->smartcardCert, FALSE)) { WLog_ERR(TAG, "unable to get smartcard certificate for logon"); return FALSE; @@ -221,24 +221,6 @@ static BOOL nla_adjust_settings_from_smartcard(rdpNla* nla) } } - if (!settings->Username && nla->smartcardCert->userHint) - { - if (!freerdp_settings_set_string(settings, FreeRDP_Username, nla->smartcardCert->userHint)) - { - WLog_ERR(TAG, "unable to copy certificate username"); - goto out; - } - } - - if (!settings->Domain && nla->smartcardCert->domainHint) - { - if (!freerdp_settings_set_string(settings, FreeRDP_Domain, nla->smartcardCert->domainHint)) - { - WLog_ERR(TAG, "unable to copy certificate domain"); - goto out; - } - } - if (!settings->ReaderName && nla->smartcardCert->reader) { if (ConvertFromUnicode(CP_UTF8, 0, nla->smartcardCert->reader, -1, &settings->ReaderName, 0, diff --git a/libfreerdp/core/smartcardlogon.c b/libfreerdp/core/smartcardlogon.c index 5193f8f4a..c0707c47e 100644 --- a/libfreerdp/core/smartcardlogon.c +++ b/libfreerdp/core/smartcardlogon.c @@ -607,14 +607,25 @@ out_error: } BOOL smartcard_enumerateCerts(const rdpSettings* settings, SmartcardCertInfo*** scCerts, - DWORD* retCount) + DWORD* retCount, BOOL gateway) { BOOL ret; LPWSTR csp = NULL; const char* ReaderName = freerdp_settings_get_string(settings, FreeRDP_ReaderName); - const char* Username = freerdp_settings_get_string(settings, FreeRDP_Username); - const char* Domain = freerdp_settings_get_string(settings, FreeRDP_Domain); const char* CspName = freerdp_settings_get_string(settings, FreeRDP_CspName); + const char* Username; + const char* Domain; + + if (gateway) + { + Username = freerdp_settings_get_string(settings, FreeRDP_GatewayUsername); + Domain = freerdp_settings_get_string(settings, FreeRDP_GatewayDomain); + } + else + { + Username = freerdp_settings_get_string(settings, FreeRDP_Username); + Domain = freerdp_settings_get_string(settings, FreeRDP_Domain); + } WINPR_ASSERT(settings); WINPR_ASSERT(scCerts); @@ -638,19 +649,32 @@ BOOL smartcard_enumerateCerts(const rdpSettings* settings, SmartcardCertInfo*** return ret; } -BOOL smartcard_getCert(const rdpContext* context, SmartcardCertInfo** cert) +static BOOL set_settings_from_smartcard(rdpSettings* settings, size_t id, const char* value) +{ + WINPR_ASSERT(settings); + + if (!freerdp_settings_get_string(settings, id) && value) + if (!freerdp_settings_set_string(settings, id, value)) + return FALSE; + + return TRUE; +} + +BOOL smartcard_getCert(const rdpContext* context, SmartcardCertInfo** cert, BOOL gateway) { WINPR_ASSERT(context); const freerdp* instance = context->instance; - const rdpSettings* settings = context->settings; + rdpSettings* settings = context->settings; SmartcardCertInfo** cert_list; DWORD count; + size_t username_setting; + size_t domain_setting; WINPR_ASSERT(instance); WINPR_ASSERT(settings); - if (!smartcard_enumerateCerts(settings, &cert_list, &count)) + if (!smartcard_enumerateCerts(settings, &cert_list, &count, gateway)) return FALSE; if (count < 1) @@ -663,7 +687,8 @@ BOOL smartcard_getCert(const rdpContext* context, SmartcardCertInfo** cert) { DWORD index; - if (!instance->ChooseSmartcard || !instance->ChooseSmartcard(cert_list, count, &index)) + if (!instance->ChooseSmartcard || + !instance->ChooseSmartcard(cert_list, count, &index, gateway)) { WLog_ERR(TAG, "more than one suitable smartcard certificate was found"); smartcardCertList_Free(cert_list, count); @@ -679,6 +704,18 @@ BOOL smartcard_getCert(const rdpContext* context, SmartcardCertInfo** cert) else *cert = cert_list[0]; + username_setting = gateway ? FreeRDP_GatewayUsername : FreeRDP_Username; + domain_setting = gateway ? FreeRDP_GatewayDomain : FreeRDP_Domain; + free(cert_list); + + if (!set_settings_from_smartcard(settings, username_setting, (*cert)->userHint) || + !set_settings_from_smartcard(settings, domain_setting, (*cert)->domainHint)) + { + WLog_ERR(TAG, "unable to set settings from smartcard!"); + smartcardCertInfo_Free(*cert); + return FALSE; + } + return TRUE; }