smartcard: take in account pkcs11-module in smartcard listing and print pkcs11 errors

This commit is contained in:
David Fort 2022-05-06 08:21:29 +02:00 committed by akallabeth
parent c5bca8bbbb
commit 4ffd3e84b9
2 changed files with 259 additions and 134 deletions

View File

@ -741,6 +741,103 @@ fail:
return FALSE;
}
static BOOL read_pem_file(rdpSettings* settings, size_t id, const char* file)
{
INT64 s;
int rs;
size_t fr;
char* ptr;
BOOL rc = FALSE;
FILE* fp = winpr_fopen(file, "r");
if (!fp)
return FALSE;
rs = _fseeki64(fp, 0, SEEK_END);
if (rs < 0)
goto fail;
s = _ftelli64(fp);
if (s < 0)
goto fail;
rs = _fseeki64(fp, 0, SEEK_SET);
if (rs < 0)
goto fail;
if (!freerdp_settings_set_string_len(settings, id, NULL, s + 1ull))
goto fail;
ptr = freerdp_settings_get_string_writable(settings, id);
fr = fread(ptr, (size_t)s, 1, fp);
if (fr != 1)
goto fail;
rc = TRUE;
fail:
fclose(fp);
return rc;
}
/** @brief suboption type */
typedef enum
{
CMDLINE_SUBOPTION_STRING,
CMDLINE_SUBOPTION_FILE,
} CmdLineSubOptionType;
typedef BOOL (*CmdLineSubOptionCb)(const char* value, rdpSettings* settings);
typedef struct
{
const char* optname;
size_t id;
CmdLineSubOptionType opttype;
CmdLineSubOptionCb cb;
} CmdLineSubOptions;
static BOOL parseSubOptions(rdpSettings* settings, const CmdLineSubOptions* opts, size_t count,
const char* arg)
{
BOOL found = FALSE;
size_t xx;
for (xx = 0; xx < count; xx++)
{
const CmdLineSubOptions* opt = &opts[xx];
size_t optlen = strlen(opt->optname);
if (strncmp(opt->optname, arg, optlen) == 0)
{
const char* val = &arg[optlen];
BOOL status;
switch (opt->opttype)
{
case CMDLINE_SUBOPTION_STRING:
status = freerdp_settings_set_string(settings, opt->id, val);
break;
case CMDLINE_SUBOPTION_FILE:
status = read_pem_file(settings, opt->id, val);
break;
default:
WLog_ERR(TAG, "invalid subOption type");
return FALSE;
}
if (!status)
return FALSE;
if (opt->cb && !opt->cb(val, settings))
return FALSE;
found = TRUE;
break;
}
}
if (!found)
WLog_ERR(TAG, "option %s not handled", arg);
return found;
}
static int freerdp_client_command_line_post_filter(void* context, COMMAND_LINE_ARGUMENT_A* arg)
{
rdpSettings* settings = (rdpSettings*)context;
@ -764,6 +861,43 @@ static int freerdp_client_command_line_post_filter(void* context, COMMAND_LINE_A
free(ptr.p);
}
CommandLineSwitchCase(arg, "kerberos")
{
size_t count;
union
{
char** p;
const char** pc;
} ptr;
ptr.p = CommandLineParseCommaSeparatedValuesEx("kerberos", arg->Value, &count);
if (ptr.pc)
{
size_t x;
const CmdLineSubOptions opts[] = {
{ "start-time:", FreeRDP_KerberosStartTime, CMDLINE_SUBOPTION_STRING, NULL },
{ "lifetime:", FreeRDP_KerberosLifeTime, CMDLINE_SUBOPTION_STRING, NULL },
{ "renewable-lifetime:", FreeRDP_KerberosRenewableLifeTime,
CMDLINE_SUBOPTION_STRING, NULL },
{ "cache:", FreeRDP_KerberosCache, CMDLINE_SUBOPTION_STRING, NULL },
{ "armor:", FreeRDP_KerberosArmor, CMDLINE_SUBOPTION_STRING, NULL },
{ "pkinit-anchors:", FreeRDP_PkinitAnchors, CMDLINE_SUBOPTION_STRING, NULL },
{ "pkcs11-module:", FreeRDP_Pkcs11Module, CMDLINE_SUBOPTION_STRING, NULL }
};
for (x = 1; x < count; x++)
{
const char* cur = ptr.pc[x];
if (!parseSubOptions(settings, opts, ARRAYSIZE(opts), cur))
{
free(ptr.p);
return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
}
}
}
free(ptr.p);
}
CommandLineSwitchCase(arg, "vc")
{
size_t count;
@ -1469,99 +1603,9 @@ static BOOL prepare_default_settings(rdpSettings* settings, COMMAND_LINE_ARGUMEN
return freerdp_set_connection_type(settings, CONNECTION_TYPE_AUTODETECT);
}
static BOOL read_pem_file(rdpSettings* settings, size_t id, const char* file)
{
INT64 s;
int rs;
size_t fr;
char* ptr;
BOOL rc = FALSE;
FILE* fp = winpr_fopen(file, "r");
if (!fp)
return FALSE;
rs = _fseeki64(fp, 0, SEEK_END);
if (rs < 0)
goto fail;
s = _ftelli64(fp);
if (s < 0)
goto fail;
rs = _fseeki64(fp, 0, SEEK_SET);
if (rs < 0)
goto fail;
if (!freerdp_settings_set_string_len(settings, id, NULL, s + 1ull))
goto fail;
ptr = freerdp_settings_get_string_writable(settings, id);
fr = fread(ptr, (size_t)s, 1, fp);
if (fr != 1)
goto fail;
rc = TRUE;
fail:
fclose(fp);
return rc;
}
typedef enum
{
CMDLINE_SUBOPTION_STRING,
CMDLINE_SUBOPTION_FILE,
} CmdLineSubOptionType;
typedef BOOL (*CmdLineSubOptionCb)(const char* value, rdpSettings* settings);
typedef struct
{
const char* optname;
size_t id;
CmdLineSubOptionType opttype;
CmdLineSubOptionCb cb;
} CmdLineSubOptions;
static BOOL parseSubOptions(rdpSettings* settings, const CmdLineSubOptions* opts, size_t count,
const char* arg)
{
BOOL found = FALSE;
size_t xx;
for (xx = 0; xx < count; xx++)
{
const CmdLineSubOptions* opt = &opts[xx];
size_t optlen = strlen(opt->optname);
if (strncmp(opt->optname, arg, optlen) == 0)
{
const char* val = &arg[optlen];
BOOL status;
switch (opt->opttype)
{
case CMDLINE_SUBOPTION_STRING:
status = freerdp_settings_set_string(settings, opt->id, val);
break;
case CMDLINE_SUBOPTION_FILE:
status = read_pem_file(settings, opt->id, val);
break;
default:
WLog_ERR(TAG, "invalid subOption type");
return FALSE;
}
if (!status)
return FALSE;
if (opt->cb && !opt->cb(val, settings))
return FALSE;
found = TRUE;
break;
}
}
if (!found)
WLog_ERR(TAG, "option %s not handled", arg);
return found;
}
static BOOL setSmartcardEmulation(const char* value, rdpSettings* settings)
{
@ -3240,42 +3284,6 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
}
}
CommandLineSwitchCase(arg, "kerberos")
{
size_t count;
union
{
char** p;
const char** pc;
} ptr;
ptr.p = CommandLineParseCommaSeparatedValuesEx("kerberos", arg->Value, &count);
if (ptr.pc)
{
size_t x;
const CmdLineSubOptions opts[] = {
{ "start-time:", FreeRDP_KerberosStartTime, CMDLINE_SUBOPTION_STRING, NULL },
{ "lifetime:", FreeRDP_KerberosLifeTime, CMDLINE_SUBOPTION_STRING, NULL },
{ "renewable-lifetime:", FreeRDP_KerberosRenewableLifeTime,
CMDLINE_SUBOPTION_STRING, NULL },
{ "cache:", FreeRDP_KerberosCache, CMDLINE_SUBOPTION_STRING, NULL },
{ "armor:", FreeRDP_KerberosArmor, CMDLINE_SUBOPTION_STRING, NULL },
{ "pkinit-anchors:", FreeRDP_PkinitAnchors, CMDLINE_SUBOPTION_STRING, NULL },
{ "pkcs11-module:", FreeRDP_Pkcs11Module, CMDLINE_SUBOPTION_STRING, NULL }
};
for (x = 1; x < count; x++)
{
const char* cur = ptr.pc[x];
if (!parseSubOptions(settings, opts, ARRAYSIZE(opts), cur))
{
free(ptr.p);
return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
}
}
}
free(ptr.p);
}
CommandLineSwitchCase(arg, "action-script")
{
if (!freerdp_settings_set_string(settings, FreeRDP_ActionScript, arg->Value))

View File

@ -16,6 +16,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WITH_PKCS11
#define WITH_PKCS11
#endif
#include <stdlib.h>
@ -216,6 +219,105 @@ static CK_RV object_load_attributes(NCryptP11ProviderHandle* provider, CK_SESSIO
return rv;
}
static const char* CK_RV_error_string(CK_RV rv)
{
static char generic_buffer[200];
#define ERR_ENTRY(X) case X: return #X
switch (rv)
{
ERR_ENTRY(CKR_OK);
ERR_ENTRY(CKR_CANCEL);
ERR_ENTRY(CKR_HOST_MEMORY);
ERR_ENTRY(CKR_SLOT_ID_INVALID);
ERR_ENTRY(CKR_GENERAL_ERROR);
ERR_ENTRY(CKR_FUNCTION_FAILED);
ERR_ENTRY(CKR_ARGUMENTS_BAD);
ERR_ENTRY(CKR_NO_EVENT);
ERR_ENTRY(CKR_NEED_TO_CREATE_THREADS);
ERR_ENTRY(CKR_CANT_LOCK);
ERR_ENTRY(CKR_ATTRIBUTE_READ_ONLY);
ERR_ENTRY(CKR_ATTRIBUTE_SENSITIVE);
ERR_ENTRY(CKR_ATTRIBUTE_TYPE_INVALID);
ERR_ENTRY(CKR_ATTRIBUTE_VALUE_INVALID);
ERR_ENTRY(CKR_DATA_INVALID);
ERR_ENTRY(CKR_DATA_LEN_RANGE);
ERR_ENTRY(CKR_DEVICE_ERROR);
ERR_ENTRY(CKR_DEVICE_MEMORY);
ERR_ENTRY(CKR_DEVICE_REMOVED);
ERR_ENTRY(CKR_ENCRYPTED_DATA_INVALID);
ERR_ENTRY(CKR_ENCRYPTED_DATA_LEN_RANGE);
ERR_ENTRY(CKR_FUNCTION_CANCELED);
ERR_ENTRY(CKR_FUNCTION_NOT_PARALLEL);
ERR_ENTRY(CKR_FUNCTION_NOT_SUPPORTED);
ERR_ENTRY(CKR_KEY_HANDLE_INVALID);
ERR_ENTRY(CKR_KEY_SIZE_RANGE);
ERR_ENTRY(CKR_KEY_TYPE_INCONSISTENT);
ERR_ENTRY(CKR_KEY_NOT_NEEDED);
ERR_ENTRY(CKR_KEY_CHANGED);
ERR_ENTRY(CKR_KEY_NEEDED);
ERR_ENTRY(CKR_KEY_INDIGESTIBLE);
ERR_ENTRY(CKR_KEY_FUNCTION_NOT_PERMITTED);
ERR_ENTRY(CKR_KEY_NOT_WRAPPABLE);
ERR_ENTRY(CKR_KEY_UNEXTRACTABLE);
ERR_ENTRY(CKR_MECHANISM_INVALID);
ERR_ENTRY(CKR_MECHANISM_PARAM_INVALID);
ERR_ENTRY(CKR_OBJECT_HANDLE_INVALID);
ERR_ENTRY(CKR_OPERATION_ACTIVE);
ERR_ENTRY(CKR_OPERATION_NOT_INITIALIZED);
ERR_ENTRY(CKR_PIN_INCORRECT);
ERR_ENTRY(CKR_PIN_INVALID);
ERR_ENTRY(CKR_PIN_LEN_RANGE);
ERR_ENTRY(CKR_PIN_EXPIRED);
ERR_ENTRY(CKR_PIN_LOCKED);
ERR_ENTRY(CKR_SESSION_CLOSED);
ERR_ENTRY(CKR_SESSION_COUNT);
ERR_ENTRY(CKR_SESSION_HANDLE_INVALID);
ERR_ENTRY(CKR_SESSION_PARALLEL_NOT_SUPPORTED);
ERR_ENTRY(CKR_SESSION_READ_ONLY);
ERR_ENTRY(CKR_SESSION_EXISTS);
ERR_ENTRY(CKR_SESSION_READ_ONLY_EXISTS);
ERR_ENTRY(CKR_SESSION_READ_WRITE_SO_EXISTS);
ERR_ENTRY(CKR_SIGNATURE_INVALID);
ERR_ENTRY(CKR_SIGNATURE_LEN_RANGE);
ERR_ENTRY(CKR_TEMPLATE_INCOMPLETE);
ERR_ENTRY(CKR_TEMPLATE_INCONSISTENT);
ERR_ENTRY(CKR_TOKEN_NOT_PRESENT);
ERR_ENTRY(CKR_TOKEN_NOT_RECOGNIZED);
ERR_ENTRY(CKR_TOKEN_WRITE_PROTECTED);
ERR_ENTRY(CKR_UNWRAPPING_KEY_HANDLE_INVALID);
ERR_ENTRY(CKR_UNWRAPPING_KEY_SIZE_RANGE);
ERR_ENTRY(CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT);
ERR_ENTRY(CKR_USER_ALREADY_LOGGED_IN);
ERR_ENTRY(CKR_USER_NOT_LOGGED_IN);
ERR_ENTRY(CKR_USER_PIN_NOT_INITIALIZED);
ERR_ENTRY(CKR_USER_TYPE_INVALID);
ERR_ENTRY(CKR_USER_ANOTHER_ALREADY_LOGGED_IN);
ERR_ENTRY(CKR_USER_TOO_MANY_TYPES);
ERR_ENTRY(CKR_WRAPPED_KEY_INVALID);
ERR_ENTRY(CKR_WRAPPED_KEY_LEN_RANGE);
ERR_ENTRY(CKR_WRAPPING_KEY_HANDLE_INVALID);
ERR_ENTRY(CKR_WRAPPING_KEY_SIZE_RANGE);
ERR_ENTRY(CKR_WRAPPING_KEY_TYPE_INCONSISTENT);
ERR_ENTRY(CKR_RANDOM_SEED_NOT_SUPPORTED);
ERR_ENTRY(CKR_RANDOM_NO_RNG);
ERR_ENTRY(CKR_DOMAIN_PARAMS_INVALID);
ERR_ENTRY(CKR_BUFFER_TOO_SMALL);
ERR_ENTRY(CKR_SAVED_STATE_INVALID);
ERR_ENTRY(CKR_INFORMATION_SENSITIVE);
ERR_ENTRY(CKR_STATE_UNSAVEABLE);
ERR_ENTRY(CKR_CRYPTOKI_NOT_INITIALIZED);
ERR_ENTRY(CKR_CRYPTOKI_ALREADY_INITIALIZED);
ERR_ENTRY(CKR_MUTEX_BAD);
ERR_ENTRY(CKR_MUTEX_NOT_LOCKED);
ERR_ENTRY(CKR_FUNCTION_REJECTED);
default:
snprintf(generic_buffer, sizeof(generic_buffer), "unknown 0x%lx", rv);
return generic_buffer;
}
#undef ERR_ENTRY
}
static SECURITY_STATUS collect_private_keys(NCryptP11ProviderHandle* provider,
P11EnumKeysState* state)
{
@ -244,12 +346,24 @@ static SECURITY_STATUS collect_private_keys(NCryptP11ProviderHandle* provider,
continue;
}
fix_padded_string((char *)slotInfo.slotDescription, sizeof(slotInfo.slotDescription));
WLog_DBG(TAG, "%s: collecting private keys for slot #%d(%lu) descr='%s' flags=0x%x", __FUNCTION__, i,
state->slots[i], slotInfo.slotDescription, slotInfo.flags);
/* this is a safety guard as we're supposed to have listed only readers with tokens in them */
if (!(slotInfo.flags & CKF_TOKEN_PRESENT))
{
WLog_ERR(TAG, "token not present for slot #%d(%d)", i, state->slots[i]);
continue;
}
WINPR_ASSERT(p11->C_OpenSession);
rv = p11->C_OpenSession(state->slots[i], CKF_SERIAL_SESSION, NULL, NULL, &session);
if (rv != CKR_OK)
{
// TODO: shall it be fatal ?
WLog_ERR(TAG, "unable to openSession for slot #%d(%d)", i, state->slots[i]);
WLog_ERR(TAG, "unable to openSession for slot #%d(%d), rv=%s", i, state->slots[i],
CK_RV_error_string(rv));
continue;
}
@ -258,7 +372,8 @@ static SECURITY_STATUS collect_private_keys(NCryptP11ProviderHandle* provider,
if (rv != CKR_OK)
{
// TODO: shall it be fatal ?
WLog_ERR(TAG, "unable to initiate search for slot #%d(%d)", i, state->slots[i]);
WLog_ERR(TAG, "unable to initiate search for slot #%d(%d), rv=%s", i, state->slots[i],
CK_RV_error_string(rv));
step = "C_FindObjectsInit";
goto cleanup_FindObjectsInit;
}
@ -267,11 +382,13 @@ static SECURITY_STATUS collect_private_keys(NCryptP11ProviderHandle* provider,
rv = p11->C_FindObjects(session, &slotObjects[0], ARRAYSIZE(slotObjects), &nslotObjects);
if (rv != CKR_OK)
{
WLog_ERR(TAG, "unable to findObjects for slot #%d(%d)", i, state->slots[i]);
WLog_ERR(TAG, "unable to findObjects for slot #%d(%d), rv=%s", i, state->slots[i],
CK_RV_error_string(rv));
step = "C_FindObjects";
goto cleanup_FindObjects;
}
WLog_DBG(TAG, "%s: slot has %d objects", __FUNCTION__, nslotObjects);
for (j = 0; j < nslotObjects; j++)
{
NCryptPrivateKeyEnum* privKey = &state->privateKeys[state->nprivateKeys];
@ -287,7 +404,7 @@ static SECURITY_STATUS collect_private_keys(NCryptP11ProviderHandle* provider,
ARRAYSIZE(key_or_certAttrs));
if (rv != CKR_OK)
{
WLog_ERR(TAG, "error getting attributes");
WLog_ERR(TAG, "error getting attributes, rv=%s", CK_RV_error_string(rv));
continue;
}
@ -302,16 +419,16 @@ static SECURITY_STATUS collect_private_keys(NCryptP11ProviderHandle* provider,
rv = p11->C_FindObjectsFinal(session);
if (rv != CKR_OK)
{
WLog_ERR(TAG, "error during C_FindObjectsFinal for slot #%d(%d) (errorStep=%s)", i,
state->slots[i], step);
WLog_ERR(TAG, "error during C_FindObjectsFinal for slot #%d(%d) (errorStep=%s), rv=%s", i,
state->slots[i], step, CK_RV_error_string(rv));
}
cleanup_FindObjectsInit:
WINPR_ASSERT(p11->C_CloseSession);
rv = p11->C_CloseSession(session);
if (rv != CKR_OK)
{
WLog_ERR(TAG, "error closing session for slot #%d(%d) (errorStep=%s)", i,
state->slots[i], step);
WLog_ERR(TAG, "error closing session for slot #%d(%d) (errorStep=%s), rv=%s", i,
state->slots[i], step, CK_RV_error_string(rv));
}
}