22#include <winpr/library.h>
23#include <winpr/assert.h>
24#include <winpr/spec.h>
25#include <winpr/smartcard.h>
26#include <winpr/asn1.h>
33#include "pkcs11-headers/pkcs11.h"
35#define TAG WINPR_TAG("ncryptp11")
39#define MAX_KEYS_PER_SLOT 64
47 CK_FUNCTION_LIST_PTR p11;
49} NCryptP11ProviderHandle;
55 NCryptP11ProviderHandle* provider;
57 CK_BYTE keyCertId[64];
58 CK_ULONG keyCertIdLen;
66 CK_CHAR keyLabel[256];
74 CK_SLOT_ID slots[MAX_SLOTS];
76 NCryptKeyEnum keys[MAX_KEYS];
85static const piv_cert_tags_t piv_cert_tags[] = {
86 {
"X.509 Certificate for PIV Authentication", { 0x5F, 0xC1, 0x05 } },
87 {
"X.509 Certificate for Digital Signature", { 0x5F, 0xC1, 0x0A } },
88 {
"X.509 Certificate for Key Management", { 0x5F, 0xC1, 0x0B } },
89 {
"X.509 Certificate for Card Authentication", { 0x5F, 0xC1, 0x01 } },
91 {
"Certificate for PIV Authentication", { 0x5F, 0xC1, 0x05 } },
92 {
"Certificate for Digital Signature", { 0x5F, 0xC1, 0x0A } },
93 {
"Certificate for Key Management", { 0x5F, 0xC1, 0x0B } },
94 {
"Certificate for Card Authentication", { 0x5F, 0xC1, 0x01 } },
96 {
"Retired Certificate for Key Management 1", { 0x5F, 0xC1, 0x0D } },
97 {
"Retired Certificate for Key Management 2", { 0x5F, 0xC1, 0x0E } },
98 {
"Retired Certificate for Key Management 3", { 0x5F, 0xC1, 0x0F } },
99 {
"Retired Certificate for Key Management 4", { 0x5F, 0xC1, 0x10 } },
100 {
"Retired Certificate for Key Management 5", { 0x5F, 0xC1, 0x11 } },
101 {
"Retired Certificate for Key Management 6", { 0x5F, 0xC1, 0x12 } },
102 {
"Retired Certificate for Key Management 7", { 0x5F, 0xC1, 0x13 } },
103 {
"Retired Certificate for Key Management 8", { 0x5F, 0xC1, 0x14 } },
104 {
"Retired Certificate for Key Management 9", { 0x5F, 0xC1, 0x15 } },
105 {
"Retired Certificate for Key Management 10", { 0x5F, 0xC1, 0x16 } },
106 {
"Retired Certificate for Key Management 11", { 0x5F, 0xC1, 0x17 } },
107 {
"Retired Certificate for Key Management 12", { 0x5F, 0xC1, 0x18 } },
108 {
"Retired Certificate for Key Management 13", { 0x5F, 0xC1, 0x19 } },
109 {
"Retired Certificate for Key Management 14", { 0x5F, 0xC1, 0x1A } },
110 {
"Retired Certificate for Key Management 15", { 0x5F, 0xC1, 0x1B } },
111 {
"Retired Certificate for Key Management 16", { 0x5F, 0xC1, 0x1C } },
112 {
"Retired Certificate for Key Management 17", { 0x5F, 0xC1, 0x1D } },
113 {
"Retired Certificate for Key Management 18", { 0x5F, 0xC1, 0x1E } },
114 {
"Retired Certificate for Key Management 19", { 0x5F, 0xC1, 0x1F } },
115 {
"Retired Certificate for Key Management 20", { 0x5F, 0xC1, 0x20 } },
118static const BYTE APDU_PIV_SELECT_AID[] = { 0x00, 0xA4, 0x04, 0x00, 0x09, 0xA0, 0x00, 0x00,
119 0x03, 0x08, 0x00, 0x00, 0x10, 0x00, 0x00 };
120static const BYTE APDU_PIV_GET_CHUID[] = { 0x00, 0xCB, 0x3F, 0xFF, 0x05, 0x5C,
121 0x03, 0x5F, 0xC1, 0x02, 0x00 };
122static const BYTE APDU_PIV_GET_MSCMAP[] = { 0x00, 0xCB, 0x3F, 0xFF, 0x05, 0x5C,
123 0x03, 0x5F, 0xFF, 0x10, 0x00 };
124static const BYTE APDU_GET_RESPONSE[] = { 0x00, 0xC0, 0x00, 0x00, 0x00 };
126#define PIV_CONTAINER_NAME_LEN 36
127#define MAX_CONTAINER_NAME_LEN 39
128#define MSCMAP_RECORD_SIZE 107
129#define MSCMAP_SLOT_OFFSET 80
138static const piv_tag_to_slot_t piv_tag_to_slot[] = {
139 { { 0x5F, 0xC1, 0x05 }, 0x9A },
140 { { 0x5F, 0xC1, 0x0A }, 0x9C },
141 { { 0x5F, 0xC1, 0x0B }, 0x9D },
142 { { 0x5F, 0xC1, 0x01 }, 0x9E },
143 { { 0x5F, 0xC1, 0x0D }, 0x82 },
144 { { 0x5F, 0xC1, 0x0E }, 0x83 },
145 { { 0x5F, 0xC1, 0x0F }, 0x84 },
146 { { 0x5F, 0xC1, 0x10 }, 0x85 },
147 { { 0x5F, 0xC1, 0x11 }, 0x86 },
148 { { 0x5F, 0xC1, 0x12 }, 0x87 },
149 { { 0x5F, 0xC1, 0x13 }, 0x88 },
150 { { 0x5F, 0xC1, 0x14 }, 0x89 },
151 { { 0x5F, 0xC1, 0x15 }, 0x8A },
152 { { 0x5F, 0xC1, 0x16 }, 0x8B },
153 { { 0x5F, 0xC1, 0x17 }, 0x8C },
154 { { 0x5F, 0xC1, 0x18 }, 0x8D },
155 { { 0x5F, 0xC1, 0x19 }, 0x8E },
156 { { 0x5F, 0xC1, 0x1A }, 0x8F },
157 { { 0x5F, 0xC1, 0x1B }, 0x90 },
158 { { 0x5F, 0xC1, 0x1C }, 0x91 },
159 { { 0x5F, 0xC1, 0x1D }, 0x92 },
160 { { 0x5F, 0xC1, 0x1E }, 0x93 },
161 { { 0x5F, 0xC1, 0x1F }, 0x94 },
162 { { 0x5F, 0xC1, 0x20 }, 0x95 },
165static CK_OBJECT_CLASS object_class_public_key = CKO_PUBLIC_KEY;
166static CK_BBOOL object_verify = CK_TRUE;
168static CK_ATTRIBUTE public_key_filter[] = { { CKA_CLASS, &object_class_public_key,
169 sizeof(object_class_public_key) },
170 { CKA_VERIFY, &object_verify,
sizeof(object_verify) } };
173static const char* CK_RV_error_string(CK_RV rv);
176static SECURITY_STATUS NCryptP11StorageProvider_dtor(NCRYPT_HANDLE handle)
178 NCryptP11ProviderHandle* provider = (NCryptP11ProviderHandle*)handle;
183 if (provider->p11 && provider->p11->C_Finalize)
184 rv = provider->p11->C_Finalize(
nullptr);
186 WLog_WARN(TAG,
"C_Finalize failed with %s [0x%08lx]", CK_RV_error_string(rv), rv);
188 free(provider->modulePath);
190 if (provider->library)
191 FreeLibrary(provider->library);
194 return winpr_NCryptDefault_dtor(handle);
197static void fix_padded_string(
char* str,
size_t maxlen)
203 char* ptr = &str[maxlen - 1];
205 while ((ptr > str) && (*ptr ==
' '))
213static BOOL attributes_have_unallocated_buffers(CK_ATTRIBUTE_PTR attributes, CK_ULONG count)
215 for (CK_ULONG i = 0; i < count; i++)
217 if (!attributes[i].pValue && (attributes[i].ulValueLen != CK_UNAVAILABLE_INFORMATION))
225static BOOL attribute_allocate_attribute_array(CK_ATTRIBUTE_PTR attribute)
227 WINPR_ASSERT(attribute);
228 attribute->pValue = calloc(attribute->ulValueLen,
sizeof(
void*));
229 return !!attribute->pValue;
233static BOOL attribute_allocate_ulong_array(CK_ATTRIBUTE_PTR attribute)
235 attribute->pValue = calloc(attribute->ulValueLen,
sizeof(CK_ULONG));
236 return !!attribute->pValue;
240static BOOL attribute_allocate_buffer(CK_ATTRIBUTE_PTR attribute)
242 attribute->pValue = calloc(attribute->ulValueLen, 1);
243 return !!attribute->pValue;
247static BOOL attributes_allocate_buffers(CK_ATTRIBUTE_PTR attributes, CK_ULONG count)
251 for (CK_ULONG i = 0; i < count; i++)
253 if (attributes[i].pValue || (attributes[i].ulValueLen == CK_UNAVAILABLE_INFORMATION))
256 switch (attributes[i].type)
258 case CKA_WRAP_TEMPLATE:
259 case CKA_UNWRAP_TEMPLATE:
260 ret &= attribute_allocate_attribute_array(&attributes[i]);
263 case CKA_ALLOWED_MECHANISMS:
264 ret &= attribute_allocate_ulong_array(&attributes[i]);
268 ret &= attribute_allocate_buffer(&attributes[i]);
277static CK_RV object_load_attributes(NCryptP11ProviderHandle* provider, CK_SESSION_HANDLE session,
278 CK_OBJECT_HANDLE
object, CK_ATTRIBUTE_PTR attributes,
281 WINPR_ASSERT(provider);
282 WINPR_ASSERT(provider->p11);
283 WINPR_ASSERT(provider->p11->C_GetAttributeValue);
285 CK_RV rv = provider->p11->C_GetAttributeValue(session,
object, attributes, count);
290 if (!attributes_have_unallocated_buffers(attributes, count))
294 case CKR_ATTRIBUTE_SENSITIVE:
295 case CKR_ATTRIBUTE_TYPE_INVALID:
296 case CKR_BUFFER_TOO_SMALL:
298 if (!attributes_allocate_buffers(attributes, count))
299 return CKR_HOST_MEMORY;
301 rv = provider->p11->C_GetAttributeValue(session,
object, attributes, count);
303 WLog_WARN(TAG,
"C_GetAttributeValue failed with %s [0x%08lx]",
304 CK_RV_error_string(rv), rv);
307 WLog_WARN(TAG,
"C_GetAttributeValue failed with %s [0x%08lx]", CK_RV_error_string(rv),
314 case CKR_ATTRIBUTE_SENSITIVE:
315 case CKR_ATTRIBUTE_TYPE_INVALID:
316 case CKR_BUFFER_TOO_SMALL:
318 "C_GetAttributeValue failed with %s [0x%08lx] even after buffer allocation",
319 CK_RV_error_string(rv), rv);
328static const char* CK_RV_error_string(CK_RV rv)
330 static char generic_buffer[200];
331#define ERR_ENTRY(X) \
338 ERR_ENTRY(CKR_CANCEL);
339 ERR_ENTRY(CKR_HOST_MEMORY);
340 ERR_ENTRY(CKR_SLOT_ID_INVALID);
341 ERR_ENTRY(CKR_GENERAL_ERROR);
342 ERR_ENTRY(CKR_FUNCTION_FAILED);
343 ERR_ENTRY(CKR_ARGUMENTS_BAD);
344 ERR_ENTRY(CKR_NO_EVENT);
345 ERR_ENTRY(CKR_NEED_TO_CREATE_THREADS);
346 ERR_ENTRY(CKR_CANT_LOCK);
347 ERR_ENTRY(CKR_ATTRIBUTE_READ_ONLY);
348 ERR_ENTRY(CKR_ATTRIBUTE_SENSITIVE);
349 ERR_ENTRY(CKR_ATTRIBUTE_TYPE_INVALID);
350 ERR_ENTRY(CKR_ATTRIBUTE_VALUE_INVALID);
351 ERR_ENTRY(CKR_DATA_INVALID);
352 ERR_ENTRY(CKR_DATA_LEN_RANGE);
353 ERR_ENTRY(CKR_DEVICE_ERROR);
354 ERR_ENTRY(CKR_DEVICE_MEMORY);
355 ERR_ENTRY(CKR_DEVICE_REMOVED);
356 ERR_ENTRY(CKR_ENCRYPTED_DATA_INVALID);
357 ERR_ENTRY(CKR_ENCRYPTED_DATA_LEN_RANGE);
358 ERR_ENTRY(CKR_FUNCTION_CANCELED);
359 ERR_ENTRY(CKR_FUNCTION_NOT_PARALLEL);
360 ERR_ENTRY(CKR_FUNCTION_NOT_SUPPORTED);
361 ERR_ENTRY(CKR_KEY_HANDLE_INVALID);
362 ERR_ENTRY(CKR_KEY_SIZE_RANGE);
363 ERR_ENTRY(CKR_KEY_TYPE_INCONSISTENT);
364 ERR_ENTRY(CKR_KEY_NOT_NEEDED);
365 ERR_ENTRY(CKR_KEY_CHANGED);
366 ERR_ENTRY(CKR_KEY_NEEDED);
367 ERR_ENTRY(CKR_KEY_INDIGESTIBLE);
368 ERR_ENTRY(CKR_KEY_FUNCTION_NOT_PERMITTED);
369 ERR_ENTRY(CKR_KEY_NOT_WRAPPABLE);
370 ERR_ENTRY(CKR_KEY_UNEXTRACTABLE);
371 ERR_ENTRY(CKR_MECHANISM_INVALID);
372 ERR_ENTRY(CKR_MECHANISM_PARAM_INVALID);
373 ERR_ENTRY(CKR_OBJECT_HANDLE_INVALID);
374 ERR_ENTRY(CKR_OPERATION_ACTIVE);
375 ERR_ENTRY(CKR_OPERATION_NOT_INITIALIZED);
376 ERR_ENTRY(CKR_PIN_INCORRECT);
377 ERR_ENTRY(CKR_PIN_INVALID);
378 ERR_ENTRY(CKR_PIN_LEN_RANGE);
379 ERR_ENTRY(CKR_PIN_EXPIRED);
380 ERR_ENTRY(CKR_PIN_LOCKED);
381 ERR_ENTRY(CKR_SESSION_CLOSED);
382 ERR_ENTRY(CKR_SESSION_COUNT);
383 ERR_ENTRY(CKR_SESSION_HANDLE_INVALID);
384 ERR_ENTRY(CKR_SESSION_PARALLEL_NOT_SUPPORTED);
385 ERR_ENTRY(CKR_SESSION_READ_ONLY);
386 ERR_ENTRY(CKR_SESSION_EXISTS);
387 ERR_ENTRY(CKR_SESSION_READ_ONLY_EXISTS);
388 ERR_ENTRY(CKR_SESSION_READ_WRITE_SO_EXISTS);
389 ERR_ENTRY(CKR_SIGNATURE_INVALID);
390 ERR_ENTRY(CKR_SIGNATURE_LEN_RANGE);
391 ERR_ENTRY(CKR_TEMPLATE_INCOMPLETE);
392 ERR_ENTRY(CKR_TEMPLATE_INCONSISTENT);
393 ERR_ENTRY(CKR_TOKEN_NOT_PRESENT);
394 ERR_ENTRY(CKR_TOKEN_NOT_RECOGNIZED);
395 ERR_ENTRY(CKR_TOKEN_WRITE_PROTECTED);
396 ERR_ENTRY(CKR_UNWRAPPING_KEY_HANDLE_INVALID);
397 ERR_ENTRY(CKR_UNWRAPPING_KEY_SIZE_RANGE);
398 ERR_ENTRY(CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT);
399 ERR_ENTRY(CKR_USER_ALREADY_LOGGED_IN);
400 ERR_ENTRY(CKR_USER_NOT_LOGGED_IN);
401 ERR_ENTRY(CKR_USER_PIN_NOT_INITIALIZED);
402 ERR_ENTRY(CKR_USER_TYPE_INVALID);
403 ERR_ENTRY(CKR_USER_ANOTHER_ALREADY_LOGGED_IN);
404 ERR_ENTRY(CKR_USER_TOO_MANY_TYPES);
405 ERR_ENTRY(CKR_WRAPPED_KEY_INVALID);
406 ERR_ENTRY(CKR_WRAPPED_KEY_LEN_RANGE);
407 ERR_ENTRY(CKR_WRAPPING_KEY_HANDLE_INVALID);
408 ERR_ENTRY(CKR_WRAPPING_KEY_SIZE_RANGE);
409 ERR_ENTRY(CKR_WRAPPING_KEY_TYPE_INCONSISTENT);
410 ERR_ENTRY(CKR_RANDOM_SEED_NOT_SUPPORTED);
411 ERR_ENTRY(CKR_RANDOM_NO_RNG);
412 ERR_ENTRY(CKR_DOMAIN_PARAMS_INVALID);
413 ERR_ENTRY(CKR_BUFFER_TOO_SMALL);
414 ERR_ENTRY(CKR_SAVED_STATE_INVALID);
415 ERR_ENTRY(CKR_INFORMATION_SENSITIVE);
416 ERR_ENTRY(CKR_STATE_UNSAVEABLE);
417 ERR_ENTRY(CKR_CRYPTOKI_NOT_INITIALIZED);
418 ERR_ENTRY(CKR_CRYPTOKI_ALREADY_INITIALIZED);
419 ERR_ENTRY(CKR_MUTEX_BAD);
420 ERR_ENTRY(CKR_MUTEX_NOT_LOCKED);
421 ERR_ENTRY(CKR_FUNCTION_REJECTED);
423 (void)snprintf(generic_buffer,
sizeof(generic_buffer),
"unknown 0x%lx", rv);
424 return generic_buffer;
429#define loge(tag, msg, rv, index, slot) \
430 log_((tag), (msg), (rv), (index), (slot), __FILE__, __func__, __LINE__)
431static void log_(
const char* tag,
const char* msg, CK_RV rv, CK_ULONG index, CK_SLOT_ID slot,
432 const char* file,
const char* fkt,
size_t line)
434 const DWORD log_level = WLOG_ERROR;
435 static wLog* log_cached_ptr =
nullptr;
437 log_cached_ptr = WLog_Get(tag);
438 if (!WLog_IsLevelActive(log_cached_ptr, log_level))
441 WLog_PrintTextMessage(log_cached_ptr, log_level, line, file, fkt,
442 "%s for slot #%lu(%lu), rv=%s", msg, index, slot, CK_RV_error_string(rv));
446static SECURITY_STATUS collect_keys(NCryptP11ProviderHandle* provider, P11EnumKeysState* state)
448 CK_OBJECT_HANDLE slotObjects[MAX_KEYS_PER_SLOT] = WINPR_C_ARRAY_INIT;
450 WINPR_ASSERT(provider);
452 CK_FUNCTION_LIST_PTR p11 = provider->p11;
455 WLog_DBG(TAG,
"checking %lx slots for valid keys...", state->nslots);
457 for (CK_ULONG i = 0; (i < state->nslots) && (state->nKeys < state->nslots); i++)
459 CK_SESSION_HANDLE session = 0;
463 WINPR_ASSERT(p11->C_GetSlotInfo);
464 CK_RV rv = p11->C_GetSlotInfo(state->slots[i], &slotInfo);
467 loge(TAG,
"unable to retrieve information", rv, i, state->slots[i]);
471 fix_padded_string((
char*)slotInfo.slotDescription,
sizeof(slotInfo.slotDescription));
472 WLog_DBG(TAG,
"collecting keys for slot #%lx(%lu) descr='%s' flags=0x%lx", i,
473 state->slots[i], slotInfo.slotDescription, slotInfo.flags);
477 if (!(slotInfo.flags & CKF_TOKEN_PRESENT))
479 WLog_INFO(TAG,
"token not present for slot #%lu(%lu)", i, state->slots[i]);
483 WINPR_ASSERT(p11->C_GetTokenInfo);
484 rv = p11->C_GetTokenInfo(state->slots[i], &tokenInfo);
486 loge(TAG,
"unable to retrieve token info", rv, i, state->slots[i]);
489 fix_padded_string((
char*)tokenInfo.label,
sizeof(tokenInfo.label));
490 WLog_DBG(TAG,
"token, label='%s' flags=0x%lx", tokenInfo.label, tokenInfo.flags);
493 WINPR_ASSERT(p11->C_OpenSession);
494 rv = p11->C_OpenSession(state->slots[i], CKF_SERIAL_SESSION,
nullptr,
nullptr, &session);
497 WLog_ERR(TAG,
"unable to openSession for slot #%lu(%lu), session=%p rv=%s", i,
498 state->slots[i], WINPR_CXX_COMPAT_CAST(
const void*, session),
499 CK_RV_error_string(rv));
503 WINPR_ASSERT(p11->C_FindObjectsInit);
504 rv = p11->C_FindObjectsInit(session, public_key_filter, ARRAYSIZE(public_key_filter));
508 loge(TAG,
"unable to initiate search", rv, i, state->slots[i]);
509 goto cleanup_FindObjectsInit;
513 CK_ULONG nslotObjects = 0;
514 WINPR_ASSERT(p11->C_FindObjects);
516 p11->C_FindObjects(session, &slotObjects[0], ARRAYSIZE(slotObjects), &nslotObjects);
519 loge(TAG,
"unable to findObjects", rv, i, state->slots[i]);
520 goto cleanup_FindObjects;
523 WLog_DBG(TAG,
"slot has %lu objects", nslotObjects);
524 for (CK_ULONG j = 0; (j < nslotObjects) && (state->nKeys < state->nslots); j++)
526 NCryptKeyEnum* key = &state->keys[state->nKeys];
527 CK_OBJECT_CLASS dataClass = CKO_PUBLIC_KEY;
529 { CKA_ID, &key->id,
sizeof(key->id) },
530 { CKA_CLASS, &dataClass,
sizeof(dataClass) },
531 { CKA_LABEL, &key->keyLabel,
sizeof(key->keyLabel) },
532 { CKA_KEY_TYPE, &key->keyType,
sizeof(key->keyType) }
535 rv = object_load_attributes(provider, session, slotObjects[j], key_or_certAttrs,
536 ARRAYSIZE(key_or_certAttrs));
539 WLog_ERR(TAG,
"error getting attributes, rv=%s", CK_RV_error_string(rv));
543 key->idLen = key_or_certAttrs[0].ulValueLen;
544 if (key->idLen >
sizeof(key->id))
546 WLog_ERR(TAG,
"error getting attributes, idLen %lu > %" PRIuz, key->idLen,
550 if (key_or_certAttrs[1].ulValueLen >
sizeof(dataClass))
552 WLog_ERR(TAG,
"error getting attributes, sizeof(CK_OBJECT_CLASS) %lu > %" PRIuz,
553 key_or_certAttrs[1].ulValueLen,
sizeof(dataClass));
556 if (key_or_certAttrs[2].ulValueLen >
sizeof(key->keyLabel))
558 WLog_ERR(TAG,
"error getting attributes, sizeof(key->keylabel) %lu > %" PRIuz,
559 key_or_certAttrs[2].ulValueLen,
sizeof(key->keyLabel));
562 if (key_or_certAttrs[3].ulValueLen >
sizeof(key->keyType))
564 WLog_ERR(TAG,
"error getting attributes, sizeof(CK_OBJECT_CLASS) %lu > %" PRIuz,
565 key_or_certAttrs[3].ulValueLen,
sizeof(key->keyType));
568 key->slotId = state->slots[i];
569 key->slotInfo = slotInfo;
575 WINPR_ASSERT(p11->C_FindObjectsFinal);
576 rv = p11->C_FindObjectsFinal(session);
578 loge(TAG,
"error during C_FindObjectsFinal", rv, i, state->slots[i]);
579 cleanup_FindObjectsInit:
580 WINPR_ASSERT(p11->C_CloseSession);
581 rv = p11->C_CloseSession(session);
583 loge(TAG,
"error closing session", rv, i, state->slots[i]);
586 return ERROR_SUCCESS;
590static BOOL convertKeyType(CK_KEY_TYPE k, LPWSTR dest, DWORD len, DWORD* outlen)
592 const WCHAR* r =
nullptr;
595#define ALGO_CASE(V, S) \
598 retLen = _wcsnlen((S), ARRAYSIZE((S))); \
602 ALGO_CASE(CKK_RSA, BCRYPT_RSA_ALGORITHM);
603 ALGO_CASE(CKK_DSA, BCRYPT_DSA_ALGORITHM);
604 ALGO_CASE(CKK_DH, BCRYPT_DH_ALGORITHM);
605 ALGO_CASE(CKK_EC, BCRYPT_ECDSA_ALGORITHM);
606 ALGO_CASE(CKK_RC2, BCRYPT_RC2_ALGORITHM);
607 ALGO_CASE(CKK_RC4, BCRYPT_RC4_ALGORITHM);
608 ALGO_CASE(CKK_DES, BCRYPT_DES_ALGORITHM);
609 ALGO_CASE(CKK_DES3, BCRYPT_3DES_ALGORITHM);
613 case CKK_GENERIC_SECRET:
631 if (retLen > UINT32_MAX)
635 *outlen = (UINT32)retLen;
646 if (retLen + 1 > len)
648 WLog_ERR(TAG,
"target buffer is too small for algo name");
652 memcpy(dest, r,
sizeof(WCHAR) * retLen);
660static BOOL wprintKeyName(LPWSTR str,
size_t strByteLen, CK_SLOT_ID slotId, CK_BYTE*
id,
663 if (strByteLen <
sizeof(slotId) + 2ull)
665 if ((strByteLen - (
sizeof(slotId) * 2ull) / 2ull) < idLen)
668 char* asciiName = calloc(strByteLen, 2);
672 char* ptr = asciiName;
676 const CK_BYTE* bytePtr = ((
const CK_BYTE*)&slotId);
677 for (CK_ULONG i = 0; i <
sizeof(slotId); i++, bytePtr++, ptr += 2)
678 (
void)snprintf(ptr, 3,
"%.2x", *bytePtr);
682 for (CK_ULONG i = 0; i < idLen; i++,
id++, ptr += 2)
683 (
void)snprintf(ptr, 3,
"%.2x", *
id);
686 ConvertUtf8NToWChar(asciiName, strByteLen, str, strnlen(asciiName, strByteLen) + 1);
687 winpr_zfree(asciiName);
692static size_t parseHex(
const char* str,
const char* end, CK_BYTE* target)
696 for (; str != end && *str; str++, ret++, target++)
699 if (*str <=
'9' && *str >=
'0')
703 else if (*str <=
'f' && *str >=
'a')
705 v = (10 + *str -
'a');
707 else if (*str <=
'F' && *str >=
'A')
709 v |= (10 + *str -
'A');
718 if (!*str || str == end)
721 if (*str <=
'9' && *str >=
'0')
725 else if (*str <=
'f' && *str >=
'a')
727 v |= (10 + *str -
'a');
729 else if (*str <=
'F' && *str >=
'A')
731 v |= (10 + *str -
'A');
744static SECURITY_STATUS parseKeyName(LPCWSTR pszKeyName, CK_SLOT_ID* slotId, CK_BYTE*
id,
747 char asciiKeyName[128] = WINPR_C_ARRAY_INIT;
750 if (ConvertWCharToUtf8(pszKeyName, asciiKeyName, ARRAYSIZE(asciiKeyName)) < 0)
753 if (*asciiKeyName !=
'\\')
756 pos = strchr(&asciiKeyName[1],
'\\');
760 if ((
size_t)(pos - &asciiKeyName[1]) >
sizeof(CK_SLOT_ID) * 2ull)
763 *slotId = (CK_SLOT_ID)0;
764 if (parseHex(&asciiKeyName[1], pos, (CK_BYTE*)slotId) !=
sizeof(CK_SLOT_ID))
767 *idLen = parseHex(pos + 1,
nullptr,
id);
771 return ERROR_SUCCESS;
775static SECURITY_STATUS NCryptP11EnumKeys(NCRYPT_PROV_HANDLE hProvider, LPCWSTR pszScope,
777 WINPR_ATTR_UNUSED DWORD dwFlags)
779 NCryptP11ProviderHandle* provider = (NCryptP11ProviderHandle*)hProvider;
780 P11EnumKeysState* state = (P11EnumKeysState*)*ppEnumState;
781 CK_RV rv = WINPR_C_ARRAY_INIT;
782 CK_SLOT_ID currentSlot = WINPR_C_ARRAY_INIT;
783 CK_SESSION_HANDLE currentSession = 0;
784 char slotFilterBuffer[65] = WINPR_C_ARRAY_INIT;
785 char* slotFilter =
nullptr;
786 size_t slotFilterLen = 0;
788 SECURITY_STATUS ret = checkNCryptHandle((NCRYPT_HANDLE)hProvider, WINPR_NCRYPT_PROVIDER);
789 if (ret != ERROR_SUCCESS)
798 char asciiScope[128 + 6 + 1] = WINPR_C_ARRAY_INIT;
799 size_t asciiScopeLen = 0;
801 if (ConvertWCharToUtf8(pszScope, asciiScope, ARRAYSIZE(asciiScope) - 1) < 0)
803 WLog_WARN(TAG,
"Invalid scope");
804 return NTE_INVALID_PARAMETER;
807 if (strstr(asciiScope,
"\\\\.\\") != asciiScope)
809 WLog_WARN(TAG,
"Invalid scope '%s'", asciiScope);
810 return NTE_INVALID_PARAMETER;
813 asciiScopeLen = strnlen(asciiScope, ARRAYSIZE(asciiScope));
814 if ((asciiScopeLen < 1) || (asciiScope[asciiScopeLen - 1] !=
'\\'))
816 WLog_WARN(TAG,
"Invalid scope '%s'", asciiScope);
817 return NTE_INVALID_PARAMETER;
820 asciiScope[asciiScopeLen - 1] = 0;
822 strncpy(slotFilterBuffer, &asciiScope[4],
sizeof(slotFilterBuffer));
823 slotFilter = slotFilterBuffer;
824 slotFilterLen = asciiScopeLen - 5;
829 state = (P11EnumKeysState*)calloc(1,
sizeof(*state));
831 return NTE_NO_MEMORY;
833 WINPR_ASSERT(provider->p11->C_GetSlotList);
834 rv = provider->p11->C_GetSlotList(CK_TRUE,
nullptr, &state->nslots);
839 WLog_WARN(TAG,
"C_GetSlotList failed with %s [0x%08lx]", CK_RV_error_string(rv), rv);
843 if (state->nslots > MAX_SLOTS)
844 state->nslots = MAX_SLOTS;
846 rv = provider->p11->C_GetSlotList(CK_TRUE, state->slots, &state->nslots);
851 WLog_WARN(TAG,
"C_GetSlotList failed with %s [0x%08lx]", CK_RV_error_string(rv), rv);
855 ret = collect_keys(provider, state);
856 if (ret != ERROR_SUCCESS)
862 *ppEnumState = state;
865 for (; state->keyIndex < state->nKeys; state->keyIndex++)
868 NCryptKeyEnum* key = &state->keys[state->keyIndex];
869 if (key->idLen >
sizeof(key->id))
871 WLog_ERR(TAG,
"NCryptKeyEnum::idLen %lu > %" PRIuz
"(slotId: %lu", key->idLen,
872 sizeof(key->id), key->slotId);
876 CK_OBJECT_CLASS oclass = CKO_CERTIFICATE;
877 CK_CERTIFICATE_TYPE ctype = CKC_X_509;
878 CK_ATTRIBUTE certificateFilter[] = { { CKA_CLASS, &oclass,
sizeof(oclass) },
879 { CKA_CERTIFICATE_TYPE, &ctype,
sizeof(ctype) },
880 { CKA_ID, key->id, key->idLen } };
881 CK_ULONG ncertObjects = 0;
882 CK_OBJECT_HANDLE certObject = 0;
885 if (slotFilter && memcmp(key->slotInfo.slotDescription, slotFilter, slotFilterLen) != 0)
888 if (!currentSession || (currentSlot != key->slotId))
894 WINPR_ASSERT(provider->p11->C_CloseSession);
895 rv = provider->p11->C_CloseSession(currentSession);
897 WLog_WARN(TAG,
"C_CloseSession failed with %s [0x%08lx]",
898 CK_RV_error_string(rv), rv);
902 WINPR_ASSERT(provider->p11->C_OpenSession);
903 rv = provider->p11->C_OpenSession(key->slotId, CKF_SERIAL_SESSION,
nullptr,
nullptr,
907 WLog_ERR(TAG,
"C_OpenSession failed with %s [0x%08lx] for slot %lu",
908 CK_RV_error_string(rv), rv, key->slotId);
911 currentSlot = key->slotId;
915 WINPR_ASSERT(provider->p11->C_FindObjectsInit);
916 rv = provider->p11->C_FindObjectsInit(currentSession, certificateFilter,
917 ARRAYSIZE(certificateFilter));
920 WLog_ERR(TAG,
"C_FindObjectsInit failed with %s [0x%08lx] for slot %lu",
921 CK_RV_error_string(rv), rv, key->slotId);
925 WINPR_ASSERT(provider->p11->C_FindObjects);
926 rv = provider->p11->C_FindObjects(currentSession, &certObject, 1, &ncertObjects);
929 WLog_ERR(TAG,
"C_FindObjects failed with %s [0x%08lx] for slot %lu",
930 CK_RV_error_string(rv), rv, currentSlot);
931 goto cleanup_FindObjects;
938 size_t KEYNAME_SZ = (1ull + (
sizeof(key->slotId) * 2ull) + 1ull +
939 (key->idLen * 2ull) + 1ull) *
942 if (!convertKeyType(key->keyType,
nullptr, 0, &algoSz))
943 goto cleanup_FindObjects;
945 KEYNAME_SZ += (1ULL + algoSz) *
sizeof(WCHAR);
950 WLog_ERR(TAG,
"unable to allocate keyName");
951 goto cleanup_FindObjects;
953 keyName->dwLegacyKeySpec = AT_KEYEXCHANGE | AT_SIGNATURE;
954 keyName->dwFlags = NCRYPT_MACHINE_KEY_FLAG;
955 keyName->pszName = (LPWSTR)(keyName + 1);
956 if (!wprintKeyName(keyName->pszName, KEYNAME_SZ, key->slotId, key->id, key->idLen))
957 goto cleanup_FindObjects;
959 keyName->pszAlgid = keyName->pszName + _wcslen(keyName->pszName) + 1;
960 if (!convertKeyType(key->keyType, keyName->pszAlgid, algoSz + 1,
nullptr))
961 goto cleanup_FindObjects;
965 WINPR_ASSERT(provider->p11->C_FindObjectsFinal);
966 rv = provider->p11->C_FindObjectsFinal(currentSession);
968 WLog_ERR(TAG,
"C_FindObjectsFinal failed with %s [0x%08lx]", CK_RV_error_string(rv),
973 *ppKeyName = keyName;
975 return ERROR_SUCCESS;
979 return NTE_NO_MORE_ITEMS;
983static BOOL piv_check_sw(DWORD buf_len,
const BYTE* buf,
size_t bufsize, BYTE expected_sw1)
985 return (buf_len >= 2) && (buf_len <= bufsize) && (buf[buf_len - 2] == expected_sw1);
989static BOOL piv_check_sw_success(DWORD buf_len,
const BYTE* buf,
size_t bufsize)
991 return (buf_len >= 2) && (buf_len <= bufsize) && (buf[buf_len - 2] == 0x90) &&
992 (buf[buf_len - 1] == 0x00);
996static SECURITY_STATUS get_piv_container_name_from_mscmap(SCARDHANDLE card,
998 const BYTE* piv_tag, BYTE* output,
1001 BYTE buf[258] = WINPR_C_ARRAY_INIT;
1002 BYTE mscmap_buf[2148] = WINPR_C_ARRAY_INIT;
1003 DWORD buf_len =
sizeof(buf);
1004 DWORD mscmap_total = 0;
1006 if (SCardTransmit(card, pci, APDU_PIV_GET_MSCMAP,
sizeof(APDU_PIV_GET_MSCMAP),
nullptr, buf,
1007 &buf_len) != SCARD_S_SUCCESS)
1008 return NTE_NOT_FOUND;
1010 if (piv_check_sw_success(buf_len, buf,
sizeof(buf)))
1012 mscmap_total = buf_len - 2;
1013 if (mscmap_total >
sizeof(mscmap_buf))
1014 return NTE_NOT_FOUND;
1015 memcpy(mscmap_buf, buf, mscmap_total);
1017 else if (piv_check_sw(buf_len, buf,
sizeof(buf), 0x61))
1019 mscmap_total = buf_len - 2;
1020 if (mscmap_total <=
sizeof(mscmap_buf))
1021 memcpy(mscmap_buf, buf, mscmap_total);
1023 while (piv_check_sw(buf_len, buf,
sizeof(buf), 0x61) && mscmap_total <
sizeof(mscmap_buf))
1025 BYTE get_resp[5] = { 0x00, 0xC0, 0x00, 0x00, buf[buf_len - 1] };
1026 buf_len =
sizeof(buf);
1028 const SECURITY_STATUS status =
1029 SCardTransmit(card, pci, get_resp,
sizeof(get_resp),
nullptr, buf, &buf_len);
1030 if (status != SCARD_S_SUCCESS)
1031 return NTE_NOT_FOUND;
1034 if (piv_check_sw_success(buf_len, buf,
sizeof(buf)) ||
1035 piv_check_sw(buf_len, buf,
sizeof(buf), 0x61))
1036 chunk = buf_len - 2;
1037 if (chunk == 0 || mscmap_total + chunk >
sizeof(mscmap_buf))
1039 memcpy(mscmap_buf + mscmap_total, buf, chunk);
1040 mscmap_total += chunk;
1042 if (!piv_check_sw_success(buf_len, buf,
sizeof(buf)))
1043 return NTE_NOT_FOUND;
1046 return NTE_NOT_FOUND;
1049 const BYTE* mscmap_data = mscmap_buf;
1050 DWORD mscmap_data_len = mscmap_total;
1052 for (
int tlv_pass = 0; tlv_pass < 2; tlv_pass++)
1054 if (mscmap_data_len < 2)
1056 BYTE tlv_tag = mscmap_data[0];
1057 if (tlv_tag != 0x53 && tlv_tag != 0x81)
1060 if (mscmap_data[1] == 0x82 && mscmap_data_len > 4)
1062 else if (mscmap_data[1] == 0x81 && mscmap_data_len > 3)
1065 mscmap_data_len -= (DWORD)hdr;
1069 BYTE target_slot = 0;
1070 for (
size_t i = 0; i < ARRAYSIZE(piv_tag_to_slot); i++)
1072 if (memcmp(piv_tag, piv_tag_to_slot[i].tag, 3) == 0)
1074 target_slot = piv_tag_to_slot[i].slot;
1078 if (target_slot == 0)
1079 return NTE_NOT_FOUND;
1082 size_t num_records = mscmap_data_len / MSCMAP_RECORD_SIZE;
1083 for (
size_t i = 0; i < num_records; i++)
1085 const BYTE* record = mscmap_data + (i * MSCMAP_RECORD_SIZE);
1086 if (record[MSCMAP_SLOT_OFFSET] == target_slot)
1088 size_t copy_len = (MAX_CONTAINER_NAME_LEN + 1) *
sizeof(WCHAR);
1089 if (copy_len > output_len)
1090 copy_len = output_len;
1091 memcpy(output, record, copy_len);
1092 return ERROR_SUCCESS;
1095 return NTE_NOT_FOUND;
1099static SECURITY_STATUS get_piv_container_name_from_chuid(SCARDHANDLE card,
1101 const BYTE* piv_tag, BYTE* output,
1104 BYTE buf[258] = WINPR_C_ARRAY_INIT;
1105 DWORD buf_len =
sizeof(buf);
1106 char container_name[PIV_CONTAINER_NAME_LEN + 1] = WINPR_C_ARRAY_INIT;
1108 if (SCardTransmit(card, pci, APDU_PIV_GET_CHUID,
sizeof(APDU_PIV_GET_CHUID),
nullptr, buf,
1109 &buf_len) != SCARD_S_SUCCESS)
1111 if (!piv_check_sw_success(buf_len, buf,
sizeof(buf)) &&
1112 !piv_check_sw(buf_len, buf,
sizeof(buf), 0x61))
1120 WinPrAsn1Decoder_InitMem(&dec, WINPR_ASN1_BER, buf, buf_len);
1121 if (!WinPrAsn1DecReadTagAndLen(&dec, &tag, &len) || tag != 0x53)
1123 while (WinPrAsn1DecReadTagLenValue(&dec, &tag, &len, &dec2) && tag != 0x34)
1125 if (tag != 0x34 || len != 16)
1128 wStream s = WinPrAsn1DecGetStream(&dec2);
1129 BYTE* p = Stream_Buffer(&s);
1131 (void)snprintf(container_name, PIV_CONTAINER_NAME_LEN + 1,
1132 "%.2x%.2x%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x", p[3],
1133 p[2], p[1], p[0], p[5], p[4], p[7], p[6], p[8], p[9], p[10], p[11], p[12],
1134 piv_tag[0], piv_tag[1], piv_tag[2]);
1142 if (ConvertUtf8NToWChar(container_name, ARRAYSIZE(container_name), cnv.wc,
1143 output_len /
sizeof(WCHAR)) > 0)
1144 return ERROR_SUCCESS;
1149static SECURITY_STATUS get_piv_container_name(NCryptP11KeyHandle* key,
const BYTE* piv_tag,
1150 BYTE* output,
size_t output_len)
1153 CK_FUNCTION_LIST_PTR p11 =
nullptr;
1154 WCHAR* reader =
nullptr;
1155 SCARDCONTEXT context = 0;
1156 SCARDHANDLE card = 0;
1159 BYTE buf[258] = WINPR_C_ARRAY_INIT;
1161 SECURITY_STATUS ret = NTE_BAD_KEY;
1164 WINPR_ASSERT(piv_tag);
1166 WINPR_ASSERT(key->provider);
1167 p11 = key->provider->p11;
1170 WINPR_ASSERT(p11->C_GetSlotInfo);
1171 if (p11->C_GetSlotInfo(key->slotId, &slot_info) != CKR_OK)
1174 fix_padded_string((
char*)slot_info.slotDescription,
sizeof(slot_info.slotDescription));
1175 reader = ConvertUtf8NToWCharAlloc((
char*)slot_info.slotDescription,
1176 ARRAYSIZE(slot_info.slotDescription),
nullptr);
1177 ret = NTE_NO_MEMORY;
1182 if (SCardEstablishContext(SCARD_SCOPE_USER,
nullptr,
nullptr, &context) != SCARD_S_SUCCESS)
1185 if (SCardConnectW(context, reader, SCARD_SHARE_SHARED, SCARD_PROTOCOL_Tx, &card, &proto) !=
1188 pci = (proto == SCARD_PROTOCOL_T0) ? SCARD_PCI_T0 : SCARD_PCI_T1;
1190 buf_len =
sizeof(buf);
1191 if (SCardTransmit(card, pci, APDU_PIV_SELECT_AID,
sizeof(APDU_PIV_SELECT_AID),
nullptr, buf,
1192 &buf_len) != SCARD_S_SUCCESS)
1194 if (!piv_check_sw_success(buf_len, buf,
sizeof(buf)) &&
1195 !piv_check_sw(buf_len, buf,
sizeof(buf), 0x61))
1199 ret = get_piv_container_name_from_mscmap(card, pci, piv_tag, output, output_len);
1200 if (ret != ERROR_SUCCESS)
1201 ret = get_piv_container_name_from_chuid(card, pci, piv_tag, output, output_len);
1206 SCardDisconnect(card, SCARD_LEAVE_CARD);
1208 SCardReleaseContext(context);
1213static SECURITY_STATUS check_for_piv_container_name(NCryptP11KeyHandle* key, BYTE* pbOutput,
1214 DWORD cbOutput, DWORD* pcbResult,
char* label,
1217 for (
size_t i = 0; i < ARRAYSIZE(piv_cert_tags); i++)
1219 const piv_cert_tags_t* cur = &piv_cert_tags[i];
1220 if (strncmp(label, cur->label, label_len) == 0)
1222 *pcbResult = (MAX_CONTAINER_NAME_LEN + 1) *
sizeof(WCHAR);
1224 return ERROR_SUCCESS;
1225 else if (cbOutput < (MAX_CONTAINER_NAME_LEN + 1) *
sizeof(WCHAR))
1226 return NTE_NO_MEMORY;
1228 return get_piv_container_name(key, cur->tag, pbOutput, cbOutput);
1231 return NTE_NOT_FOUND;
1235static SECURITY_STATUS NCryptP11KeyGetProperties(NCryptP11KeyHandle* keyHandle,
1236 NCryptKeyGetPropertyEnum property, PBYTE pbOutput,
1237 DWORD cbOutput, DWORD* pcbResult,
1238 WINPR_ATTR_UNUSED DWORD dwFlags)
1240 SECURITY_STATUS ret = NTE_FAIL;
1242 CK_SESSION_HANDLE session = 0;
1243 CK_OBJECT_HANDLE objectHandle = 0;
1244 CK_ULONG objectCount = 0;
1245 NCryptP11ProviderHandle* provider =
nullptr;
1246 CK_OBJECT_CLASS oclass = CKO_CERTIFICATE;
1247 CK_CERTIFICATE_TYPE ctype = CKC_X_509;
1248 CK_ATTRIBUTE certificateFilter[] = { { CKA_CLASS, &oclass,
sizeof(oclass) },
1249 { CKA_CERTIFICATE_TYPE, &ctype,
sizeof(ctype) },
1250 { CKA_ID, keyHandle->keyCertId,
1251 keyHandle->keyCertIdLen } };
1253 CK_ULONG objectFilterLen = ARRAYSIZE(certificateFilter);
1255 WINPR_ASSERT(keyHandle);
1256 provider = keyHandle->provider;
1257 WINPR_ASSERT(provider);
1262 case NCRYPT_PROPERTY_CERTIFICATE:
1263 case NCRYPT_PROPERTY_NAME:
1265 case NCRYPT_PROPERTY_READER:
1269 WINPR_ASSERT(provider->p11->C_GetSlotInfo);
1270 rv = provider->p11->C_GetSlotInfo(keyHandle->slotId, &slotInfo);
1274#define SLOT_DESC_SZ sizeof(slotInfo.slotDescription)
1275 fix_padded_string((
char*)slotInfo.slotDescription, SLOT_DESC_SZ);
1276 const size_t len = 2ULL * (strnlen((
char*)slotInfo.slotDescription, SLOT_DESC_SZ) + 1);
1277 if (len > UINT32_MAX)
1278 return NTE_BAD_DATA;
1279 *pcbResult = (UINT32)len;
1288 if (cbOutput < *pcbResult)
1289 return NTE_NO_MEMORY;
1291 if (ConvertUtf8NToWChar((
char*)slotInfo.slotDescription, SLOT_DESC_SZ, cnv.wc,
1292 cbOutput /
sizeof(WCHAR)) < 0)
1293 return NTE_NO_MEMORY;
1295 return ERROR_SUCCESS;
1297 case NCRYPT_PROPERTY_SLOTID:
1302 UINT32* ptr = WINPR_PACKED_ALIGN_CAST(UINT32*, pbOutput);
1305 return NTE_NO_MEMORY;
1306 if (keyHandle->slotId > UINT32_MAX)
1311 *ptr = (UINT32)keyHandle->slotId;
1313 return ERROR_SUCCESS;
1315 case NCRYPT_PROPERTY_UNKNOWN:
1317 return NTE_NOT_SUPPORTED;
1320 WINPR_ASSERT(provider->p11->C_OpenSession);
1321 rv = provider->p11->C_OpenSession(keyHandle->slotId, CKF_SERIAL_SESSION,
nullptr,
nullptr,
1325 WLog_ERR(TAG,
"error opening session on slot %lu", keyHandle->slotId);
1329 WINPR_ASSERT(provider->p11->C_FindObjectsInit);
1330 rv = provider->p11->C_FindObjectsInit(session, objectFilter, objectFilterLen);
1333 WLog_ERR(TAG,
"unable to initiate search for slot %lu", keyHandle->slotId);
1337 WINPR_ASSERT(provider->p11->C_FindObjects);
1338 rv = provider->p11->C_FindObjects(session, &objectHandle, 1, &objectCount);
1341 WLog_ERR(TAG,
"unable to findObjects for slot %lu", keyHandle->slotId);
1346 ret = NTE_NOT_FOUND;
1352 case NCRYPT_PROPERTY_CERTIFICATE:
1354 CK_ATTRIBUTE certValue = { CKA_VALUE, pbOutput, cbOutput };
1356 WINPR_ASSERT(provider->p11->C_GetAttributeValue);
1357 rv = provider->p11->C_GetAttributeValue(session, objectHandle, &certValue, 1);
1363 if (certValue.ulValueLen > UINT32_MAX)
1368 *pcbResult = (UINT32)certValue.ulValueLen;
1369 ret = ERROR_SUCCESS;
1372 case NCRYPT_PROPERTY_NAME:
1375 char* label =
nullptr;
1377 WINPR_ASSERT(provider->p11->C_GetAttributeValue);
1378 rv = provider->p11->C_GetAttributeValue(session, objectHandle, &attr, 1);
1381 label = calloc(1, attr.ulValueLen);
1384 ret = NTE_NO_MEMORY;
1388 attr.pValue = label;
1389 rv = provider->p11->C_GetAttributeValue(session, objectHandle, &attr, 1);
1395 ret = check_for_piv_container_name(keyHandle, pbOutput, cbOutput, pcbResult, label,
1399 if (ret == NTE_NOT_FOUND)
1406 const size_t olen = pbOutput ? cbOutput /
sizeof(WCHAR) : 0;
1408 SSIZE_T size = ConvertUtf8NToWChar(label, attr.ulValueLen, cnv.wc, olen);
1410 ret = ERROR_CONVERT_TO_LARGE;
1413 *pcbResult = (UINT32)size *
sizeof(WCHAR);
1414 ret = ERROR_SUCCESS;
1423 ret = NTE_NOT_SUPPORTED;
1428 WINPR_ASSERT(provider->p11->C_FindObjectsFinal);
1429 rv = provider->p11->C_FindObjectsFinal(session);
1432 WLog_ERR(TAG,
"error in C_FindObjectsFinal() for slot %lu", keyHandle->slotId);
1435 WINPR_ASSERT(provider->p11->C_CloseSession);
1436 rv = provider->p11->C_CloseSession(session);
1439 WLog_ERR(TAG,
"error in C_CloseSession() for slot %lu", keyHandle->slotId);
1445static SECURITY_STATUS NCryptP11GetProperty(NCRYPT_HANDLE hObject, NCryptKeyGetPropertyEnum prop,
1446 PBYTE pbOutput, DWORD cbOutput, DWORD* pcbResult,
1454 case WINPR_NCRYPT_PROVIDER:
1455 return ERROR_CALL_NOT_IMPLEMENTED;
1456 case WINPR_NCRYPT_KEY:
1457 return NCryptP11KeyGetProperties((NCryptP11KeyHandle*)hObject, prop, pbOutput, cbOutput,
1458 pcbResult, dwFlags);
1460 return ERROR_INVALID_HANDLE;
1462 return ERROR_SUCCESS;
1466static SECURITY_STATUS NCryptP11OpenKey(NCRYPT_PROV_HANDLE hProvider, NCRYPT_KEY_HANDLE* phKey,
1467 LPCWSTR pszKeyName, WINPR_ATTR_UNUSED DWORD dwLegacyKeySpec,
1468 WINPR_ATTR_UNUSED DWORD dwFlags)
1470 SECURITY_STATUS ret = 0;
1471 CK_SLOT_ID slotId = 0;
1472 CK_BYTE keyCertId[64] = WINPR_C_ARRAY_INIT;
1473 CK_ULONG keyCertIdLen = 0;
1474 NCryptP11KeyHandle* keyHandle =
nullptr;
1476 ret = parseKeyName(pszKeyName, &slotId, keyCertId, &keyCertIdLen);
1477 if (ret != ERROR_SUCCESS)
1480 keyHandle = (NCryptP11KeyHandle*)ncrypt_new_handle(
1481 WINPR_NCRYPT_KEY,
sizeof(*keyHandle), NCryptP11GetProperty, winpr_NCryptDefault_dtor);
1483 return NTE_NO_MEMORY;
1485 keyHandle->provider = (NCryptP11ProviderHandle*)hProvider;
1486 keyHandle->slotId = slotId;
1487 memcpy(keyHandle->keyCertId, keyCertId,
sizeof(keyCertId));
1488 keyHandle->keyCertIdLen = keyCertIdLen;
1489 *phKey = (NCRYPT_KEY_HANDLE)keyHandle;
1490 return ERROR_SUCCESS;
1494static SECURITY_STATUS initialize_pkcs11(HANDLE handle,
1495 CK_RV (*c_get_function_list)(CK_FUNCTION_LIST_PTR_PTR),
1496 NCRYPT_PROV_HANDLE* phProvider)
1498 SECURITY_STATUS status = ERROR_SUCCESS;
1499 NCryptP11ProviderHandle* ret =
nullptr;
1502 WINPR_ASSERT(c_get_function_list);
1503 WINPR_ASSERT(phProvider);
1505 ret = (NCryptP11ProviderHandle*)ncrypt_new_handle(
1506 WINPR_NCRYPT_PROVIDER,
sizeof(*ret), NCryptP11GetProperty, NCryptP11StorageProvider_dtor);
1508 return NTE_NO_MEMORY;
1510 ret->library = handle;
1511 ret->baseProvider.enumKeysFn = NCryptP11EnumKeys;
1512 ret->baseProvider.openKeyFn = NCryptP11OpenKey;
1514 rv = c_get_function_list(&ret->p11);
1517 status = NTE_PROVIDER_DLL_FAIL;
1521 WINPR_ASSERT(ret->p11);
1522 WINPR_ASSERT(ret->p11->C_Initialize);
1523 rv = ret->p11->C_Initialize(
nullptr);
1526 status = NTE_PROVIDER_DLL_FAIL;
1530 *phProvider = (NCRYPT_PROV_HANDLE)ret;
1533 if (status != ERROR_SUCCESS)
1534 ret->baseProvider.baseHandle.releaseFn((NCRYPT_HANDLE)ret);
1538SECURITY_STATUS NCryptOpenP11StorageProviderEx(NCRYPT_PROV_HANDLE* phProvider,
1539 WINPR_ATTR_UNUSED LPCWSTR pszProviderName,
1540 WINPR_ATTR_UNUSED DWORD dwFlags, LPCSTR* modulePaths)
1542 SECURITY_STATUS status = ERROR_INVALID_PARAMETER;
1543 LPCSTR defaultPaths[] = {
"p11-kit-proxy.so",
"opensc-pkcs11.so",
nullptr };
1546 return ERROR_INVALID_PARAMETER;
1549 modulePaths = defaultPaths;
1551 while (*modulePaths)
1553 const char* modulePath = *modulePaths++;
1554 HANDLE library = LoadLibrary(modulePath);
1555 typedef CK_RV (*c_get_function_list_t)(CK_FUNCTION_LIST_PTR_PTR);
1556 NCryptP11ProviderHandle* provider =
nullptr;
1558 WLog_DBG(TAG,
"Trying pkcs11 module '%s'", modulePath);
1561 status = NTE_PROV_DLL_NOT_FOUND;
1562 goto out_load_library;
1566 c_get_function_list_t c_get_function_list =
1567 GetProcAddressAs(library,
"C_GetFunctionList", c_get_function_list_t);
1569 if (!c_get_function_list)
1571 status = NTE_PROV_TYPE_ENTRY_BAD;
1572 goto out_load_library;
1575 status = initialize_pkcs11(library, c_get_function_list, phProvider);
1577 if (status != ERROR_SUCCESS)
1579 status = NTE_PROVIDER_DLL_FAIL;
1580 goto out_load_library;
1583 provider = (NCryptP11ProviderHandle*)*phProvider;
1584 provider->modulePath = _strdup(modulePath);
1585 if (!provider->modulePath)
1587 status = NTE_NO_MEMORY;
1588 goto out_load_library;
1591 WLog_DBG(TAG,
"module '%s' loaded", modulePath);
1592 return ERROR_SUCCESS;
1596 FreeLibrary(library);
1602const char* NCryptGetModulePath(NCRYPT_PROV_HANDLE phProvider)
1604 NCryptP11ProviderHandle* provider = (NCryptP11ProviderHandle*)phProvider;
1606 WINPR_ASSERT(provider);
1608 return provider->modulePath;
common ncrypt handle items
common ncrypt provider items