smartcardlogon: choose a single smartcard to use

Require a single smartcard certificate to be chosen and define a
callback to choose when more than one is available.
This commit is contained in:
fifthdegree 2022-10-14 12:58:30 -04:00 committed by David Fort
parent 1cf69f04e6
commit 9d0beaccae
9 changed files with 239 additions and 180 deletions

View File

@ -623,6 +623,7 @@ static BOOL wlf_client_new(freerdp* instance, rdpContext* context)
instance->PostConnect = wl_post_connect;
instance->PostDisconnect = wl_post_disconnect;
instance->AuthenticateEx = client_cli_authenticate_ex;
instance->ChooseSmartcard = client_cli_choose_smartcard;
instance->VerifyCertificateEx = client_cli_verify_certificate_ex;
instance->VerifyChangedCertificateEx = client_cli_verify_changed_certificate_ex;
instance->PresentGatewayMessage = client_cli_present_gateway_message;

View File

@ -1754,6 +1754,7 @@ static BOOL xfreerdp_client_new(freerdp* instance, rdpContext* context)
instance->PostConnect = xf_post_connect;
instance->PostDisconnect = xf_post_disconnect;
instance->AuthenticateEx = client_cli_authenticate_ex;
instance->ChooseSmartcard = client_cli_choose_smartcard;
instance->VerifyCertificateEx = client_cli_verify_certificate_ex;
instance->VerifyChangedCertificateEx = client_cli_verify_changed_certificate_ex;
instance->PresentGatewayMessage = client_cli_present_gateway_message;

View File

@ -30,6 +30,7 @@
#include <freerdp/utils/passphrase.h>
#include <freerdp/client/cmdline.h>
#include <freerdp/client/channels.h>
#include <freerdp/utils/smartcardlogon.h>
#if defined(CHANNEL_AINPUT_CLIENT)
#include <freerdp/client/ainput.h>
@ -517,6 +518,47 @@ 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)
{
unsigned long answer;
char* p = NULL;
printf("Multiple smartcards are available for use:\n");
for (DWORD i = 0; i < count; i++)
{
const SmartcardCertInfo* cert = cert_list[i];
char* reader = NULL;
ConvertFromUnicode(CP_UTF8, 0, cert->reader, -1, &reader, 0, NULL, NULL);
printf("[%" PRIu32
"] %s\n\tReader: %s\n\tUser: %s@%s\n\tSubject: %s\n\tIssuer: %s\n\tUPN: %s\n",
i, cert->containerName, reader, cert->userHint, cert->domainHint, cert->subject,
cert->issuer, cert->upn);
free(reader);
}
while (1)
{
char input[10] = { 0 };
printf("\nChoose a smartcard to use (0 - %" PRIu32 "): ", count - 1);
fflush(stdout);
if (!fgets(input, 10, stdin))
{
WLog_ERR(TAG, "could not read from stdin");
return FALSE;
}
answer = strtoul(input, &p, 10);
if ((*p == '\n' && p != input) && answer < count)
{
*choice = answer;
return TRUE;
}
}
}
#if defined(WITH_FREERDP_DEPRECATED)
BOOL client_cli_authenticate(freerdp* instance, char** username, char** password, char** domain)
{

View File

@ -24,7 +24,7 @@
BOOL freerdp_smartcard_list(const rdpSettings* settings)
{
SmartcardCerts* certs = NULL;
SmartcardCertInfo** certs = NULL;
DWORD i, count;
if (!smartcard_enumerateCerts(settings, &certs, &count))
@ -32,7 +32,7 @@ BOOL freerdp_smartcard_list(const rdpSettings* settings)
for (i = 0; i < count; i++)
{
const SmartcardCertInfo* info = smartcard_getCertInfo(certs, i);
const SmartcardCertInfo* info = certs[i];
char asciiStr[256] = { 0 };
WINPR_ASSERT(info);
@ -54,7 +54,7 @@ BOOL freerdp_smartcard_list(const rdpSettings* settings)
if (info->upn)
printf("\t* UPN: %s\n", info->upn);
}
smartcardCerts_Free(&certs);
smartcardCertList_Free(certs, count);
return TRUE;
}

View File

@ -138,6 +138,9 @@ extern "C"
FREERDP_API BOOL client_cli_authenticate_ex(freerdp* instance, char** username, char** password,
char** domain, rdp_auth_reason reason);
FREERDP_API BOOL client_cli_choose_smartcard(SmartcardCertInfo** cert_list, DWORD count,
DWORD* choice);
FREERDP_API void
freerdp_client_OnChannelConnectedEventHandler(void* context,
const ChannelConnectedEventArgs* e);

View File

@ -58,6 +58,7 @@ typedef RDP_CLIENT_ENTRY_POINTS_V1 RDP_CLIENT_ENTRY_POINTS;
#include <freerdp/heartbeat.h>
typedef struct stream_dump_context rdpStreamDumpContext;
typedef struct SmartcardCertInfo_st SmartcardCertInfo;
#ifdef __cplusplus
extern "C"
@ -117,6 +118,7 @@ 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);
/** @brief Callback used if user interaction is required to accept
* an unknown certificate.
@ -493,7 +495,12 @@ owned by rdpRdp */
Callback for authentication.
It is used to get the username/password. The reason
argument tells why it was called. */
UINT64 paddingE[80 - 70]; /* 70 */
ALIGN64 pChooseSmartcard
ChooseSmartcard; /* (offset 70)
Callback for choosing a smartcard for logon.
Used when multiple smartcards are available. Returns an index into a list
of SmartcardCertInfo pointers */
UINT64 paddingE[80 - 71]; /* 71 */
};
struct rdp_channel_handles

View File

@ -22,9 +22,9 @@
#include <freerdp/settings.h>
#include <freerdp/crypto/crypto.h>
typedef struct sSmartCardCerts SmartcardCerts;
typedef struct SmartcardKeyInfo_st SmartcardKeyInfo;
typedef struct
typedef struct SmartcardCertInfo_st
{
LPWSTR csp;
LPWSTR reader;
@ -38,11 +38,13 @@ typedef struct
char* subject;
char* issuer;
BYTE sha1Hash[20];
SmartcardKeyInfo* key_info;
} SmartcardCertInfo;
FREERDP_API BOOL smartcard_enumerateCerts(const rdpSettings* settings, SmartcardCerts** scCert,
FREERDP_API BOOL smartcard_enumerateCerts(const rdpSettings* settings, SmartcardCertInfo*** scCerts,
DWORD* retCount);
FREERDP_API const SmartcardCertInfo* smartcard_getCertInfo(SmartcardCerts* scCerts, DWORD index);
FREERDP_API void smartcardCerts_Free(SmartcardCerts** pscCert);
FREERDP_API BOOL smartcard_getCert(const rdpContext* context, SmartcardCertInfo** cert);
FREERDP_API void smartcardCertInfo_Free(SmartcardCertInfo* pscCert);
FREERDP_API void smartcardCertList_Free(SmartcardCertInfo** pscCert, DWORD count);
#endif /* LIBFREERDP_CORE_SMARTCARDLOGON_H */

View File

@ -124,8 +124,7 @@ struct rdp_nla
rdpCredsspAuth* auth;
char* pkinitArgs;
SmartcardCerts* smartcardCerts;
DWORD nsmartcardCerts;
SmartcardCertInfo* smartcardCert;
BYTE certSha1[20];
};
@ -187,7 +186,6 @@ static const UINT32 NonceLength = 32;
static BOOL nla_adjust_settings_from_smartcard(rdpNla* nla)
{
const SmartcardCertInfo* info = NULL;
rdpSettings* settings;
BOOL ret = FALSE;
@ -200,35 +198,18 @@ static BOOL nla_adjust_settings_from_smartcard(rdpNla* nla)
if (!settings->SmartcardLogon)
return TRUE;
smartcardCerts_Free(&nla->smartcardCerts);
smartcardCertInfo_Free(nla->smartcardCert);
if (!smartcard_enumerateCerts(settings, &nla->smartcardCerts, &nla->nsmartcardCerts))
if (!smartcard_getCert(nla->rdpcontext, &nla->smartcardCert))
{
WLog_ERR(TAG, "unable to list smartcard certificates");
WLog_ERR(TAG, "unable to get smartcard certificate for logon");
return FALSE;
}
if (nla->nsmartcardCerts < 1)
{
WLog_ERR(TAG, "no smartcard certificates found");
goto out;
}
if (nla->nsmartcardCerts != 1)
goto setup_pin;
info = smartcard_getCertInfo(nla->smartcardCerts, 0);
if (!info)
goto out;
/*
* just one result let's try to fill missing parameters
*/
if (!settings->CspName)
{
if (info->csp &&
ConvertFromUnicode(CP_UTF8, 0, info->csp, -1, &settings->CspName, 0, NULL, FALSE) <= 0)
if (nla->smartcardCert->csp && ConvertFromUnicode(CP_UTF8, 0, nla->smartcardCert->csp, -1,
&settings->CspName, 0, NULL, FALSE) <= 0)
{
WLog_ERR(TAG, "unable to set CSP name");
goto out;
@ -240,48 +221,49 @@ static BOOL nla_adjust_settings_from_smartcard(rdpNla* nla)
}
}
if (!settings->Username && info->userHint)
if (!settings->Username && nla->smartcardCert->userHint)
{
if (!freerdp_settings_set_string(settings, FreeRDP_Username, info->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 && info->domainHint)
if (!settings->Domain && nla->smartcardCert->domainHint)
{
if (!freerdp_settings_set_string(settings, FreeRDP_Domain, info->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 && info->reader)
if (!settings->ReaderName && nla->smartcardCert->reader)
{
if (ConvertFromUnicode(CP_UTF8, 0, info->reader, -1, &settings->ReaderName, 0, NULL, NULL) <
0)
if (ConvertFromUnicode(CP_UTF8, 0, nla->smartcardCert->reader, -1, &settings->ReaderName, 0,
NULL, NULL) < 0)
{
WLog_ERR(TAG, "unable to copy reader name");
goto out;
}
}
if (!settings->ContainerName && info->containerName)
if (!settings->ContainerName && nla->smartcardCert->containerName)
{
if (!freerdp_settings_set_string(settings, FreeRDP_ContainerName, info->containerName))
if (!freerdp_settings_set_string(settings, FreeRDP_ContainerName,
nla->smartcardCert->containerName))
{
WLog_ERR(TAG, "unable to copy container name");
goto out;
}
}
memcpy(nla->certSha1, info->sha1Hash, sizeof(nla->certSha1));
memcpy(nla->certSha1, nla->smartcardCert->sha1Hash, sizeof(nla->certSha1));
if (info->pkinitArgs)
if (nla->smartcardCert->pkinitArgs)
{
nla->pkinitArgs = _strdup(info->pkinitArgs);
nla->pkinitArgs = _strdup(nla->smartcardCert->pkinitArgs);
if (!nla->pkinitArgs)
{
WLog_ERR(TAG, "unable to copy pkinitArgs");
@ -289,8 +271,6 @@ static BOOL nla_adjust_settings_from_smartcard(rdpNla* nla)
}
}
setup_pin:
ret = TRUE;
out:
return ret;
@ -1699,7 +1679,7 @@ void nla_free(rdpNla* nla)
if (!nla)
return;
smartcardCerts_Free(&nla->smartcardCerts);
smartcardCertInfo_Free(nla->smartcardCert);
sspi_SecBufferFree(&nla->pubKeyAuth);
sspi_SecBufferFree(&nla->authInfo);
sspi_SecBufferFree(&nla->negoToken);

View File

@ -36,39 +36,12 @@
#define TAG FREERDP_TAG("smartcardlogon")
typedef struct
struct SmartcardKeyInfo_st
{
SmartcardCertInfo info;
char* certPath;
char* keyPath;
} SmartcardCertInfoPrivate;
struct sSmartCardCerts
{
size_t count;
SmartcardCertInfoPrivate* certs;
};
static void smartcardCertInfo_Free(SmartcardCertInfo* scCert)
{
const SmartcardCertInfo empty = { 0 };
if (!scCert)
return;
free(scCert->csp);
free(scCert->reader);
crypto_cert_free(scCert->certificate);
free(scCert->pkinitArgs);
free(scCert->containerName);
free(scCert->upn);
free(scCert->userHint);
free(scCert->domainHint);
free(scCert->subject);
free(scCert->issuer);
*scCert = empty;
}
static void delete_file(char* path)
{
WCHAR* wpath = NULL;
@ -97,33 +70,46 @@ static void delete_file(char* path)
free(path);
}
static void smartcardCertInfoPrivate_Free(SmartcardCertInfoPrivate* scCert)
static void smartcardKeyInfo_Free(SmartcardKeyInfo* key_info)
{
const SmartcardCertInfoPrivate empty = { 0 };
if (!scCert)
if (!key_info)
return;
smartcardCertInfo_Free(&scCert->info);
delete_file(scCert->keyPath);
delete_file(scCert->certPath);
*scCert = empty;
delete_file(key_info->certPath);
delete_file(key_info->keyPath);
free(key_info);
}
void smartcardCerts_Free(SmartcardCerts** pscCert)
void smartcardCertInfo_Free(SmartcardCertInfo* scCert)
{
size_t x;
SmartcardCerts* scCert;
WINPR_ASSERT(pscCert);
scCert = *pscCert;
if (!scCert)
return;
for (x = 0; x < scCert->count; x++)
smartcardCertInfoPrivate_Free(&scCert->certs[x]);
free(scCert->csp);
free(scCert->reader);
crypto_cert_free(scCert->certificate);
free(scCert->pkinitArgs);
free(scCert->containerName);
free(scCert->upn);
free(scCert->userHint);
free(scCert->domainHint);
free(scCert->subject);
free(scCert->issuer);
smartcardKeyInfo_Free(scCert->key_info);
free(scCert);
*pscCert = NULL;
}
void smartcardCertList_Free(SmartcardCertInfo** cert_list, DWORD count)
{
if (!cert_list)
return;
for (DWORD i = 0; i < count; i++)
smartcardCertInfo_Free(cert_list[i]);
free(cert_list);
}
static BOOL treat_sc_cert(SmartcardCertInfo* scCert)
@ -207,12 +193,13 @@ static BOOL build_pkinit_args(const rdpSettings* settings, SmartcardCertInfo* sc
static BOOL list_provider_keys(const rdpSettings* settings, NCRYPT_PROV_HANDLE provider,
LPCWSTR csp, LPCWSTR scope, const char* userFilter,
const char* domainFilter, SmartcardCerts** pcerts, size_t* pcount)
const char* domainFilter, SmartcardCertInfo*** pcerts,
size_t* pcount)
{
BOOL ret = FALSE;
NCryptKeyName* keyName = NULL;
PVOID enumState = NULL;
SmartcardCerts* certs = *pcerts;
SmartcardCertInfo** cert_list = *pcerts;
size_t count = *pcount;
while (NCryptEnumKeys(provider, scope, &keyName, &enumState, NCRYPT_SILENT_FLAG) ==
@ -222,32 +209,19 @@ static BOOL list_provider_keys(const rdpSettings* settings, NCRYPT_PROV_HANDLE p
PBYTE certBytes = NULL;
DWORD dwFlags = NCRYPT_SILENT_FLAG;
DWORD cbOutput;
SmartcardCertInfoPrivate* cert;
SmartcardCertInfo* cert = NULL;
BOOL haveError = TRUE;
SECURITY_STATUS status;
count++;
{
SmartcardCerts* tmp =
realloc(certs, sizeof(SmartcardCerts) + (sizeof(SmartcardCertInfoPrivate) * count));
if (!tmp)
{
WLog_ERR(TAG, "unable to reallocate certs");
goto out;
}
certs = tmp;
certs->count = count;
certs->certs = (SmartcardCertInfoPrivate*)(certs + 1);
}
cert = calloc(1, sizeof(SmartcardCertInfo));
if (!cert)
goto out;
cert = &certs->certs[count - 1];
ZeroMemory(cert, sizeof(*cert));
if (ConvertFromUnicode(CP_UTF8, 0, keyName->pszName, -1, &cert->info.containerName, 0, NULL,
if (ConvertFromUnicode(CP_UTF8, 0, keyName->pszName, -1, &cert->containerName, 0, NULL,
NULL) <= 0)
goto endofloop;
WLog_DBG(TAG, "opening key %s", cert->info.containerName);
WLog_DBG(TAG, "opening key %s", cert->containerName);
status =
NCryptOpenKey(provider, &phKey, keyName->pszName, keyName->dwLegacyKeySpec, dwFlags);
@ -261,17 +235,17 @@ static BOOL list_provider_keys(const rdpSettings* settings, NCRYPT_PROV_HANDLE p
goto endofloop;
}
cert->info.csp = _wcsdup(csp);
if (!cert->info.csp)
cert->csp = _wcsdup(csp);
if (!cert->csp)
goto endofloop;
#ifndef _WIN32
status = NCryptGetProperty(phKey, NCRYPT_WINPR_SLOTID, (PBYTE)&cert->info.slotId, 4,
&cbOutput, dwFlags);
status = NCryptGetProperty(phKey, NCRYPT_WINPR_SLOTID, (PBYTE)&cert->slotId, 4, &cbOutput,
dwFlags);
if (status != ERROR_SUCCESS)
{
WLog_ERR(TAG, "unable to retrieve slotId for key %s, status=%s",
cert->info.containerName, winpr_NCryptSecurityStatusError(status));
WLog_ERR(TAG, "unable to retrieve slotId for key %s, status=%s", cert->containerName,
winpr_NCryptSecurityStatusError(status));
goto endofloop;
}
#endif /* _WIN32 */
@ -282,22 +256,22 @@ static BOOL list_provider_keys(const rdpSettings* settings, NCRYPT_PROV_HANDLE p
if (status != ERROR_SUCCESS)
{
WLog_DBG(TAG, "unable to retrieve reader's name length for key %s",
cert->info.containerName);
cert->containerName);
goto endofloop;
}
cert->info.reader = calloc(1, cbOutput + 2);
if (!cert->info.reader)
cert->reader = calloc(1, cbOutput + 2);
if (!cert->reader)
{
WLog_ERR(TAG, "unable to allocate reader's name for key %s", cert->info.containerName);
WLog_ERR(TAG, "unable to allocate reader's name for key %s", cert->containerName);
goto endofloop;
}
status = NCryptGetProperty(phKey, NCRYPT_READER_PROPERTY, (PBYTE)cert->info.reader,
cbOutput + 2, &cbOutput, dwFlags);
status = NCryptGetProperty(phKey, NCRYPT_READER_PROPERTY, (PBYTE)cert->reader, cbOutput + 2,
&cbOutput, dwFlags);
if (status != ERROR_SUCCESS)
{
WLog_ERR(TAG, "unable to retrieve reader's name for key %s", cert->info.containerName);
WLog_ERR(TAG, "unable to retrieve reader's name for key %s", cert->containerName);
goto endofloop;
}
@ -316,7 +290,7 @@ static BOOL list_provider_keys(const rdpSettings* settings, NCRYPT_PROV_HANDLE p
if (!certBytes)
{
WLog_ERR(TAG, "unable to allocate %" PRIu32 " certBytes for key %s", cbOutput,
cert->info.containerName);
cert->containerName);
goto endofloop;
}
@ -324,49 +298,47 @@ static BOOL list_provider_keys(const rdpSettings* settings, NCRYPT_PROV_HANDLE p
&cbOutput, dwFlags);
if (status != ERROR_SUCCESS)
{
WLog_ERR(TAG, "unable to retrieve certificate for key %s", cert->info.containerName);
WLog_ERR(TAG, "unable to retrieve certificate for key %s", cert->containerName);
goto endofloop;
}
if (!winpr_Digest(WINPR_MD_SHA1, certBytes, cbOutput, cert->info.sha1Hash,
sizeof(cert->info.sha1Hash)))
if (!winpr_Digest(WINPR_MD_SHA1, certBytes, cbOutput, cert->sha1Hash,
sizeof(cert->sha1Hash)))
{
WLog_ERR(TAG, "unable to compute certificate sha1 for key %s",
cert->info.containerName);
WLog_ERR(TAG, "unable to compute certificate sha1 for key %s", cert->containerName);
goto endofloop;
}
cert->info.certificate = crypto_cert_read(certBytes, cbOutput);
cert->certificate = crypto_cert_read(certBytes, cbOutput);
if (!cert->info.certificate)
if (!cert->certificate)
{
WLog_ERR(TAG, "unable to parse X509 certificate for key %s", cert->info.containerName);
WLog_ERR(TAG, "unable to parse X509 certificate for key %s", cert->containerName);
goto endofloop;
}
if (!treat_sc_cert(&cert->info))
if (!treat_sc_cert(cert))
{
WLog_DBG(TAG, "error treating cert");
goto endofloop;
}
if (userFilter && cert->info.userHint && strcmp(cert->info.userHint, userFilter) != 0)
if (userFilter && cert->userHint && strcmp(cert->userHint, userFilter) != 0)
{
WLog_DBG(TAG, "discarding non matching cert by user %s@%s", cert->info.userHint,
cert->info.domainHint);
WLog_DBG(TAG, "discarding non matching cert by user %s@%s", cert->userHint,
cert->domainHint);
goto endofloop;
}
if (domainFilter && cert->info.domainHint &&
strcmp(cert->info.domainHint, domainFilter) != 0)
if (domainFilter && cert->domainHint && strcmp(cert->domainHint, domainFilter) != 0)
{
WLog_DBG(TAG, "discarding non matching cert by domain(%s) %s@%s", domainFilter,
cert->info.userHint, cert->info.domainHint);
cert->userHint, cert->domainHint);
goto endofloop;
}
#ifndef _WIN32
if (!build_pkinit_args(settings, &cert->info))
if (!build_pkinit_args(settings, cert))
{
WLog_ERR(TAG, "error build pkinit args");
goto endofloop;
@ -381,23 +353,33 @@ static BOOL list_provider_keys(const rdpSettings* settings, NCRYPT_PROV_HANDLE p
NCryptFreeObject((NCRYPT_HANDLE)phKey);
if (haveError)
smartcardCertInfo_Free(cert);
else
{
smartcardCertInfoPrivate_Free(cert);
count--;
SmartcardCertInfo** tmp;
tmp = realloc(cert_list, sizeof(SmartcardCertInfo*) * (count + 1));
if (!tmp)
{
WLog_ERR(TAG, "unable to reallocate certs");
goto out;
}
cert_list = tmp;
cert_list[count++] = cert;
}
}
ret = TRUE;
out:
*pcount = count;
*pcerts = certs;
*pcerts = cert_list;
NCryptFreeBuffer(enumState);
return ret;
}
static BOOL smartcard_hw_enumerateCerts(const rdpSettings* settings, LPCWSTR csp,
const char* reader, const char* userFilter,
const char* domainFilter, SmartcardCerts** scCerts,
const char* domainFilter, SmartcardCertInfo*** scCerts,
DWORD* retCount)
{
BOOL ret = FALSE;
@ -405,7 +387,7 @@ static BOOL smartcard_hw_enumerateCerts(const rdpSettings* settings, LPCWSTR csp
NCRYPT_PROV_HANDLE provider;
SECURITY_STATUS status;
size_t count = 0;
SmartcardCerts* certs = NULL;
SmartcardCertInfo** cert_list = NULL;
const char* Pkcs11Module = freerdp_settings_get_string(settings, FreeRDP_Pkcs11Module);
WINPR_ASSERT(scCerts);
@ -440,7 +422,7 @@ static BOOL smartcard_hw_enumerateCerts(const rdpSettings* settings, LPCWSTR csp
}
status = list_provider_keys(settings, provider, csp, scope, userFilter, domainFilter,
&certs, &count);
&cert_list, &count);
NCryptFreeObject((NCRYPT_HANDLE)provider);
if (status != ERROR_SUCCESS)
{
@ -484,7 +466,7 @@ static BOOL smartcard_hw_enumerateCerts(const rdpSettings* settings, LPCWSTR csp
continue;
if (!list_provider_keys(settings, provider, names[i].pszName, scope, userFilter,
domainFilter, &certs, &count))
domainFilter, &cert_list, &count))
WLog_INFO(TAG, "error when retrieving keys in CSP '%s'", providerNameStr);
NCryptFreeObject((NCRYPT_HANDLE)provider);
@ -493,13 +475,13 @@ static BOOL smartcard_hw_enumerateCerts(const rdpSettings* settings, LPCWSTR csp
NCryptFreeBuffer(names);
}
*scCerts = certs;
*scCerts = cert_list;
*retCount = (DWORD)count;
ret = TRUE;
out:
if (!ret)
smartcardCerts_Free(&certs);
smartcardCertList_Free(cert_list, count);
free(scope);
return ret;
}
@ -528,14 +510,13 @@ static char* create_temporary_file(void)
return path;
}
static BOOL smartcard_sw_enumerateCerts(const rdpSettings* settings, SmartcardCerts** scCerts,
static BOOL smartcard_sw_enumerateCerts(const rdpSettings* settings, SmartcardCertInfo*** scCerts,
DWORD* retCount)
{
BOOL rc = FALSE;
int res;
SmartcardCerts* certs = NULL;
SmartcardCertInfoPrivate* cert;
const size_t count = 1;
SmartcardCertInfo** cert_list = NULL;
SmartcardCertInfo* cert = NULL;
char* keyPath = create_temporary_file();
char* certPath = create_temporary_file();
@ -543,32 +524,38 @@ static BOOL smartcard_sw_enumerateCerts(const rdpSettings* settings, SmartcardCe
WINPR_ASSERT(scCerts);
WINPR_ASSERT(retCount);
certs = calloc(count, sizeof(SmartcardCertInfoPrivate) + sizeof(SmartcardCerts));
if (!certs)
cert_list = calloc(1, sizeof(SmartcardCertInfo*));
if (!cert_list)
goto out_error;
certs->count = count;
cert = certs->certs = (SmartcardCertInfoPrivate*)(certs + 1);
*cert_list = calloc(1, sizeof(SmartcardCertInfo));
if (!(*cert_list))
goto out_error;
cert = *cert_list;
cert->info.certificate =
cert->key_info = calloc(1, sizeof(SmartcardKeyInfo));
if (!cert->key_info)
goto out_error;
cert->certificate =
crypto_cert_pem_read(freerdp_settings_get_string(settings, FreeRDP_SmartcardCertificate));
if (!cert->info.certificate)
if (!cert->certificate)
{
WLog_ERR(TAG, "unable to read smartcard certificate");
goto out_error;
}
if (!treat_sc_cert(&cert->info))
if (!treat_sc_cert(cert))
{
WLog_ERR(TAG, "unable to treat smartcard certificate");
goto out_error;
}
if (ConvertToUnicode(CP_UTF8, 0, "FreeRDP Emulator", -1, &cert->info.reader, 0) < 0)
if (ConvertToUnicode(CP_UTF8, 0, "FreeRDP Emulator", -1, &cert->reader, 0) < 0)
goto out_error;
cert->info.containerName = _strdup("Private Key 00");
if (!cert->info.containerName)
cert->containerName = _strdup("Private Key 00");
if (!cert->containerName)
goto out_error;
/* compute PKINIT args FILE:<cert file>,<key file>
@ -581,24 +568,24 @@ static BOOL smartcard_sw_enumerateCerts(const rdpSettings* settings, SmartcardCe
goto out_error;
if (!write_pem(certPath, freerdp_settings_get_string(settings, FreeRDP_SmartcardCertificate)))
goto out_error;
res = allocating_sprintf(&cert->info.pkinitArgs, "FILE:%s,%s", certPath, keyPath);
res = allocating_sprintf(&cert->pkinitArgs, "FILE:%s,%s", certPath, keyPath);
if (res <= 0)
goto out_error;
cert->certPath = certPath;
cert->keyPath = keyPath;
cert->key_info->certPath = certPath;
cert->key_info->keyPath = keyPath;
rc = TRUE;
*scCerts = certs;
*retCount = (DWORD)certs->count;
*scCerts = cert_list;
*retCount = 1;
out_error:
if (!rc)
smartcardCerts_Free(&certs);
smartcardCertList_Free(cert_list, 1);
return rc;
}
BOOL smartcard_enumerateCerts(const rdpSettings* settings, SmartcardCerts** scCerts,
BOOL smartcard_enumerateCerts(const rdpSettings* settings, SmartcardCertInfo*** scCerts,
DWORD* retCount)
{
BOOL ret;
@ -630,11 +617,47 @@ BOOL smartcard_enumerateCerts(const rdpSettings* settings, SmartcardCerts** scCe
return ret;
}
const SmartcardCertInfo* smartcard_getCertInfo(SmartcardCerts* scCerts, DWORD index)
BOOL smartcard_getCert(const rdpContext* context, SmartcardCertInfo** cert)
{
WINPR_ASSERT(scCerts);
if (index >= scCerts->count)
return NULL;
WINPR_ASSERT(context);
return &scCerts->certs[index].info;
const freerdp* instance = context->instance;
const rdpSettings* settings = context->settings;
SmartcardCertInfo** cert_list;
DWORD count;
WINPR_ASSERT(instance);
WINPR_ASSERT(settings);
if (!smartcard_enumerateCerts(settings, &cert_list, &count))
return FALSE;
if (count < 1)
{
WLog_ERR(TAG, "no suitable smartcard certificates were found");
return FALSE;
}
if (count > 1)
{
DWORD index;
if (!instance->ChooseSmartcard || !instance->ChooseSmartcard(cert_list, count, &index))
{
WLog_ERR(TAG, "more than one suitable smartcard certificate was found");
smartcardCertList_Free(cert_list, count);
return FALSE;
}
*cert = cert_list[index];
for (DWORD i = 0; i < index; i++)
smartcardCertInfo_Free(cert_list[i]);
for (DWORD i = index + 1; i < count; i++)
smartcardCertInfo_Free(cert_list[i]);
}
else
*cert = cert_list[0];
free(cert_list);
return TRUE;
}