mirror of
https://github.com/morgan9e/FreeRDP
synced 2026-04-14 00:14:11 +09:00
fix smartcard logon with smartcard emulation
When smartcard emulation was enabled we were dumping the key and cert to temporary files for PKINIT call, but they were deleted before we have actually done the PKINIT. This patch fixes it. It also add debug statement for the listing of smartcard keys / certs. This also fixes the listing of smartcard on certain windows configurations were we have to force NCRYPT_SILENT when doing a NCryptOpenKey.
This commit is contained in:
@@ -54,7 +54,7 @@ BOOL freerdp_smartcard_list(const rdpSettings* settings)
|
||||
if (info->upn)
|
||||
printf("\t* UPN: %s\n", info->upn);
|
||||
}
|
||||
smartcardCerts_Free(certs);
|
||||
smartcardCerts_Free(&certs);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -45,6 +45,6 @@ typedef struct
|
||||
FREERDP_API BOOL smartcard_enumerateCerts(const rdpSettings* settings, SmartcardCerts** scCert,
|
||||
DWORD* retCount);
|
||||
FREERDP_API const SmartcardCertInfo* smartcard_getCertInfo(SmartcardCerts* scCerts, DWORD index);
|
||||
FREERDP_API void smartcardCerts_Free(SmartcardCerts* scCert);
|
||||
FREERDP_API void smartcardCerts_Free(SmartcardCerts** pscCert);
|
||||
|
||||
#endif /* LIBFREERDP_CORE_SMARTCARDLOGON_H */
|
||||
|
||||
@@ -124,6 +124,8 @@ struct rdp_nla
|
||||
|
||||
rdpCredsspAuth* auth;
|
||||
char* pkinitArgs;
|
||||
SmartcardCerts* smartcardCerts;
|
||||
DWORD nsmartcardCerts;
|
||||
BYTE certSha1[20];
|
||||
};
|
||||
|
||||
@@ -185,9 +187,7 @@ static const UINT32 NonceLength = 32;
|
||||
|
||||
static BOOL nla_adjust_settings_from_smartcard(rdpNla* nla)
|
||||
{
|
||||
SmartcardCerts* certs = NULL;
|
||||
const SmartcardCertInfo* info = NULL;
|
||||
DWORD count;
|
||||
rdpSettings* settings;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
@@ -200,22 +200,24 @@ static BOOL nla_adjust_settings_from_smartcard(rdpNla* nla)
|
||||
if (!settings->SmartcardLogon)
|
||||
return TRUE;
|
||||
|
||||
if (!smartcard_enumerateCerts(settings, &certs, &count))
|
||||
smartcardCerts_Free(&nla->smartcardCerts);
|
||||
|
||||
if (!smartcard_enumerateCerts(settings, &nla->smartcardCerts, &nla->nsmartcardCerts))
|
||||
{
|
||||
WLog_ERR(TAG, "unable to list smartcard certificates");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (count < 1)
|
||||
if (nla->nsmartcardCerts < 1)
|
||||
{
|
||||
WLog_ERR(TAG, "no smartcard certificates found");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (count != 1)
|
||||
if (nla->nsmartcardCerts != 1)
|
||||
goto setup_pin;
|
||||
|
||||
info = smartcard_getCertInfo(certs, 0);
|
||||
info = smartcard_getCertInfo(nla->smartcardCerts, 0);
|
||||
if (!info)
|
||||
goto out;
|
||||
|
||||
@@ -291,8 +293,6 @@ setup_pin:
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
smartcardCerts_Free(certs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1694,6 +1694,7 @@ void nla_free(rdpNla* nla)
|
||||
if (!nla)
|
||||
return;
|
||||
|
||||
smartcardCerts_Free(&nla->smartcardCerts);
|
||||
sspi_SecBufferFree(&nla->pubKeyAuth);
|
||||
sspi_SecBufferFree(&nla->authInfo);
|
||||
sspi_SecBufferFree(&nla->negoToken);
|
||||
@@ -1703,8 +1704,8 @@ void nla_free(rdpNla* nla)
|
||||
credssp_auth_free(nla->auth);
|
||||
|
||||
sspi_FreeAuthIdentity(nla->identity);
|
||||
free(nla->pkinitArgs);
|
||||
free(nla->identity);
|
||||
|
||||
free(nla);
|
||||
}
|
||||
|
||||
|
||||
@@ -151,9 +151,13 @@ static void smartcardCertInfoPrivate_Free(SmartcardCertInfoPrivate* scCert)
|
||||
*scCert = empty;
|
||||
}
|
||||
|
||||
void smartcardCerts_Free(SmartcardCerts* scCert)
|
||||
void smartcardCerts_Free(SmartcardCerts** pscCert)
|
||||
{
|
||||
size_t x;
|
||||
SmartcardCerts* scCert;
|
||||
|
||||
WINPR_ASSERT(pscCert);
|
||||
scCert = *pscCert;
|
||||
if (!scCert)
|
||||
return;
|
||||
|
||||
@@ -161,13 +165,17 @@ void smartcardCerts_Free(SmartcardCerts* scCert)
|
||||
smartcardCertInfoPrivate_Free(&scCert->certs[x]);
|
||||
|
||||
free(scCert);
|
||||
*pscCert = NULL;
|
||||
}
|
||||
|
||||
static BOOL treat_sc_cert(SmartcardCertInfo* scCert)
|
||||
{
|
||||
scCert->upn = crypto_cert_get_upn(scCert->certificate->px509);
|
||||
if (!scCert->upn)
|
||||
{
|
||||
WLog_DBG(TAG, "%s has no UPN, trying emailAddress", scCert->containerName);
|
||||
scCert->upn = crypto_cert_get_email(scCert->certificate->px509);
|
||||
}
|
||||
|
||||
if (scCert->upn)
|
||||
{
|
||||
@@ -280,10 +288,19 @@ static BOOL list_provider_keys(const rdpSettings* settings, NCRYPT_PROV_HANDLE p
|
||||
NULL) <= 0)
|
||||
goto endofloop;
|
||||
|
||||
WLog_DBG(TAG, "opening key %s", cert->info.containerName);
|
||||
|
||||
status = NCryptOpenKey(provider, &phKey, keyName->pszName, keyName->dwLegacyKeySpec,
|
||||
keyName->dwFlags);
|
||||
NCRYPT_SILENT_FLAG);
|
||||
if (status != ERROR_SUCCESS)
|
||||
{
|
||||
WLog_DBG(TAG,
|
||||
"unable to NCryptOpenKey(dwLegacyKeySpec=0x%" PRIx32 " dwFlags=0x%" PRIx32
|
||||
"), status=%s, skipping",
|
||||
status, keyName->dwLegacyKeySpec, keyName->dwFlags,
|
||||
winpr_NCryptSecurityStatusError(status));
|
||||
goto endofloop;
|
||||
}
|
||||
|
||||
cert->info.csp = _wcsdup(csp);
|
||||
if (!cert->info.csp)
|
||||
@@ -294,7 +311,8 @@ static BOOL list_provider_keys(const rdpSettings* settings, NCRYPT_PROV_HANDLE p
|
||||
&cbOutput, NCRYPT_SILENT_FLAG);
|
||||
if (status != ERROR_SUCCESS)
|
||||
{
|
||||
WLog_ERR(TAG, "unable to retrieve slotId for key %s", cert->info.containerName);
|
||||
WLog_ERR(TAG, "unable to retrieve slotId for key %s, status=%s",
|
||||
cert->info.containerName, winpr_NCryptSecurityStatusError(status));
|
||||
goto endofloop;
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
@@ -335,6 +353,8 @@ static BOOL list_provider_keys(const rdpSettings* settings, NCRYPT_PROV_HANDLE p
|
||||
if (status != ERROR_SUCCESS)
|
||||
{
|
||||
/* can happen that key don't have certificates */
|
||||
WLog_DBG(TAG, "unable to retrieve certificate property len, status=0x%lx, skipping",
|
||||
status);
|
||||
goto endofloop;
|
||||
}
|
||||
|
||||
@@ -371,7 +391,10 @@ static BOOL list_provider_keys(const rdpSettings* settings, NCRYPT_PROV_HANDLE p
|
||||
}
|
||||
|
||||
if (!treat_sc_cert(&cert->info))
|
||||
{
|
||||
WLog_DBG(TAG, "error treating cert");
|
||||
goto endofloop;
|
||||
}
|
||||
|
||||
if (userFilter && cert->info.userHint && strcmp(cert->info.userHint, userFilter) != 0)
|
||||
{
|
||||
@@ -522,7 +545,7 @@ static BOOL smartcard_hw_enumerateCerts(const rdpSettings* settings, LPCWSTR csp
|
||||
|
||||
out:
|
||||
if (!ret)
|
||||
smartcardCerts_Free(certs);
|
||||
smartcardCerts_Free(&certs);
|
||||
free(scope);
|
||||
return ret;
|
||||
}
|
||||
@@ -599,6 +622,7 @@ static BOOL smartcard_sw_enumerateCerts(const rdpSettings* settings, SmartcardCe
|
||||
* We need files for PKINIT to read, so write the certificate to some
|
||||
* temporary location and use that.
|
||||
*/
|
||||
WLog_DBG(TAG, "writing PKINIT cert/key to %s and %s", keyPath, certPath);
|
||||
if (!write_pem(keyPath, freerdp_settings_get_string(settings, FreeRDP_SmartcardPrivateKey)))
|
||||
goto out_error;
|
||||
if (!write_pem(certPath, freerdp_settings_get_string(settings, FreeRDP_SmartcardCertificate)))
|
||||
@@ -616,7 +640,7 @@ static BOOL smartcard_sw_enumerateCerts(const rdpSettings* settings, SmartcardCe
|
||||
|
||||
out_error:
|
||||
if (!rc)
|
||||
smartcardCerts_Free(certs);
|
||||
smartcardCerts_Free(&certs);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -202,6 +202,14 @@ extern "C"
|
||||
LPCWSTR pszProviderName,
|
||||
DWORD dwFlags, LPCSTR* modulePaths);
|
||||
|
||||
/**
|
||||
* Gives a string representation of a SECURITY_STATUS
|
||||
*
|
||||
* @param status [in] SECURITY_STATUS that we want as string
|
||||
* @return the string representation of status
|
||||
*/
|
||||
WINPR_API const char* winpr_NCryptSecurityStatusError(SECURITY_STATUS status);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -271,4 +271,62 @@ out_free_lib:
|
||||
FreeLibrary(lib);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
#endif /* _WIN32 */
|
||||
|
||||
const char* winpr_NCryptSecurityStatusError(SECURITY_STATUS status)
|
||||
{
|
||||
#define NTE_CASE(S) \
|
||||
case S: \
|
||||
return #S
|
||||
|
||||
switch (status)
|
||||
{
|
||||
NTE_CASE(ERROR_SUCCESS);
|
||||
NTE_CASE(ERROR_INVALID_PARAMETER);
|
||||
NTE_CASE(ERROR_INVALID_HANDLE);
|
||||
NTE_CASE(ERROR_NOT_SUPPORTED);
|
||||
|
||||
NTE_CASE(NTE_BAD_UID);
|
||||
NTE_CASE(NTE_BAD_HASH);
|
||||
NTE_CASE(NTE_BAD_KEY);
|
||||
NTE_CASE(NTE_BAD_LEN);
|
||||
NTE_CASE(NTE_BAD_DATA);
|
||||
NTE_CASE(NTE_BAD_SIGNATURE);
|
||||
NTE_CASE(NTE_BAD_VER);
|
||||
NTE_CASE(NTE_BAD_ALGID);
|
||||
NTE_CASE(NTE_BAD_FLAGS);
|
||||
NTE_CASE(NTE_BAD_TYPE);
|
||||
NTE_CASE(NTE_BAD_KEY_STATE);
|
||||
NTE_CASE(NTE_BAD_HASH_STATE);
|
||||
NTE_CASE(NTE_NO_KEY);
|
||||
NTE_CASE(NTE_NO_MEMORY);
|
||||
NTE_CASE(NTE_EXISTS);
|
||||
NTE_CASE(NTE_PERM);
|
||||
NTE_CASE(NTE_NOT_FOUND);
|
||||
NTE_CASE(NTE_DOUBLE_ENCRYPT);
|
||||
NTE_CASE(NTE_BAD_PROVIDER);
|
||||
NTE_CASE(NTE_BAD_PROV_TYPE);
|
||||
NTE_CASE(NTE_BAD_PUBLIC_KEY);
|
||||
NTE_CASE(NTE_BAD_KEYSET);
|
||||
NTE_CASE(NTE_PROV_TYPE_NOT_DEF);
|
||||
NTE_CASE(NTE_PROV_TYPE_ENTRY_BAD);
|
||||
NTE_CASE(NTE_KEYSET_NOT_DEF);
|
||||
NTE_CASE(NTE_KEYSET_ENTRY_BAD);
|
||||
NTE_CASE(NTE_PROV_TYPE_NO_MATCH);
|
||||
NTE_CASE(NTE_SIGNATURE_FILE_BAD);
|
||||
NTE_CASE(NTE_PROVIDER_DLL_FAIL);
|
||||
NTE_CASE(NTE_PROV_DLL_NOT_FOUND);
|
||||
NTE_CASE(NTE_BAD_KEYSET_PARAM);
|
||||
NTE_CASE(NTE_FAIL);
|
||||
NTE_CASE(NTE_SYS_ERR);
|
||||
NTE_CASE(NTE_SILENT_CONTEXT);
|
||||
NTE_CASE(NTE_TOKEN_KEYSET_STORAGE_FULL);
|
||||
NTE_CASE(NTE_TEMPORARY_PROFILE);
|
||||
NTE_CASE(NTE_FIXEDPARAMETER);
|
||||
|
||||
default:
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
#undef NTE_CASE
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user