diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 5d6b13515..82d738528 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -3354,9 +3354,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, { const char* f = &cur[5]; - if (!freerdp_settings_set_string(settings, FreeRDP_SmartcardCertificateFile, - f) || - !read_pem_file(settings, FreeRDP_SmartcardCertificate, f)) + if (!read_pem_file(settings, FreeRDP_SmartcardCertificate, f)) { free(ptr.p); return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; @@ -3365,9 +3363,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, else if (strncmp("key:", cur, 4) == 0) { const char* f = &cur[4]; - if (!freerdp_settings_set_string(settings, FreeRDP_SmartcardPrivateKeyFile, - f) || - !read_pem_file(settings, FreeRDP_SmartcardPrivateKey, f)) + if (!read_pem_file(settings, FreeRDP_SmartcardPrivateKey, f)) { free(ptr.p); return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; diff --git a/client/common/smartcard_cli.c b/client/common/smartcard_cli.c index ef2974e6e..406501e7d 100644 --- a/client/common/smartcard_cli.c +++ b/client/common/smartcard_cli.c @@ -16,35 +16,41 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +#include + #include #include "../../libfreerdp/core/smartcardlogon.h" BOOL freerdp_smartcard_list(const rdpSettings* settings) { - SmartcardCert certs[64] = { 0 }; + SmartcardCerts* certs = NULL; DWORD i, count; - if (!smartcard_enumerateCerts(settings, certs, 64, &count)) + if (!smartcard_enumerateCerts(settings, &certs, &count)) return FALSE; for (i = 0; i < count; i++) { + const SmartcardCertInfo* info = smartcard_getCertInfo(certs, i); char readerName[256] = { 0 }; - printf("%d: %s\n", i, certs[i].subject); + WINPR_ASSERT(info); - if (WideCharToMultiByte(CP_UTF8, 0, certs[i].reader, -1, readerName, sizeof(readerName), - NULL, NULL) > 0) + printf("%d: %s\n", i, info->subject); + + if (WideCharToMultiByte(CP_UTF8, 0, info->reader, -1, readerName, sizeof(readerName), NULL, + NULL) > 0) printf("\t* reader: %s\n", readerName); #ifndef _WIN32 - printf("\t* slotId: %" PRIu32 "\n", certs[i].slotId); - printf("\t* pkinitArgs: %s\n", certs[i].pkinitArgs); + printf("\t* slotId: %" PRIu32 "\n", info->slotId); + printf("\t* pkinitArgs: %s\n", info->pkinitArgs); #endif - printf("\t* containerName: %s\n", certs[i].containerName); - if (certs[i].upn) - printf("\t* UPN: %s\n", certs[i].upn); - - smartcardCert_Free(&certs[i]); + printf("\t* containerName: %s\n", info->containerName); + if (info->upn) + printf("\t* UPN: %s\n", info->upn); } + smartcardCerts_Free(certs); + return TRUE; } diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index 2ea5701a2..0c635068a 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -663,16 +663,14 @@ typedef struct #define FreeRDP_SmartcardPrivateKey (1286) #define FreeRDP_SmartcardPin (1287) #define FreeRDP_SmartcardEmulation (1288) -#define FreeRDP_SmartcardCertificateFile (1289) -#define FreeRDP_SmartcardPrivateKeyFile (1290) -#define FreeRDP_Pkcs11Module (1291) -#define FreeRDP_Pin (1292) -#define FreeRDP_KeySpec (1293) -#define FreeRDP_CardName (1294) -#define FreeRDP_ReaderName (1295) -#define FreeRDP_ContainerName (1296) -#define FreeRDP_CspName (1297) -#define FreeRDP_PkinitAnchors (1298) +#define FreeRDP_Pkcs11Module (1289) +#define FreeRDP_Pin (1290) +#define FreeRDP_KeySpec (1291) +#define FreeRDP_CardName (1292) +#define FreeRDP_ReaderName (1293) +#define FreeRDP_ContainerName (1294) +#define FreeRDP_CspName (1295) +#define FreeRDP_PkinitAnchors (1296) #define FreeRDP_KerberosKdc (1344) #define FreeRDP_KerberosRealm (1345) #define FreeRDP_KerberosStartTime (1346) @@ -1159,21 +1157,19 @@ struct rdp_settings UINT64 padding1284[1285 - 1284]; /* 1284 */ /* Settings used for smartcard emulation */ - ALIGN64 char* SmartcardCertificate; /* 1285 */ - ALIGN64 char* SmartcardPrivateKey; /* 1286 */ - ALIGN64 char* SmartcardPin; /* 1287 */ - ALIGN64 BOOL SmartcardEmulation; /* 1288 */ - ALIGN64 char* SmartcardCertificateFile; /* 1289 */ - ALIGN64 char* SmartcardPrivateKeyFile; /* 1290 */ - ALIGN64 char* Pkcs11Module; /* 1291 */ - ALIGN64 char* Pin; /* 1292 */ - ALIGN64 UINT32 KeySpec; /* 1293 */ - ALIGN64 char* CardName; /* 1294 */ - ALIGN64 char* ReaderName; /* 1295 */ - ALIGN64 char* ContainerName; /* 1296 */ - ALIGN64 char* CspName; /* 1297 */ - ALIGN64 char* PkinitAnchors; /* 1298 */ - UINT64 padding1344[1344 - 1299]; /* 1299 */ + ALIGN64 char* SmartcardCertificate; /* 1285 */ + ALIGN64 char* SmartcardPrivateKey; /* 1286 */ + ALIGN64 char* SmartcardPin; /* 1287 */ + ALIGN64 BOOL SmartcardEmulation; /* 1288 */ + ALIGN64 char* Pkcs11Module; /* 1289 */ + ALIGN64 char* Pin; /* 1290 */ + ALIGN64 UINT32 KeySpec; /* 1291 */ + ALIGN64 char* CardName; /* 1292 */ + ALIGN64 char* ReaderName; /* 1293 */ + ALIGN64 char* ContainerName; /* 1294 */ + ALIGN64 char* CspName; /* 1295 */ + ALIGN64 char* PkinitAnchors; /* 1296 */ + UINT64 padding1344[1344 - 1297]; /* 1297 */ /* Kerberos Authentication */ ALIGN64 char* KerberosKdc; /* 1344 */ diff --git a/libfreerdp/common/settings_getters.c b/libfreerdp/common/settings_getters.c index 1bab14faa..cef72b4b9 100644 --- a/libfreerdp/common/settings_getters.c +++ b/libfreerdp/common/settings_getters.c @@ -2554,18 +2554,12 @@ const char* freerdp_settings_get_string(const rdpSettings* settings, size_t id) case FreeRDP_SmartcardCertificate: return settings->SmartcardCertificate; - case FreeRDP_SmartcardCertificateFile: - return settings->SmartcardCertificateFile; - case FreeRDP_SmartcardPin: return settings->SmartcardPin; case FreeRDP_SmartcardPrivateKey: return settings->SmartcardPrivateKey; - case FreeRDP_SmartcardPrivateKeyFile: - return settings->SmartcardPrivateKeyFile; - case FreeRDP_TargetNetAddress: return settings->TargetNetAddress; @@ -2818,18 +2812,12 @@ char* freerdp_settings_get_string_writable(rdpSettings* settings, size_t id) case FreeRDP_SmartcardCertificate: return settings->SmartcardCertificate; - case FreeRDP_SmartcardCertificateFile: - return settings->SmartcardCertificateFile; - case FreeRDP_SmartcardPin: return settings->SmartcardPin; case FreeRDP_SmartcardPrivateKey: return settings->SmartcardPrivateKey; - case FreeRDP_SmartcardPrivateKeyFile: - return settings->SmartcardPrivateKeyFile; - case FreeRDP_TargetNetAddress: return settings->TargetNetAddress; @@ -3092,18 +3080,12 @@ BOOL freerdp_settings_set_string_(rdpSettings* settings, size_t id, const char* case FreeRDP_SmartcardCertificate: return update_string(&settings->SmartcardCertificate, cnv.cc, len, cleanup); - case FreeRDP_SmartcardCertificateFile: - return update_string(&settings->SmartcardCertificateFile, cnv.cc, len, cleanup); - case FreeRDP_SmartcardPin: return update_string(&settings->SmartcardPin, cnv.cc, len, cleanup); case FreeRDP_SmartcardPrivateKey: return update_string(&settings->SmartcardPrivateKey, cnv.cc, len, cleanup); - case FreeRDP_SmartcardPrivateKeyFile: - return update_string(&settings->SmartcardPrivateKeyFile, cnv.cc, len, cleanup); - case FreeRDP_TargetNetAddress: return update_string(&settings->TargetNetAddress, cnv.cc, len, cleanup); diff --git a/libfreerdp/common/settings_str.c b/libfreerdp/common/settings_str.c index 760d0662c..83d71c49c 100644 --- a/libfreerdp/common/settings_str.c +++ b/libfreerdp/common/settings_str.c @@ -383,10 +383,8 @@ static const struct settings_str_entry settings_map[] = { { FreeRDP_ServerHostname, 7, "FreeRDP_ServerHostname" }, { FreeRDP_ShellWorkingDirectory, 7, "FreeRDP_ShellWorkingDirectory" }, { FreeRDP_SmartcardCertificate, 7, "FreeRDP_SmartcardCertificate" }, - { FreeRDP_SmartcardCertificateFile, 7, "FreeRDP_SmartcardCertificateFile" }, { FreeRDP_SmartcardPin, 7, "FreeRDP_SmartcardPin" }, { FreeRDP_SmartcardPrivateKey, 7, "FreeRDP_SmartcardPrivateKey" }, - { FreeRDP_SmartcardPrivateKeyFile, 7, "FreeRDP_SmartcardPrivateKeyFile" }, { FreeRDP_TargetNetAddress, 7, "FreeRDP_TargetNetAddress" }, { FreeRDP_TransportDumpFile, 7, "FreeRDP_TransportDumpFile" }, { FreeRDP_Username, 7, "FreeRDP_Username" }, diff --git a/libfreerdp/core/nla.c b/libfreerdp/core/nla.c index 595fdd4c1..d3ec09178 100644 --- a/libfreerdp/core/nla.c +++ b/libfreerdp/core/nla.c @@ -538,9 +538,9 @@ void nla_identity_free(SEC_WINNT_AUTH_IDENTITY* identity) static BOOL nla_adjust_settings_from_smartcard(rdpNla* nla) { -#define MAX_SC_CERTS 64 - SmartcardCert certs[MAX_SC_CERTS]; - DWORD count, i = 0; + SmartcardCerts* certs = NULL; + const SmartcardCertInfo* info = NULL; + DWORD count; rdpSettings* settings = nla->settings; SEC_WINPR_KERBEROS_SETTINGS* kerbSettings = &nla->kerberosSettings; BOOL ret = FALSE; @@ -564,68 +564,71 @@ static BOOL nla_adjust_settings_from_smartcard(rdpNla* nla) } } - if (!smartcard_enumerateCerts(settings, certs, MAX_SC_CERTS, &count)) + if (!smartcard_enumerateCerts(settings, &certs, &count)) { WLog_ERR(TAG, "unable to list smartcard certificates"); return FALSE; } - if (!count) + if (count < 1) { WLog_ERR(TAG, "no smartcard certificates found"); - return FALSE; + goto out; } if (count != 1) goto setup_pin; + info = smartcard_getCertInfo(certs, 0); + if (!info) + goto out; + /* * just one result let's try to fill missing parameters */ - if (!settings->Username && certs[0].userHint) + if (!settings->Username && info->userHint) { - if (!freerdp_settings_set_string(settings, FreeRDP_Username, certs[0].userHint)) + if (!freerdp_settings_set_string(settings, FreeRDP_Username, info->userHint)) { WLog_ERR(TAG, "unable to copy certificate username"); goto out; } } - if (!settings->Domain && certs[0].domainHint) + if (!settings->Domain && info->domainHint) { - if (!freerdp_settings_set_string(settings, FreeRDP_Domain, certs[0].domainHint)) + if (!freerdp_settings_set_string(settings, FreeRDP_Domain, info->domainHint)) { WLog_ERR(TAG, "unable to copy certificate domain"); goto out; } } - if (!settings->ReaderName && certs[0].reader) + if (!settings->ReaderName && info->reader) { - if (ConvertFromUnicode(CP_UTF8, 0, certs[0].reader, -1, &settings->ReaderName, 0, NULL, - NULL) < 0) + if (ConvertFromUnicode(CP_UTF8, 0, info->reader, -1, &settings->ReaderName, 0, NULL, NULL) < + 0) { WLog_ERR(TAG, "unable to copy reader name"); goto out; } } - if (!settings->ContainerName && certs[0].containerName) + if (!settings->ContainerName && info->containerName) { - if (!freerdp_settings_set_string(settings, FreeRDP_ContainerName, certs[0].containerName)) + if (!freerdp_settings_set_string(settings, FreeRDP_ContainerName, info->containerName)) { WLog_ERR(TAG, "unable to copy container name"); goto out; } } - memcpy(nla->kerberosSettings.certSha1, certs[0].sha1Hash, - sizeof(nla->kerberosSettings.certSha1)); + memcpy(nla->kerberosSettings.certSha1, info->sha1Hash, sizeof(nla->kerberosSettings.certSha1)); #ifndef _WIN32 - if (certs[0].pkinitArgs) + if (info->pkinitArgs) { - kerbSettings->pkinitX509Identity = strdup(certs[0].pkinitArgs); + kerbSettings->pkinitX509Identity = _strdup(info->pkinitArgs); if (!kerbSettings->pkinitX509Identity) { WLog_ERR(TAG, "unable to copy pkinitArgs"); @@ -669,8 +672,7 @@ setup_pin: ret = TRUE; out: - for (i = 0; i < count; i++) - smartcardCert_Free(&certs[i]); + smartcardCerts_Free(certs); return ret; } @@ -1995,8 +1997,6 @@ static BOOL nla_encode_ts_credentials(rdpNla* nla) s = Stream_StaticInit(&staticRetStream, (BYTE*)nla->tsCredentials.pvBuffer, length); ber_write_nla_TSCredentials(s, &cr); ret = TRUE; - - printf("creds=%s\n", winpr_BinToHexString((BYTE*)nla->tsCredentials.pvBuffer, length, TRUE)); out: Stream_Free(credsContentStream, TRUE); return ret; diff --git a/libfreerdp/core/smartcardlogon.c b/libfreerdp/core/smartcardlogon.c index 230679049..f393119c8 100644 --- a/libfreerdp/core/smartcardlogon.c +++ b/libfreerdp/core/smartcardlogon.c @@ -29,6 +29,7 @@ #include #include #include +#include #include @@ -36,6 +37,19 @@ #define TAG FREERDP_TAG("smartcardlogon") +typedef struct +{ + SmartcardCertInfo info; + char* certPath; + char* keyPath; +} SmartcardCertInfoPrivate; + +struct sSmartCardCerts +{ + size_t count; + SmartcardCertInfoPrivate* certs; +}; + static BOOL getAtr(LPWSTR readerName, BYTE* atr, DWORD* atrLen) { WCHAR atrName[256]; @@ -77,8 +91,12 @@ out_connect: return ret; } -void smartcardCert_Free(SmartcardCert* scCert) +static void smartcardCertInfo_Free(SmartcardCertInfo* scCert) { + const SmartcardCertInfo empty = { 0 }; + + if (!scCert) + return; free(scCert->reader); crypto_cert_free(scCert->certificate); free(scCert->pkinitArgs); @@ -89,10 +107,62 @@ void smartcardCert_Free(SmartcardCert* scCert) free(scCert->subject); free(scCert->issuer); - ZeroMemory(scCert, sizeof(*scCert)); + *scCert = empty; } -static BOOL treat_sc_cert(SmartcardCert* scCert) +static void delete_file(char* path) +{ + WCHAR* wpath = NULL; + if (!path) + return; + + /* Overwrite data in files before deletion */ + { + FILE* fp = winpr_fopen(path, "r+"); + if (fp) + { + INT64 x, size = 0; + int rs = _fseeki64(fp, 0, SEEK_END); + if (rs == 0) + size = _ftelli64(fp); + _fseeki64(fp, 0, SEEK_SET); + for (x = 0; x < size; x++) + fputc(0, fp); + fclose(fp); + } + } + + ConvertToUnicode(CP_UTF8, 0, path, -1, &wpath, 0); + DeleteFileW(wpath); + free(wpath); + free(path); +} + +static void smartcardCertInfoPrivate_Free(SmartcardCertInfoPrivate* scCert) +{ + const SmartcardCertInfoPrivate empty = { 0 }; + + if (!scCert) + return; + smartcardCertInfo_Free(&scCert->info); + delete_file(scCert->keyPath); + delete_file(scCert->certPath); + *scCert = empty; +} + +void smartcardCerts_Free(SmartcardCerts* scCert) +{ + size_t x; + if (!scCert) + return; + + for (x = 0; x < scCert->count; x++) + smartcardCertInfoPrivate_Free(&scCert->certs[x]); + + free(scCert); +} + +static BOOL treat_sc_cert(SmartcardCertInfo* scCert) { scCert->upn = crypto_cert_get_upn(scCert->certificate->px509); if (scCert->upn) @@ -106,7 +176,7 @@ static BOOL treat_sc_cert(SmartcardCert* scCert) return FALSE; } - userLen = (atPos - scCert->upn); + userLen = (size_t)(atPos - scCert->upn); scCert->userHint = malloc(userLen + 1); scCert->domainHint = strdup(atPos + 1); @@ -126,32 +196,47 @@ static BOOL treat_sc_cert(SmartcardCert* scCert) return TRUE; } +static int allocating_sprintf(char** dst, const char* fmt, ...) +{ + int rc; + va_list ap; + + WINPR_ASSERT(dst); + + va_start(ap, fmt); + rc = vsnprintf(NULL, 0, fmt, ap); + va_end(ap); + + { + char* tmp = realloc(*dst, rc + 1); + if (!tmp) + return -1; + *dst = tmp; + } + va_start(ap, fmt); + rc = vsnprintf(*dst, rc + 1, fmt, ap); + va_end(ap); + return rc; +} + #ifndef _WIN32 -static BOOL build_pkinit_args(const rdpSettings* settings, SmartcardCert* scCert) +static BOOL build_pkinit_args(const rdpSettings* settings, SmartcardCertInfo* scCert) { /* pkinit args only under windows * PKCS11:module_name=opensc-pkcs11.so */ - size_t sz; const char* pkModule = settings->Pkcs11Module ? settings->Pkcs11Module : "opensc-pkcs11.so"; - sz = _snprintf(NULL, 0, "PKCS11:module_name=%s:slotid=%" PRIu16, pkModule, - (UINT16)scCert->slotId) + - 1; - scCert->pkinitArgs = malloc(sz); - if (!scCert->pkinitArgs) + if (allocating_sprintf(&scCert->pkinitArgs, "PKCS11:module_name=%s:slotid=%" PRIu16, pkModule, + (UINT16)scCert->slotId) <= 0) return FALSE; - - _snprintf(scCert->pkinitArgs, sz, "PKCS11:module_name=%s:slotid=%" PRIu16, pkModule, - (UINT16)scCert->slotId); - return TRUE; } #endif /* _WIN32 */ static BOOL smartcard_hw_enumerateCerts(const rdpSettings* settings, LPCWSTR csp, const char* reader, const char* userFilter, - SmartcardCert* scCert, DWORD count, DWORD* retCount) + SmartcardCerts** scCerts, DWORD* retCount) { BOOL ret = FALSE; LPWSTR scope = NULL; @@ -159,6 +244,13 @@ static BOOL smartcard_hw_enumerateCerts(const rdpSettings* settings, LPCWSTR csp NCRYPT_PROV_HANDLE provider; NCryptKeyName* keyName = NULL; SECURITY_STATUS status; + size_t count = 0; + SmartcardCerts* certs = NULL; + + WINPR_ASSERT(settings); + WINPR_ASSERT(csp); + WINPR_ASSERT(scCerts); + WINPR_ASSERT(retCount); if (reader) { @@ -183,33 +275,42 @@ static BOOL smartcard_hw_enumerateCerts(const rdpSettings* settings, LPCWSTR csp goto out; } - *retCount = 0; - while ((*retCount < count) && (status = NCryptEnumKeys(provider, scope, &keyName, &enumState, - NCRYPT_SILENT_FLAG)) == ERROR_SUCCESS) + while ((status = NCryptEnumKeys(provider, scope, &keyName, &enumState, NCRYPT_SILENT_FLAG)) == + ERROR_SUCCESS) { - NCRYPT_KEY_HANDLE phKey; + NCRYPT_KEY_HANDLE phKey = 0; PBYTE certBytes = NULL; DWORD cbOutput; + SmartcardCertInfoPrivate* cert; - if (ConvertFromUnicode(CP_UTF8, 0, keyName->pszName, -1, &scCert->containerName, 0, NULL, + count++; + { + SmartcardCerts* tmp = + realloc(certs, sizeof(SmartcardCerts) + sizeof(SmartcardCertInfoPrivate) * (count)); + if (!tmp) + goto out; + certs = tmp; + certs->count = count; + certs->certs = (SmartcardCertInfoPrivate*)(certs + 1); + } + + cert = &certs->certs[count - 1]; + + if (ConvertFromUnicode(CP_UTF8, 0, keyName->pszName, -1, &cert->info.containerName, 0, NULL, NULL) <= 0) - continue; + goto endofloop; status = NCryptOpenKey(provider, &phKey, keyName->pszName, keyName->dwLegacyKeySpec, keyName->dwFlags); if (status != ERROR_SUCCESS) - { - smartcardCert_Free(scCert); - continue; - } + goto endofloop; #ifndef _WIN32 - status = NCryptGetProperty(phKey, NCRYPT_WINPR_SLOTID, (PBYTE)&scCert->slotId, 4, &cbOutput, - NCRYPT_SILENT_FLAG); + status = NCryptGetProperty(phKey, NCRYPT_WINPR_SLOTID, (PBYTE)&cert->info.slotId, 4, + &cbOutput, NCRYPT_SILENT_FLAG); if (status != ERROR_SUCCESS) { - WLog_ERR(TAG, "unable to retrieve slotId for key %s", scCert->containerName); - smartcardCert_Free(scCert); + WLog_ERR(TAG, "unable to retrieve slotId for key %s", cert->info.containerName); goto endofloop; } #endif /* _WIN32 */ @@ -220,32 +321,28 @@ static BOOL smartcard_hw_enumerateCerts(const rdpSettings* settings, LPCWSTR csp if (status != ERROR_SUCCESS) { WLog_ERR(TAG, "unable to retrieve reader's name length for key %s", - scCert->containerName); - smartcardCert_Free(scCert); + cert->info.containerName); goto endofloop; } - scCert->reader = calloc(1, cbOutput + 2); - if (!scCert->reader) + cert->info.reader = calloc(1, cbOutput + 2); + if (!cert->info.reader) { - WLog_ERR(TAG, "unable to allocate reader's name for key %s", scCert->containerName); - smartcardCert_Free(scCert); + WLog_ERR(TAG, "unable to allocate reader's name for key %s", cert->info.containerName); goto endofloop; } - status = NCryptGetProperty(phKey, NCRYPT_READER_PROPERTY, (PBYTE)scCert->reader, + status = NCryptGetProperty(phKey, NCRYPT_READER_PROPERTY, (PBYTE)cert->info.reader, cbOutput + 2, &cbOutput, NCRYPT_SILENT_FLAG); if (status != ERROR_SUCCESS) { - WLog_ERR(TAG, "unable to retrieve reader's name for key %s", scCert->containerName); - smartcardCert_Free(scCert); + WLog_ERR(TAG, "unable to retrieve reader's name for key %s", cert->info.containerName); goto endofloop; } - if (!getAtr(scCert->reader, scCert->atr, &scCert->atrLength)) + if (!getAtr(cert->info.reader, cert->info.atr, &cert->info.atrLength)) { - WLog_ERR(TAG, "unable to retrieve card ATR for key %s", scCert->containerName); - smartcardCert_Free(scCert); + WLog_ERR(TAG, "unable to retrieve card ATR for key %s", cert->info.containerName); goto endofloop; } @@ -255,7 +352,6 @@ static BOOL smartcard_hw_enumerateCerts(const rdpSettings* settings, LPCWSTR csp if (status != ERROR_SUCCESS) { /* can happen that key don't have certificates */ - smartcardCert_Free(scCert); goto endofloop; } @@ -263,8 +359,7 @@ static BOOL smartcard_hw_enumerateCerts(const rdpSettings* settings, LPCWSTR csp if (!certBytes) { WLog_ERR(TAG, "unable to allocate %d certBytes for key %s", cbOutput, - scCert->containerName); - smartcardCert_Free(scCert); + cert->info.containerName); goto endofloop; } @@ -272,59 +367,50 @@ static BOOL smartcard_hw_enumerateCerts(const rdpSettings* settings, LPCWSTR csp &cbOutput, NCRYPT_SILENT_FLAG); if (status != ERROR_SUCCESS) { - WLog_ERR(TAG, "unable to retrieve certificate for key %s", scCert->containerName); - free(certBytes); - smartcardCert_Free(scCert); + WLog_ERR(TAG, "unable to retrieve certificate for key %s", cert->info.containerName); goto endofloop; } - if (!winpr_Digest(WINPR_MD_SHA1, certBytes, cbOutput, scCert->sha1Hash, - sizeof(scCert->sha1Hash))) + if (!winpr_Digest(WINPR_MD_SHA1, certBytes, cbOutput, cert->info.sha1Hash, + sizeof(cert->info.sha1Hash))) { - WLog_ERR(TAG, "unable to compute certificate sha1 for key %s", scCert->containerName); - free(certBytes); - smartcardCert_Free(scCert); + WLog_ERR(TAG, "unable to compute certificate sha1 for key %s", + cert->info.containerName); goto endofloop; } - scCert->certificate = crypto_cert_read(certBytes, cbOutput); - free(certBytes); + cert->info.certificate = crypto_cert_read(certBytes, cbOutput); - if (!scCert->certificate) + if (!cert->info.certificate) { - WLog_ERR(TAG, "unable to parse X509 certificate for key %s", scCert->containerName); - smartcardCert_Free(scCert); + WLog_ERR(TAG, "unable to parse X509 certificate for key %s", cert->info.containerName); goto endofloop; } - if (!treat_sc_cert(scCert)) - { - smartcardCert_Free(scCert); + if (!treat_sc_cert(&cert->info)) goto endofloop; - } - if (userFilter && scCert->userHint && strcmp(scCert->userHint, userFilter) != 0) + if (userFilter && cert->info.userHint && strcmp(cert->info.userHint, userFilter) != 0) { - smartcardCert_Free(scCert); goto endofloop; } #ifndef _WIN32 - if (!build_pkinit_args(settings, scCert)) + if (!build_pkinit_args(settings, &cert->info)) { WLog_ERR(TAG, "error build pkinit args"); - smartcardCert_Free(scCert); goto endofloop; } #endif - ++*retCount; - scCert++; - endofloop: - NCryptFreeObject((NCRYPT_HANDLE)phKey); + free(certBytes); + if (phKey) + NCryptFreeObject((NCRYPT_HANDLE)phKey); } + *scCerts = certs; + *retCount = (DWORD)certs->count; ret = TRUE; NCryptFreeObject((NCRYPT_HANDLE)provider); @@ -333,64 +419,113 @@ out: return ret; } -static BOOL smartcard_sw_enumerateCerts(const rdpSettings* settings, SmartcardCert* scCert, - DWORD count, DWORD* retCount) +static BOOL write_pem(const char* file, const char* pem) { - size_t sz; - - if (count < 1) + size_t rc, size = strlen(pem) + 1; + FILE* fp = winpr_fopen(file, "w"); + if (!fp) return FALSE; + rc = fwrite(pem, 1, size, fp); + fclose(fp); + return rc == size; +} - if (!settings->SmartcardCertificateFile || !settings->SmartcardPrivateKeyFile) - { - WLog_ERR(TAG, "missing smartcard emulation cert or key"); - return FALSE; - } +static char* create_temporary_file(void) +{ + BYTE buffer[32]; + char* hex; + char* path; - /* compute PKINIT args FILE:, */ - sz = strlen("FILE:") + strlen(settings->SmartcardCertificateFile) + 1 + - strlen(settings->SmartcardPrivateKeyFile) + 1; - scCert->pkinitArgs = malloc(sz); - _snprintf(scCert->pkinitArgs, sz, "FILE:%s,%s", settings->SmartcardCertificateFile, - settings->SmartcardPrivateKeyFile); + winpr_RAND(buffer, sizeof(buffer)); + hex = winpr_BinToHexString(buffer, sizeof(buffer), FALSE); + path = GetKnownSubPath(KNOWN_PATH_TEMP, hex); + free(hex); + return path; +} - scCert->certificate = crypto_cert_pem_read(settings->SmartcardCertificate); - if (!scCert->certificate) +static BOOL smartcard_sw_enumerateCerts(const rdpSettings* settings, SmartcardCerts** scCerts, + DWORD* retCount) +{ + BOOL rc = FALSE; + int res; + SmartcardCerts* certs = NULL; + SmartcardCertInfoPrivate* cert; + const size_t count = 1; + char* keyPath = create_temporary_file(); + char* certPath = create_temporary_file(); + + WINPR_ASSERT(settings); + WINPR_ASSERT(scCerts); + WINPR_ASSERT(retCount); + + certs = calloc(count, sizeof(SmartcardCertInfoPrivate) + sizeof(SmartcardCerts)); + if (!certs) + goto out_error; + + certs->count = count; + cert = certs->certs = (SmartcardCertInfoPrivate*)(certs + 1); + + cert->info.certificate = crypto_cert_pem_read(settings->SmartcardCertificate); + if (!cert->info.certificate) { WLog_ERR(TAG, "unable to read smartcard certificate"); goto out_error; } - if (!treat_sc_cert(scCert)) + if (!treat_sc_cert(&cert->info)) { WLog_ERR(TAG, "unable to treat smartcard certificate"); goto out_error; } - if (ConvertToUnicode(CP_UTF8, 0, "FreeRDP Emulator", -1, &scCert->reader, 0) < 0) + if (ConvertToUnicode(CP_UTF8, 0, "FreeRDP Emulator", -1, &cert->info.reader, 0) < 0) goto out_error; - scCert->containerName = strdup("Private Key 00"); - if (!scCert->containerName) + cert->info.containerName = strdup("Private Key 00"); + if (!cert->info.containerName) goto out_error; - *retCount = 1; - return TRUE; + /* compute PKINIT args FILE:, + * + * We need files for PKINIT to read, so write the certificate to some + * temporary location and use that. + */ + if (!write_pem(keyPath, settings->SmartcardPrivateKey)) + goto out_error; + if (!write_pem(certPath, settings->SmartcardCertificate)) + goto out_error; + res = allocating_sprintf(&cert->info.pkinitArgs, "FILE:%s,%s", certPath, keyPath); + if (res <= 0) + goto out_error; + + cert->certPath = certPath; + cert->keyPath = keyPath; + + rc = TRUE; + *scCerts = certs; + *retCount = (DWORD)certs->count; out_error: - smartcardCert_Free(scCert); - return FALSE; + if (!rc) + smartcardCerts_Free(certs); + return rc; } -BOOL smartcard_enumerateCerts(const rdpSettings* settings, SmartcardCert* scCert, DWORD count, +BOOL smartcard_enumerateCerts(const rdpSettings* settings, SmartcardCerts** scCerts, DWORD* retCount) { BOOL ret; LPWSTR csp; - const char* asciiCsp = settings->CspName ? settings->CspName : MS_SCARD_PROV_A; + const char* asciiCsp; + + WINPR_ASSERT(settings); + WINPR_ASSERT(scCerts); + WINPR_ASSERT(retCount); + + asciiCsp = settings->CspName ? settings->CspName : MS_SCARD_PROV_A; if (settings->SmartcardEmulation) - return smartcard_sw_enumerateCerts(settings, scCert, count, retCount); + return smartcard_sw_enumerateCerts(settings, scCerts, retCount); if (ConvertToUnicode(CP_UTF8, 0, asciiCsp, -1, &csp, 0) <= 0) { @@ -399,7 +534,16 @@ BOOL smartcard_enumerateCerts(const rdpSettings* settings, SmartcardCert* scCert } ret = smartcard_hw_enumerateCerts(settings, csp, settings->ReaderName, settings->Username, - scCert, count, retCount); + scCerts, retCount); free(csp); return ret; } + +const SmartcardCertInfo* smartcard_getCertInfo(SmartcardCerts* scCerts, DWORD index) +{ + WINPR_ASSERT(scCerts); + if (index >= scCerts->count) + return NULL; + + return &scCerts->certs[index].info; +} diff --git a/libfreerdp/core/smartcardlogon.h b/libfreerdp/core/smartcardlogon.h index 0177634f8..a7aaecbdd 100644 --- a/libfreerdp/core/smartcardlogon.h +++ b/libfreerdp/core/smartcardlogon.h @@ -22,7 +22,9 @@ #include #include -struct _SmartcardCert +typedef struct sSmartCardCerts SmartcardCerts; + +typedef struct { LPWSTR reader; CryptoCert certificate; @@ -37,12 +39,12 @@ struct _SmartcardCert BYTE atr[256]; DWORD atrLength; BYTE sha1Hash[20]; -}; -typedef struct _SmartcardCert SmartcardCert; +} SmartcardCertInfo; -FREERDP_API void smartcardCert_Free(SmartcardCert* scCert); +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 BOOL smartcard_enumerateCerts(const rdpSettings* settings, SmartcardCert* scCert, DWORD count, - DWORD* retCount); #endif /* LIBFREERDP_CORE_SMARTCARDLOGON_H */ diff --git a/libfreerdp/core/test/settings_property_lists.h b/libfreerdp/core/test/settings_property_lists.h index f80875655..ac983c885 100644 --- a/libfreerdp/core/test/settings_property_lists.h +++ b/libfreerdp/core/test/settings_property_lists.h @@ -392,10 +392,8 @@ static const size_t string_list_indices[] = { FreeRDP_ServerHostname, FreeRDP_ShellWorkingDirectory, FreeRDP_SmartcardCertificate, - FreeRDP_SmartcardCertificateFile, FreeRDP_SmartcardPin, FreeRDP_SmartcardPrivateKey, - FreeRDP_SmartcardPrivateKeyFile, FreeRDP_TargetNetAddress, FreeRDP_TransportDumpFile, FreeRDP_Username,