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>
32 #include "pkcs11-headers/pkcs11.h"
34 #define TAG WINPR_TAG("ncryptp11")
38 #define MAX_KEYS_PER_SLOT 64
46 CK_FUNCTION_LIST_PTR p11;
48 } NCryptP11ProviderHandle;
54 NCryptP11ProviderHandle* provider;
56 CK_BYTE keyCertId[64];
57 CK_ULONG keyCertIdLen;
65 CK_CHAR keyLabel[256];
73 CK_SLOT_ID slots[MAX_SLOTS];
75 NCryptKeyEnum keys[MAX_KEYS];
84 static const piv_cert_tags_t piv_cert_tags[] = {
85 {
"Certificate for PIV Authentication",
"\x5F\xC1\x05" },
86 {
"Certificate for Digital Signature",
"\x5F\xC1\x0A" },
87 {
"Certificate for Key Management",
"\x5F\xC1\x0B" },
88 {
"Certificate for Card Authentication",
"\x5F\xC1\x01" },
91 static const BYTE APDU_PIV_SELECT_AID[] = { 0x00, 0xA4, 0x04, 0x00, 0x09, 0xA0, 0x00, 0x00,
92 0x03, 0x08, 0x00, 0x00, 0x10, 0x00, 0x00 };
93 static const BYTE APDU_PIV_GET_CHUID[] = { 0x00, 0xCB, 0x3F, 0xFF, 0x05, 0x5C,
94 0x03, 0x5F, 0xC1, 0x02, 0x00 };
95 #define PIV_CONTAINER_NAME_LEN 36
97 static CK_OBJECT_CLASS object_class_public_key = CKO_PUBLIC_KEY;
98 static CK_BBOOL object_verify = CK_TRUE;
99 static CK_KEY_TYPE object_ktype_rsa = CKK_RSA;
102 { CKA_CLASS, &object_class_public_key,
sizeof(object_class_public_key) },
103 { CKA_VERIFY, &object_verify,
sizeof(object_verify) },
104 { CKA_KEY_TYPE, &object_ktype_rsa,
sizeof(object_ktype_rsa) }
107 static const char* CK_RV_error_string(CK_RV rv);
109 static SECURITY_STATUS NCryptP11StorageProvider_dtor(NCRYPT_HANDLE handle)
111 NCryptP11ProviderHandle* provider = (NCryptP11ProviderHandle*)handle;
116 if (provider->p11 && provider->p11->C_Finalize)
117 rv = provider->p11->C_Finalize(NULL);
119 WLog_WARN(TAG,
"C_Finalize failed with %s [0x%08" PRIx32
"]", CK_RV_error_string(rv),
122 free(provider->modulePath);
124 if (provider->library)
125 FreeLibrary(provider->library);
128 return winpr_NCryptDefault_dtor(handle);
131 static void fix_padded_string(
char* str,
size_t maxlen)
133 char* ptr = str + maxlen - 1;
135 while (ptr > str && *ptr ==
' ')
141 static BOOL attributes_have_unallocated_buffers(CK_ATTRIBUTE_PTR attributes, CK_ULONG count)
143 for (CK_ULONG i = 0; i < count; i++)
145 if (!attributes[i].pValue && (attributes[i].ulValueLen != CK_UNAVAILABLE_INFORMATION))
152 static BOOL attribute_allocate_attribute_array(CK_ATTRIBUTE_PTR attribute)
154 WINPR_ASSERT(attribute);
155 attribute->pValue = calloc(attribute->ulValueLen,
sizeof(
void*));
156 return !!attribute->pValue;
159 static BOOL attribute_allocate_ulong_array(CK_ATTRIBUTE_PTR attribute)
161 attribute->pValue = calloc(attribute->ulValueLen,
sizeof(CK_ULONG));
162 return !!attribute->pValue;
165 static BOOL attribute_allocate_buffer(CK_ATTRIBUTE_PTR attribute)
167 attribute->pValue = calloc(attribute->ulValueLen, 1);
168 return !!attribute->pValue;
171 static BOOL attributes_allocate_buffers(CK_ATTRIBUTE_PTR attributes, CK_ULONG count)
175 for (CK_ULONG i = 0; i < count; i++)
177 if (attributes[i].pValue || (attributes[i].ulValueLen == CK_UNAVAILABLE_INFORMATION))
180 switch (attributes[i].type)
182 case CKA_WRAP_TEMPLATE:
183 case CKA_UNWRAP_TEMPLATE:
184 ret &= attribute_allocate_attribute_array(&attributes[i]);
187 case CKA_ALLOWED_MECHANISMS:
188 ret &= attribute_allocate_ulong_array(&attributes[i]);
192 ret &= attribute_allocate_buffer(&attributes[i]);
200 static CK_RV object_load_attributes(NCryptP11ProviderHandle* provider, CK_SESSION_HANDLE session,
201 CK_OBJECT_HANDLE
object, CK_ATTRIBUTE_PTR attributes,
204 WINPR_ASSERT(provider);
205 WINPR_ASSERT(provider->p11);
206 WINPR_ASSERT(provider->p11->C_GetAttributeValue);
208 CK_RV rv = provider->p11->C_GetAttributeValue(session,
object, attributes, count);
213 if (!attributes_have_unallocated_buffers(attributes, count))
217 case CKR_ATTRIBUTE_SENSITIVE:
218 case CKR_ATTRIBUTE_TYPE_INVALID:
219 case CKR_BUFFER_TOO_SMALL:
221 if (!attributes_allocate_buffers(attributes, count))
222 return CKR_HOST_MEMORY;
224 rv = provider->p11->C_GetAttributeValue(session,
object, attributes, count);
226 WLog_WARN(TAG,
"C_GetAttributeValue failed with %s [0x%08" PRIx32
"]",
227 CK_RV_error_string(rv), rv);
230 WLog_WARN(TAG,
"C_GetAttributeValue failed with %s [0x%08" PRIx32
"]",
231 CK_RV_error_string(rv), rv);
237 case CKR_ATTRIBUTE_SENSITIVE:
238 case CKR_ATTRIBUTE_TYPE_INVALID:
239 case CKR_BUFFER_TOO_SMALL:
241 "C_GetAttributeValue failed with %s [0x%08" PRIx32
242 "] even after buffer allocation",
243 CK_RV_error_string(rv), rv);
251 static const char* CK_RV_error_string(CK_RV rv)
253 static char generic_buffer[200];
254 #define ERR_ENTRY(X) \
261 ERR_ENTRY(CKR_CANCEL);
262 ERR_ENTRY(CKR_HOST_MEMORY);
263 ERR_ENTRY(CKR_SLOT_ID_INVALID);
264 ERR_ENTRY(CKR_GENERAL_ERROR);
265 ERR_ENTRY(CKR_FUNCTION_FAILED);
266 ERR_ENTRY(CKR_ARGUMENTS_BAD);
267 ERR_ENTRY(CKR_NO_EVENT);
268 ERR_ENTRY(CKR_NEED_TO_CREATE_THREADS);
269 ERR_ENTRY(CKR_CANT_LOCK);
270 ERR_ENTRY(CKR_ATTRIBUTE_READ_ONLY);
271 ERR_ENTRY(CKR_ATTRIBUTE_SENSITIVE);
272 ERR_ENTRY(CKR_ATTRIBUTE_TYPE_INVALID);
273 ERR_ENTRY(CKR_ATTRIBUTE_VALUE_INVALID);
274 ERR_ENTRY(CKR_DATA_INVALID);
275 ERR_ENTRY(CKR_DATA_LEN_RANGE);
276 ERR_ENTRY(CKR_DEVICE_ERROR);
277 ERR_ENTRY(CKR_DEVICE_MEMORY);
278 ERR_ENTRY(CKR_DEVICE_REMOVED);
279 ERR_ENTRY(CKR_ENCRYPTED_DATA_INVALID);
280 ERR_ENTRY(CKR_ENCRYPTED_DATA_LEN_RANGE);
281 ERR_ENTRY(CKR_FUNCTION_CANCELED);
282 ERR_ENTRY(CKR_FUNCTION_NOT_PARALLEL);
283 ERR_ENTRY(CKR_FUNCTION_NOT_SUPPORTED);
284 ERR_ENTRY(CKR_KEY_HANDLE_INVALID);
285 ERR_ENTRY(CKR_KEY_SIZE_RANGE);
286 ERR_ENTRY(CKR_KEY_TYPE_INCONSISTENT);
287 ERR_ENTRY(CKR_KEY_NOT_NEEDED);
288 ERR_ENTRY(CKR_KEY_CHANGED);
289 ERR_ENTRY(CKR_KEY_NEEDED);
290 ERR_ENTRY(CKR_KEY_INDIGESTIBLE);
291 ERR_ENTRY(CKR_KEY_FUNCTION_NOT_PERMITTED);
292 ERR_ENTRY(CKR_KEY_NOT_WRAPPABLE);
293 ERR_ENTRY(CKR_KEY_UNEXTRACTABLE);
294 ERR_ENTRY(CKR_MECHANISM_INVALID);
295 ERR_ENTRY(CKR_MECHANISM_PARAM_INVALID);
296 ERR_ENTRY(CKR_OBJECT_HANDLE_INVALID);
297 ERR_ENTRY(CKR_OPERATION_ACTIVE);
298 ERR_ENTRY(CKR_OPERATION_NOT_INITIALIZED);
299 ERR_ENTRY(CKR_PIN_INCORRECT);
300 ERR_ENTRY(CKR_PIN_INVALID);
301 ERR_ENTRY(CKR_PIN_LEN_RANGE);
302 ERR_ENTRY(CKR_PIN_EXPIRED);
303 ERR_ENTRY(CKR_PIN_LOCKED);
304 ERR_ENTRY(CKR_SESSION_CLOSED);
305 ERR_ENTRY(CKR_SESSION_COUNT);
306 ERR_ENTRY(CKR_SESSION_HANDLE_INVALID);
307 ERR_ENTRY(CKR_SESSION_PARALLEL_NOT_SUPPORTED);
308 ERR_ENTRY(CKR_SESSION_READ_ONLY);
309 ERR_ENTRY(CKR_SESSION_EXISTS);
310 ERR_ENTRY(CKR_SESSION_READ_ONLY_EXISTS);
311 ERR_ENTRY(CKR_SESSION_READ_WRITE_SO_EXISTS);
312 ERR_ENTRY(CKR_SIGNATURE_INVALID);
313 ERR_ENTRY(CKR_SIGNATURE_LEN_RANGE);
314 ERR_ENTRY(CKR_TEMPLATE_INCOMPLETE);
315 ERR_ENTRY(CKR_TEMPLATE_INCONSISTENT);
316 ERR_ENTRY(CKR_TOKEN_NOT_PRESENT);
317 ERR_ENTRY(CKR_TOKEN_NOT_RECOGNIZED);
318 ERR_ENTRY(CKR_TOKEN_WRITE_PROTECTED);
319 ERR_ENTRY(CKR_UNWRAPPING_KEY_HANDLE_INVALID);
320 ERR_ENTRY(CKR_UNWRAPPING_KEY_SIZE_RANGE);
321 ERR_ENTRY(CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT);
322 ERR_ENTRY(CKR_USER_ALREADY_LOGGED_IN);
323 ERR_ENTRY(CKR_USER_NOT_LOGGED_IN);
324 ERR_ENTRY(CKR_USER_PIN_NOT_INITIALIZED);
325 ERR_ENTRY(CKR_USER_TYPE_INVALID);
326 ERR_ENTRY(CKR_USER_ANOTHER_ALREADY_LOGGED_IN);
327 ERR_ENTRY(CKR_USER_TOO_MANY_TYPES);
328 ERR_ENTRY(CKR_WRAPPED_KEY_INVALID);
329 ERR_ENTRY(CKR_WRAPPED_KEY_LEN_RANGE);
330 ERR_ENTRY(CKR_WRAPPING_KEY_HANDLE_INVALID);
331 ERR_ENTRY(CKR_WRAPPING_KEY_SIZE_RANGE);
332 ERR_ENTRY(CKR_WRAPPING_KEY_TYPE_INCONSISTENT);
333 ERR_ENTRY(CKR_RANDOM_SEED_NOT_SUPPORTED);
334 ERR_ENTRY(CKR_RANDOM_NO_RNG);
335 ERR_ENTRY(CKR_DOMAIN_PARAMS_INVALID);
336 ERR_ENTRY(CKR_BUFFER_TOO_SMALL);
337 ERR_ENTRY(CKR_SAVED_STATE_INVALID);
338 ERR_ENTRY(CKR_INFORMATION_SENSITIVE);
339 ERR_ENTRY(CKR_STATE_UNSAVEABLE);
340 ERR_ENTRY(CKR_CRYPTOKI_NOT_INITIALIZED);
341 ERR_ENTRY(CKR_CRYPTOKI_ALREADY_INITIALIZED);
342 ERR_ENTRY(CKR_MUTEX_BAD);
343 ERR_ENTRY(CKR_MUTEX_NOT_LOCKED);
344 ERR_ENTRY(CKR_FUNCTION_REJECTED);
346 (void)snprintf(generic_buffer,
sizeof(generic_buffer),
"unknown 0x%lx", rv);
347 return generic_buffer;
352 #define loge(tag, msg, rv, index, slot) \
353 log_((tag), (msg), (rv), (index), (slot), __FILE__, __func__, __LINE__)
354 static void log_(
const char* tag,
const char* msg, CK_RV rv, CK_ULONG index, CK_SLOT_ID slot,
355 const char* file,
const char* fkt,
size_t line)
357 const DWORD log_level = WLOG_ERROR;
358 static wLog* log_cached_ptr = NULL;
360 log_cached_ptr = WLog_Get(tag);
361 if (!WLog_IsLevelActive(log_cached_ptr, log_level))
364 WLog_PrintMessage(log_cached_ptr, WLOG_MESSAGE_TEXT, log_level, line, file, fkt,
365 "%s for slot #%" PRIu32
"(%" PRIu32
"), rv=%s", msg, index, slot,
366 CK_RV_error_string(rv));
369 static SECURITY_STATUS collect_keys(NCryptP11ProviderHandle* provider, P11EnumKeysState* state)
371 CK_OBJECT_HANDLE slotObjects[MAX_KEYS_PER_SLOT] = { 0 };
373 WINPR_ASSERT(provider);
375 CK_FUNCTION_LIST_PTR p11 = provider->p11;
378 WLog_DBG(TAG,
"checking %" PRIu32
" slots for valid keys...", state->nslots);
380 for (CK_ULONG i = 0; i < state->nslots; i++)
382 CK_SESSION_HANDLE session = (CK_SESSION_HANDLE)NULL;
386 WINPR_ASSERT(p11->C_GetSlotInfo);
387 CK_RV rv = p11->C_GetSlotInfo(state->slots[i], &slotInfo);
390 loge(TAG,
"unable to retrieve information", rv, i, state->slots[i]);
394 fix_padded_string((
char*)slotInfo.slotDescription,
sizeof(slotInfo.slotDescription));
395 WLog_DBG(TAG,
"collecting keys for slot #%" PRIu32
"(%" PRIu32
") descr='%s' flags=0x%x", i,
396 state->slots[i], slotInfo.slotDescription, slotInfo.flags);
400 if (!(slotInfo.flags & CKF_TOKEN_PRESENT))
402 WLog_INFO(TAG,
"token not present for slot #%" PRIu32
"(%" PRIu32
")", i,
407 WINPR_ASSERT(p11->C_GetTokenInfo);
408 rv = p11->C_GetTokenInfo(state->slots[i], &tokenInfo);
410 loge(TAG,
"unable to retrieve token info", rv, i, state->slots[i]);
413 fix_padded_string((
char*)tokenInfo.label,
sizeof(tokenInfo.label));
414 WLog_DBG(TAG,
"token, label='%s' flags=0x%x", tokenInfo.label, tokenInfo.flags);
417 WINPR_ASSERT(p11->C_OpenSession);
418 rv = p11->C_OpenSession(state->slots[i], CKF_SERIAL_SESSION, NULL, NULL, &session);
422 "unable to openSession for slot #%" PRIu32
"(%" PRIu32
"), session=%p rv=%s",
423 i, state->slots[i], session, CK_RV_error_string(rv));
427 WINPR_ASSERT(p11->C_FindObjectsInit);
428 rv = p11->C_FindObjectsInit(session, public_key_filter, ARRAYSIZE(public_key_filter));
432 loge(TAG,
"unable to initiate search", rv, i, state->slots[i]);
433 goto cleanup_FindObjectsInit;
436 CK_ULONG nslotObjects = 0;
437 WINPR_ASSERT(p11->C_FindObjects);
438 rv = p11->C_FindObjects(session, &slotObjects[0], ARRAYSIZE(slotObjects), &nslotObjects);
441 loge(TAG,
"unable to findObjects", rv, i, state->slots[i]);
442 goto cleanup_FindObjects;
445 WLog_DBG(TAG,
"slot has %d objects", nslotObjects);
446 for (CK_ULONG j = 0; j < nslotObjects; j++)
448 NCryptKeyEnum* key = &state->keys[state->nKeys];
449 CK_OBJECT_CLASS dataClass = CKO_PUBLIC_KEY;
451 { CKA_ID, &key->id,
sizeof(key->id) },
452 { CKA_CLASS, &dataClass,
sizeof(dataClass) },
453 { CKA_LABEL, &key->keyLabel,
sizeof(key->keyLabel) },
454 { CKA_KEY_TYPE, &key->keyType,
sizeof(key->keyType) }
457 rv = object_load_attributes(provider, session, slotObjects[j], key_or_certAttrs,
458 ARRAYSIZE(key_or_certAttrs));
461 WLog_ERR(TAG,
"error getting attributes, rv=%s", CK_RV_error_string(rv));
465 key->idLen = key_or_certAttrs[0].ulValueLen;
466 key->slotId = state->slots[i];
467 key->slotInfo = slotInfo;
472 WINPR_ASSERT(p11->C_FindObjectsFinal);
473 rv = p11->C_FindObjectsFinal(session);
475 loge(TAG,
"error during C_FindObjectsFinal", rv, i, state->slots[i]);
476 cleanup_FindObjectsInit:
477 WINPR_ASSERT(p11->C_CloseSession);
478 rv = p11->C_CloseSession(session);
480 loge(TAG,
"error closing session", rv, i, state->slots[i]);
483 return ERROR_SUCCESS;
486 static BOOL convertKeyType(CK_KEY_TYPE k, LPWSTR dest, DWORD len, DWORD* outlen)
488 const WCHAR* r = NULL;
490 #define ALGO_CASE(V, S) \
496 ALGO_CASE(CKK_RSA, BCRYPT_RSA_ALGORITHM);
497 ALGO_CASE(CKK_DSA, BCRYPT_DSA_ALGORITHM);
498 ALGO_CASE(CKK_DH, BCRYPT_DH_ALGORITHM);
499 ALGO_CASE(CKK_EC, BCRYPT_ECDSA_ALGORITHM);
500 ALGO_CASE(CKK_RC2, BCRYPT_RC2_ALGORITHM);
501 ALGO_CASE(CKK_RC4, BCRYPT_RC4_ALGORITHM);
502 ALGO_CASE(CKK_DES, BCRYPT_DES_ALGORITHM);
503 ALGO_CASE(CKK_DES3, BCRYPT_3DES_ALGORITHM);
507 case CKK_GENERIC_SECRET:
525 size_t retLen = _wcslen(r);
526 if (retLen > UINT32_MAX)
530 *outlen = (UINT32)retLen;
540 if (retLen + 1 < len)
542 WLog_ERR(TAG,
"target buffer is too small for algo name");
548 memcpy(dest, r,
sizeof(WCHAR) * retLen);
556 static void wprintKeyName(LPWSTR str, CK_SLOT_ID slotId, CK_BYTE*
id, CK_ULONG idLen)
558 char asciiName[128] = { 0 };
559 char* ptr = asciiName;
560 const CK_BYTE* bytePtr = NULL;
565 bytePtr = ((CK_BYTE*)&slotId);
566 for (CK_ULONG i = 0; i <
sizeof(slotId); i++, bytePtr++, ptr += 2)
567 (
void)snprintf(ptr, 3,
"%.2x", *bytePtr);
572 for (CK_ULONG i = 0; i < idLen; i++,
id++, ptr += 2)
573 (
void)snprintf(ptr, 3,
"%.2x", *
id);
575 (void)ConvertUtf8NToWChar(asciiName, ARRAYSIZE(asciiName), str,
576 strnlen(asciiName, ARRAYSIZE(asciiName)) + 1);
579 static size_t parseHex(
const char* str,
const char* end, CK_BYTE* target)
583 for (; str != end && *str; str++, ret++, target++)
586 if (*str <= '9' && *str >=
'0')
590 else if (*str <= 'f' && *str >=
'a')
592 v = (10 + *str -
'a');
594 else if (*str <= 'F' && *str >=
'A')
596 v |= (10 + *str -
'A');
605 if (!*str || str == end)
608 if (*str <= '9' && *str >=
'0')
612 else if (*str <= 'f' && *str >=
'a')
614 v |= (10 + *str -
'a');
616 else if (*str <= 'F' && *str >=
'A')
618 v |= (10 + *str -
'A');
630 static SECURITY_STATUS parseKeyName(LPCWSTR pszKeyName, CK_SLOT_ID* slotId, CK_BYTE*
id,
633 char asciiKeyName[128] = { 0 };
636 if (ConvertWCharToUtf8(pszKeyName, asciiKeyName, ARRAYSIZE(asciiKeyName)) < 0)
639 if (*asciiKeyName !=
'\\')
642 pos = strchr(&asciiKeyName[1],
'\\');
646 if ((
size_t)(pos - &asciiKeyName[1]) >
sizeof(CK_SLOT_ID) * 2ull)
649 *slotId = (CK_SLOT_ID)0;
650 if (parseHex(&asciiKeyName[1], pos, (CK_BYTE*)slotId) !=
sizeof(CK_SLOT_ID))
653 *idLen = parseHex(pos + 1, NULL,
id);
657 return ERROR_SUCCESS;
660 static SECURITY_STATUS NCryptP11EnumKeys(NCRYPT_PROV_HANDLE hProvider, LPCWSTR pszScope,
664 NCryptP11ProviderHandle* provider = (NCryptP11ProviderHandle*)hProvider;
665 P11EnumKeysState* state = (P11EnumKeysState*)*ppEnumState;
667 CK_SLOT_ID currentSlot = { 0 };
668 CK_SESSION_HANDLE currentSession = (CK_SESSION_HANDLE)NULL;
669 char slotFilterBuffer[65] = { 0 };
670 char* slotFilter = NULL;
671 size_t slotFilterLen = 0;
673 SECURITY_STATUS ret = checkNCryptHandle((NCRYPT_HANDLE)hProvider, WINPR_NCRYPT_PROVIDER);
674 if (ret != ERROR_SUCCESS)
683 char asciiScope[128 + 6 + 1] = { 0 };
684 size_t asciiScopeLen = 0;
686 if (ConvertWCharToUtf8(pszScope, asciiScope, ARRAYSIZE(asciiScope) - 1) < 0)
688 WLog_WARN(TAG,
"Invalid scope");
689 return NTE_INVALID_PARAMETER;
692 if (strstr(asciiScope,
"\\\\.\\") != asciiScope)
694 WLog_WARN(TAG,
"Invalid scope '%s'", asciiScope);
695 return NTE_INVALID_PARAMETER;
698 asciiScopeLen = strnlen(asciiScope, ARRAYSIZE(asciiScope));
699 if ((asciiScopeLen < 1) || (asciiScope[asciiScopeLen - 1] !=
'\\'))
701 WLog_WARN(TAG,
"Invalid scope '%s'", asciiScope);
702 return NTE_INVALID_PARAMETER;
705 asciiScope[asciiScopeLen - 1] = 0;
707 strncpy(slotFilterBuffer, &asciiScope[4],
sizeof(slotFilterBuffer));
708 slotFilter = slotFilterBuffer;
709 slotFilterLen = asciiScopeLen - 5;
714 state = (P11EnumKeysState*)calloc(1,
sizeof(*state));
716 return NTE_NO_MEMORY;
718 WINPR_ASSERT(provider->p11->C_GetSlotList);
719 rv = provider->p11->C_GetSlotList(CK_TRUE, NULL, &state->nslots);
724 WLog_WARN(TAG,
"C_GetSlotList failed with %s [0x%08" PRIx32
"]", CK_RV_error_string(rv),
729 if (state->nslots > MAX_SLOTS)
730 state->nslots = MAX_SLOTS;
732 rv = provider->p11->C_GetSlotList(CK_TRUE, state->slots, &state->nslots);
737 WLog_WARN(TAG,
"C_GetSlotList failed with %s [0x%08" PRIx32
"]", CK_RV_error_string(rv),
742 ret = collect_keys(provider, state);
743 if (ret != ERROR_SUCCESS)
749 *ppEnumState = state;
752 for (; state->keyIndex < state->nKeys; state->keyIndex++)
755 NCryptKeyEnum* key = &state->keys[state->keyIndex];
756 CK_OBJECT_CLASS oclass = CKO_CERTIFICATE;
757 CK_CERTIFICATE_TYPE ctype = CKC_X_509;
758 CK_ATTRIBUTE certificateFilter[] = { { CKA_CLASS, &oclass,
sizeof(oclass) },
759 { CKA_CERTIFICATE_TYPE, &ctype,
sizeof(ctype) },
760 { CKA_ID, key->id, key->idLen } };
761 CK_ULONG ncertObjects = 0;
762 CK_OBJECT_HANDLE certObject = 0;
765 if (slotFilter && memcmp(key->slotInfo.slotDescription, slotFilter, slotFilterLen) != 0)
768 if (!currentSession || (currentSlot != key->slotId))
774 WINPR_ASSERT(provider->p11->C_CloseSession);
775 rv = provider->p11->C_CloseSession(currentSession);
777 WLog_WARN(TAG,
"C_CloseSession failed with %s [0x%08" PRIx32
"]",
778 CK_RV_error_string(rv), rv);
779 currentSession = (CK_SESSION_HANDLE)NULL;
782 WINPR_ASSERT(provider->p11->C_OpenSession);
783 rv = provider->p11->C_OpenSession(key->slotId, CKF_SERIAL_SESSION, NULL, NULL,
787 WLog_ERR(TAG,
"C_OpenSession failed with %s [0x%08" PRIx32
"] for slot %d",
788 CK_RV_error_string(rv), rv, key->slotId);
791 currentSlot = key->slotId;
795 WINPR_ASSERT(provider->p11->C_FindObjectsInit);
796 rv = provider->p11->C_FindObjectsInit(currentSession, certificateFilter,
797 ARRAYSIZE(certificateFilter));
800 WLog_ERR(TAG,
"C_FindObjectsInit failed with %s [0x%08" PRIx32
"] for slot %d",
801 CK_RV_error_string(rv), rv, key->slotId);
805 WINPR_ASSERT(provider->p11->C_FindObjects);
806 rv = provider->p11->C_FindObjects(currentSession, &certObject, 1, &ncertObjects);
809 WLog_ERR(TAG,
"C_FindObjects failed with %s [0x%08" PRIx32
"] for slot %d",
810 CK_RV_error_string(rv), rv, currentSlot);
811 goto cleanup_FindObjects;
819 (1 + (
sizeof(key->slotId) * 2) + 1 + (key->idLen * 2) + 1) * 2;
821 convertKeyType(key->keyType, NULL, 0, &algoSz);
822 KEYNAME_SZ += (1ULL + algoSz) * 2ULL;
824 keyName = calloc(1,
sizeof(*keyName) + KEYNAME_SZ);
827 WLog_ERR(TAG,
"unable to allocate keyName");
828 goto cleanup_FindObjects;
830 keyName->dwLegacyKeySpec = AT_KEYEXCHANGE | AT_SIGNATURE;
831 keyName->dwFlags = NCRYPT_MACHINE_KEY_FLAG;
832 keyName->pszName = (LPWSTR)(keyName + 1);
833 wprintKeyName(keyName->pszName, key->slotId, key->id, key->idLen);
835 keyName->pszAlgid = keyName->pszName + _wcslen(keyName->pszName) + 1;
836 convertKeyType(key->keyType, keyName->pszAlgid, algoSz + 1, NULL);
840 WINPR_ASSERT(provider->p11->C_FindObjectsFinal);
841 rv = provider->p11->C_FindObjectsFinal(currentSession);
843 WLog_ERR(TAG,
"C_FindObjectsFinal failed with %s [0x%08" PRIx32
"]",
844 CK_RV_error_string(rv), rv);
848 *ppKeyName = keyName;
850 return ERROR_SUCCESS;
854 return NTE_NO_MORE_ITEMS;
857 static SECURITY_STATUS get_piv_container_name(NCryptP11KeyHandle* key,
const BYTE* piv_tag,
858 BYTE* output,
size_t output_len)
861 CK_FUNCTION_LIST_PTR p11 = NULL;
862 WCHAR* reader = NULL;
863 SCARDCONTEXT context = 0;
864 SCARDHANDLE card = 0;
867 BYTE buf[258] = { 0 };
868 char container_name[PIV_CONTAINER_NAME_LEN + 1] = { 0 };
870 SECURITY_STATUS ret = NTE_BAD_KEY;
879 WINPR_ASSERT(piv_tag);
881 WINPR_ASSERT(key->provider);
882 p11 = key->provider->p11;
886 WINPR_ASSERT(p11->C_GetSlotInfo);
887 if (p11->C_GetSlotInfo(key->slotId, &slot_info) != CKR_OK)
890 fix_padded_string((
char*)slot_info.slotDescription,
sizeof(slot_info.slotDescription));
891 reader = ConvertUtf8NToWCharAlloc((
char*)slot_info.slotDescription,
892 ARRAYSIZE(slot_info.slotDescription), NULL);
898 if (SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &context) != SCARD_S_SUCCESS)
901 if (SCardConnectW(context, reader, SCARD_SHARE_SHARED, SCARD_PROTOCOL_Tx, &card, &proto) !=
904 pci = (proto == SCARD_PROTOCOL_T0) ? SCARD_PCI_T0 : SCARD_PCI_T1;
906 buf_len =
sizeof(buf);
907 if (SCardTransmit(card, pci, APDU_PIV_SELECT_AID,
sizeof(APDU_PIV_SELECT_AID), NULL, buf,
908 &buf_len) != SCARD_S_SUCCESS)
910 if ((buf[buf_len - 2] != 0x90 || buf[buf_len - 1] != 0) && buf[buf_len - 2] != 0x61)
913 buf_len =
sizeof(buf);
914 if (SCardTransmit(card, pci, APDU_PIV_GET_CHUID,
sizeof(APDU_PIV_GET_CHUID), NULL, buf,
915 &buf_len) != SCARD_S_SUCCESS)
917 if ((buf[buf_len - 2] != 0x90 || buf[buf_len - 1] != 0) && buf[buf_len - 2] != 0x61)
921 WinPrAsn1Decoder_InitMem(&dec, WINPR_ASN1_BER, buf, buf_len);
922 if (!WinPrAsn1DecReadTagAndLen(&dec, &tag, &len) || tag != 0x53)
924 while (WinPrAsn1DecReadTagLenValue(&dec, &tag, &len, &dec2) && tag != 0x34)
926 if (tag != 0x34 || len != 16)
929 s = WinPrAsn1DecGetStream(&dec2);
930 p = Stream_Buffer(&s);
933 (void)snprintf(container_name, PIV_CONTAINER_NAME_LEN + 1,
934 "%.2x%.2x%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x", p[3],
935 p[2], p[1], p[0], p[5], p[4], p[7], p[6], p[8], p[9], p[10], p[11], p[12],
936 piv_tag[0], piv_tag[1], piv_tag[2]);
945 if (ConvertUtf8NToWChar(container_name, ARRAYSIZE(container_name), cnv.wc,
946 output_len /
sizeof(WCHAR)) > 0)
952 SCardDisconnect(card, SCARD_LEAVE_CARD);
954 SCardReleaseContext(context);
958 static SECURITY_STATUS check_for_piv_container_name(NCryptP11KeyHandle* key, BYTE* pbOutput,
959 DWORD cbOutput, DWORD* pcbResult,
char* label,
962 for (
size_t i = 0; i < ARRAYSIZE(piv_cert_tags); i++)
964 const piv_cert_tags_t* cur = &piv_cert_tags[i];
965 if (strncmp(label, cur->label, label_len) == 0)
967 *pcbResult = (PIV_CONTAINER_NAME_LEN + 1) *
sizeof(WCHAR);
969 return ERROR_SUCCESS;
970 else if (cbOutput < (PIV_CONTAINER_NAME_LEN + 1) *
sizeof(WCHAR))
971 return NTE_NO_MEMORY;
973 return get_piv_container_name(key, cur->tag, pbOutput, cbOutput);
976 return NTE_NOT_FOUND;
979 static SECURITY_STATUS NCryptP11KeyGetProperties(NCryptP11KeyHandle* keyHandle,
980 NCryptKeyGetPropertyEnum property, PBYTE pbOutput,
981 DWORD cbOutput, DWORD* pcbResult, DWORD dwFlags)
983 SECURITY_STATUS ret = NTE_FAIL;
985 CK_SESSION_HANDLE session = 0;
986 CK_OBJECT_HANDLE objectHandle = 0;
987 CK_ULONG objectCount = 0;
988 NCryptP11ProviderHandle* provider = NULL;
989 CK_OBJECT_CLASS oclass = CKO_CERTIFICATE;
990 CK_CERTIFICATE_TYPE ctype = CKC_X_509;
991 CK_ATTRIBUTE certificateFilter[] = { { CKA_CLASS, &oclass,
sizeof(oclass) },
992 { CKA_CERTIFICATE_TYPE, &ctype,
sizeof(ctype) },
993 { CKA_ID, keyHandle->keyCertId,
994 keyHandle->keyCertIdLen } };
996 CK_ULONG objectFilterLen = ARRAYSIZE(certificateFilter);
998 WINPR_ASSERT(keyHandle);
999 provider = keyHandle->provider;
1000 WINPR_ASSERT(provider);
1005 case NCRYPT_PROPERTY_CERTIFICATE:
1006 case NCRYPT_PROPERTY_NAME:
1008 case NCRYPT_PROPERTY_READER:
1012 WINPR_ASSERT(provider->p11->C_GetSlotInfo);
1013 rv = provider->p11->C_GetSlotInfo(keyHandle->slotId, &slotInfo);
1017 #define SLOT_DESC_SZ sizeof(slotInfo.slotDescription)
1018 fix_padded_string((
char*)slotInfo.slotDescription, SLOT_DESC_SZ);
1019 const size_t len = 2ULL * (strnlen((
char*)slotInfo.slotDescription, SLOT_DESC_SZ) + 1);
1020 if (len > UINT32_MAX)
1021 return NTE_BAD_DATA;
1022 *pcbResult = (UINT32)len;
1031 if (cbOutput < *pcbResult)
1032 return NTE_NO_MEMORY;
1034 if (ConvertUtf8ToWChar((
char*)slotInfo.slotDescription, cnv.wc,
1035 cbOutput /
sizeof(WCHAR)) < 0)
1036 return NTE_NO_MEMORY;
1038 return ERROR_SUCCESS;
1040 case NCRYPT_PROPERTY_SLOTID:
1045 UINT32* ptr = (UINT32*)pbOutput;
1048 return NTE_NO_MEMORY;
1049 if (keyHandle->slotId > UINT32_MAX)
1054 *ptr = (UINT32)keyHandle->slotId;
1056 return ERROR_SUCCESS;
1058 case NCRYPT_PROPERTY_UNKNOWN:
1060 return NTE_NOT_SUPPORTED;
1063 WINPR_ASSERT(provider->p11->C_OpenSession);
1064 rv = provider->p11->C_OpenSession(keyHandle->slotId, CKF_SERIAL_SESSION, NULL, NULL, &session);
1067 WLog_ERR(TAG,
"error opening session on slot %d", keyHandle->slotId);
1071 WINPR_ASSERT(provider->p11->C_FindObjectsInit);
1072 rv = provider->p11->C_FindObjectsInit(session, objectFilter, objectFilterLen);
1075 WLog_ERR(TAG,
"unable to initiate search for slot %d", keyHandle->slotId);
1079 WINPR_ASSERT(provider->p11->C_FindObjects);
1080 rv = provider->p11->C_FindObjects(session, &objectHandle, 1, &objectCount);
1083 WLog_ERR(TAG,
"unable to findObjects for slot %d", keyHandle->slotId);
1088 ret = NTE_NOT_FOUND;
1094 case NCRYPT_PROPERTY_CERTIFICATE:
1096 CK_ATTRIBUTE certValue = { CKA_VALUE, pbOutput, cbOutput };
1098 WINPR_ASSERT(provider->p11->C_GetAttributeValue);
1099 rv = provider->p11->C_GetAttributeValue(session, objectHandle, &certValue, 1);
1105 if (certValue.ulValueLen > UINT32_MAX)
1110 *pcbResult = (UINT32)certValue.ulValueLen;
1111 ret = ERROR_SUCCESS;
1114 case NCRYPT_PROPERTY_NAME:
1119 WINPR_ASSERT(provider->p11->C_GetAttributeValue);
1120 rv = provider->p11->C_GetAttributeValue(session, objectHandle, &attr, 1);
1123 label = calloc(1, attr.ulValueLen);
1126 ret = NTE_NO_MEMORY;
1130 attr.pValue = label;
1131 rv = provider->p11->C_GetAttributeValue(session, objectHandle, &attr, 1);
1137 ret = check_for_piv_container_name(keyHandle, pbOutput, cbOutput, pcbResult, label,
1141 if (ret == NTE_NOT_FOUND)
1148 const size_t olen = pbOutput ? cbOutput /
sizeof(WCHAR) : 0;
1150 SSIZE_T size = ConvertUtf8NToWChar(label, attr.ulValueLen, cnv.wc, olen);
1152 ret = ERROR_CONVERT_TO_LARGE;
1154 ret = ERROR_SUCCESS;
1162 ret = NTE_NOT_SUPPORTED;
1167 WINPR_ASSERT(provider->p11->C_FindObjectsFinal);
1168 rv = provider->p11->C_FindObjectsFinal(session);
1171 WLog_ERR(TAG,
"error in C_FindObjectsFinal() for slot %d", keyHandle->slotId);
1174 WINPR_ASSERT(provider->p11->C_CloseSession);
1175 rv = provider->p11->C_CloseSession(session);
1178 WLog_ERR(TAG,
"error in C_CloseSession() for slot %d", keyHandle->slotId);
1183 static SECURITY_STATUS NCryptP11GetProperty(NCRYPT_HANDLE hObject, NCryptKeyGetPropertyEnum prop,
1184 PBYTE pbOutput, DWORD cbOutput, DWORD* pcbResult,
1192 case WINPR_NCRYPT_PROVIDER:
1193 return ERROR_CALL_NOT_IMPLEMENTED;
1194 case WINPR_NCRYPT_KEY:
1195 return NCryptP11KeyGetProperties((NCryptP11KeyHandle*)hObject, prop, pbOutput, cbOutput,
1196 pcbResult, dwFlags);
1198 return ERROR_INVALID_HANDLE;
1200 return ERROR_SUCCESS;
1203 static SECURITY_STATUS NCryptP11OpenKey(NCRYPT_PROV_HANDLE hProvider, NCRYPT_KEY_HANDLE* phKey,
1204 LPCWSTR pszKeyName, DWORD dwLegacyKeySpec, DWORD dwFlags)
1206 SECURITY_STATUS ret = 0;
1207 CK_SLOT_ID slotId = 0;
1208 CK_BYTE keyCertId[64] = { 0 };
1209 CK_ULONG keyCertIdLen = 0;
1210 NCryptP11KeyHandle* keyHandle = NULL;
1212 ret = parseKeyName(pszKeyName, &slotId, keyCertId, &keyCertIdLen);
1213 if (ret != ERROR_SUCCESS)
1216 keyHandle = (NCryptP11KeyHandle*)ncrypt_new_handle(
1217 WINPR_NCRYPT_KEY,
sizeof(*keyHandle), NCryptP11GetProperty, winpr_NCryptDefault_dtor);
1219 return NTE_NO_MEMORY;
1221 keyHandle->provider = (NCryptP11ProviderHandle*)hProvider;
1222 keyHandle->slotId = slotId;
1223 memcpy(keyHandle->keyCertId, keyCertId,
sizeof(keyCertId));
1224 keyHandle->keyCertIdLen = keyCertIdLen;
1225 *phKey = (NCRYPT_KEY_HANDLE)keyHandle;
1226 return ERROR_SUCCESS;
1229 static SECURITY_STATUS initialize_pkcs11(HANDLE handle,
1230 CK_RV (*c_get_function_list)(CK_FUNCTION_LIST_PTR_PTR),
1231 NCRYPT_PROV_HANDLE* phProvider)
1233 SECURITY_STATUS status = ERROR_SUCCESS;
1234 NCryptP11ProviderHandle* ret = NULL;
1237 WINPR_ASSERT(c_get_function_list);
1238 WINPR_ASSERT(phProvider);
1240 ret = (NCryptP11ProviderHandle*)ncrypt_new_handle(
1241 WINPR_NCRYPT_PROVIDER,
sizeof(*ret), NCryptP11GetProperty, NCryptP11StorageProvider_dtor);
1243 return NTE_NO_MEMORY;
1245 ret->library = handle;
1246 ret->baseProvider.enumKeysFn = NCryptP11EnumKeys;
1247 ret->baseProvider.openKeyFn = NCryptP11OpenKey;
1249 rv = c_get_function_list(&ret->p11);
1252 status = NTE_PROVIDER_DLL_FAIL;
1256 WINPR_ASSERT(ret->p11);
1257 WINPR_ASSERT(ret->p11->C_Initialize);
1258 rv = ret->p11->C_Initialize(NULL);
1261 status = NTE_PROVIDER_DLL_FAIL;
1265 *phProvider = (NCRYPT_PROV_HANDLE)ret;
1268 if (status != ERROR_SUCCESS)
1269 ret->baseProvider.baseHandle.releaseFn((NCRYPT_HANDLE)ret);
1273 SECURITY_STATUS NCryptOpenP11StorageProviderEx(NCRYPT_PROV_HANDLE* phProvider,
1274 LPCWSTR pszProviderName, DWORD dwFlags,
1275 LPCSTR* modulePaths)
1277 SECURITY_STATUS status = ERROR_INVALID_PARAMETER;
1278 LPCSTR defaultPaths[] = {
"p11-kit-proxy.so",
"opensc-pkcs11.so", NULL };
1281 return ERROR_INVALID_PARAMETER;
1284 modulePaths = defaultPaths;
1286 while (*modulePaths)
1288 const char* modulePath = *modulePaths++;
1289 HANDLE library = LoadLibrary(modulePath);
1290 typedef CK_RV (*c_get_function_list_t)(CK_FUNCTION_LIST_PTR_PTR);
1291 NCryptP11ProviderHandle* provider = NULL;
1293 WLog_DBG(TAG,
"Trying pkcs11 module '%s'", modulePath);
1296 status = NTE_PROV_DLL_NOT_FOUND;
1297 goto out_load_library;
1300 c_get_function_list_t c_get_function_list =
1301 GetProcAddressAs(library,
"C_GetFunctionList", c_get_function_list_t);
1303 if (!c_get_function_list)
1305 status = NTE_PROV_TYPE_ENTRY_BAD;
1306 goto out_load_library;
1309 status = initialize_pkcs11(library, c_get_function_list, phProvider);
1310 if (status != ERROR_SUCCESS)
1312 status = NTE_PROVIDER_DLL_FAIL;
1313 goto out_load_library;
1316 provider = (NCryptP11ProviderHandle*)*phProvider;
1317 provider->modulePath = _strdup(modulePath);
1318 if (!provider->modulePath)
1320 status = NTE_NO_MEMORY;
1321 goto out_load_library;
1324 WLog_DBG(TAG,
"module '%s' loaded", modulePath);
1325 return ERROR_SUCCESS;
1329 FreeLibrary(library);
1335 const char* NCryptGetModulePath(NCRYPT_PROV_HANDLE phProvider)
1337 NCryptP11ProviderHandle* provider = (NCryptP11ProviderHandle*)phProvider;
1339 WINPR_ASSERT(provider);
1341 return provider->modulePath;
common ncrypt handle items
common ncrypt provider items