winpr: implement ncrypt API

This implements the emulation for the ncrypt API and more specifically the smartcard
provider so that we can list available keys and certificates using pkcs11-helper.
This commit is contained in:
David Fort 2021-12-07 00:07:57 +01:00 committed by akallabeth
parent a6cadd6f97
commit d4020e2328
15 changed files with 1560 additions and 93 deletions

24
cmake/FindPkcs11.cmake Normal file
View File

@ -0,0 +1,24 @@
# - Try to find Pkcs11-helper
# Using Pkg-config if available for path
#
# PKCS11_FOUND - all required ffmpeg components found on system
# PKCS11_INCLUDE_DIRS - combined include directories
# PKCS11_LIBRARIES - combined libraries to link
include(FindPkgConfig)
if (PKG_CONFIG_FOUND)
pkg_check_modules(PKCS11 libpkcs11-helper-1)
endif()
find_path(PKCS11_INCLUDE_DIR pkcs11-helper-1.0/pkcs11.h PATHS ${PKCS11_INCLUDE_DIRS})
find_library(PKCS11_LIBRARY pkcs11-helper PATHS ${PKCS11_LIBRARY_DIRS})
if (PKCS11_INCLUDE_DIR AND PKCS11_LIBRARY)
set(PKCS11_FOUND TRUE)
endif()
# include(FindPackageHandleStandardArgs)
# FIND_PACKAGE_HANDLE_STANDARD_ARGS(FFmpeg DEFAULT_MSG AVUTIL_FOUND AVCODEC_FOUND SWRESAMPLE_FOUND)

View File

@ -137,57 +137,57 @@ else()
set(WINPR_HAVE_STDBOOL_H 1)
endif()
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
if(NOT IOS)
find_package(Threads REQUIRED)
if(NOT IOS)
find_package(Threads REQUIRED)
endif()
# Include files
if(NOT IOS)
check_include_files(fcntl.h HAVE_FCNTL_H)
check_include_files(aio.h HAVE_AIO_H)
check_include_files(sys/timerfd.h HAVE_SYS_TIMERFD_H)
check_include_files(unistd.h HAVE_UNISTD_H)
check_include_files(inttypes.h HAVE_INTTYPES_H)
check_include_files(sys/filio.h HAVE_SYS_FILIO_H)
check_include_files(sys/sockio.h HAVE_SYS_SOCKIO_H)
check_include_files(syslog.h HAVE_SYSLOG_H)
check_include_files(sys/select.h HAVE_SYS_SELECT_H)
check_include_files(sys/eventfd.h HAVE_SYS_EVENTFD_H)
if (HAVE_SYS_EVENTFD_H)
check_symbol_exists(eventfd_read sys/eventfd.h WITH_EVENTFD_READ_WRITE)
endif()
else()
set(HAVE_FCNTL_H 1)
set(HAVE_UNISTD_H 1)
set(HAVE_INTTYPES_H 1)
set(HAVE_SYS_FILIO_H 1)
endif()
# Include files
if(NOT IOS)
check_include_files(fcntl.h HAVE_FCNTL_H)
check_include_files(aio.h HAVE_AIO_H)
check_include_files(sys/timerfd.h HAVE_SYS_TIMERFD_H)
check_include_files(unistd.h HAVE_UNISTD_H)
check_include_files(inttypes.h HAVE_INTTYPES_H)
check_include_files(sys/filio.h HAVE_SYS_FILIO_H)
check_include_files(sys/sockio.h HAVE_SYS_SOCKIO_H)
check_include_files(syslog.h HAVE_SYSLOG_H)
check_include_files(sys/select.h HAVE_SYS_SELECT_H)
check_include_files(sys/eventfd.h HAVE_SYS_EVENTFD_H)
if (HAVE_SYS_EVENTFD_H)
check_symbol_exists(eventfd_read sys/eventfd.h WITH_EVENTFD_READ_WRITE)
endif()
else()
set(HAVE_FCNTL_H 1)
set(HAVE_UNISTD_H 1)
set(HAVE_INTTYPES_H 1)
set(HAVE_SYS_FILIO_H 1)
endif()
if(NOT IOS)
check_struct_has_member("struct tm" tm_gmtoff time.h HAVE_TM_GMTOFF)
else()
set(HAVE_TM_GMTOFF 1)
endif()
if(NOT IOS)
check_struct_has_member("struct tm" tm_gmtoff time.h HAVE_TM_GMTOFF)
else()
set(HAVE_TM_GMTOFF 1)
endif()
if(NOT WIN32 AND NOT IOS)
if (NOT HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB)
CHECK_LIBRARY_EXISTS(pthreads pthread_mutex_timedlock "" HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIBS)
endif (NOT HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB)
if(NOT WIN32 AND NOT IOS)
if (NOT HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB)
CHECK_LIBRARY_EXISTS(pthreads pthread_mutex_timedlock "" HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIBS)
endif (NOT HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB)
if (NOT HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL)
CHECK_LIBRARY_EXISTS(pthread pthread_mutex_timedlock "" HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB)
endif (NOT HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL)
if (NOT HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL)
CHECK_LIBRARY_EXISTS(pthread pthread_mutex_timedlock "" HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB)
endif (NOT HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL)
list(APPEND CMAKE_REQUIRED_LIBRARIES pthread)
CHECK_SYMBOL_EXISTS(pthread_mutex_timedlock pthread.h HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL)
list(APPEND CMAKE_REQUIRED_LIBRARIES pthread)
CHECK_SYMBOL_EXISTS(pthread_mutex_timedlock pthread.h HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL)
if (HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL OR HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB OR HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIBS)
set(HAVE_PTHREAD_MUTEX_TIMEDLOCK ON)
endif (HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL OR HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB OR HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIBS)
list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES pthread)
endif()
if (HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL OR HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB OR HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIBS)
set(HAVE_PTHREAD_MUTEX_TIMEDLOCK ON)
endif (HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL OR HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB OR HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIBS)
list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES pthread)
endif()
set(OPENSSL_FEATURE_TYPE "RECOMMENDED")
set(OPENSSL_FEATURE_PURPOSE "cryptography")
@ -227,6 +227,17 @@ set(OPENSSL_FEATURE_TYPE "RECOMMENDED")
set(TESTING_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/Testing")
endif()
if (NOT WIN32)
set(P11_FEATURE_TYPE "OPTIONAL")
set(P11_FEATURE_PURPOSE "PKCS11")
set(P11_FEATURE_DESCRIPTION "encryption, certificate validation, hashing functions")
find_feature(Pkcs11 ${P11_FEATURE_TYPE} ${P11_FEATURE_PURPOSE} ${P11_FEATURE_DESCRIPTION})
if (PKCS11_FOUND)
add_definitions("-DWITH_PKCS11")
endif()
endif()
# Default to release build type
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release")

View File

@ -20,6 +20,10 @@
#ifndef WINPR_BCRYPT_H
#define WINPR_BCRYPT_H
#ifdef _WIN32
#include <bcrypt.h>
#else
#include <winpr/winpr.h>
#include <winpr/wtypes.h>
@ -29,59 +33,92 @@ typedef PVOID BCRYPT_KEY_HANDLE;
typedef PVOID BCRYPT_HASH_HANDLE;
typedef PVOID BCRYPT_SECRET_HANDLE;
#define BCRYPT_RSA_ALGORITHM L"RSA"
#define BCRYPT_RSA_SIGN_ALGORITHM L"RSA_SIGN"
#define BCRYPT_DH_ALGORITHM L"DH"
#define BCRYPT_DSA_ALGORITHM L"DSA"
#define BCRYPT_RC2_ALGORITHM L"RC2"
#define BCRYPT_RC4_ALGORITHM L"RC4"
#define BCRYPT_AES_ALGORITHM L"AES"
#define BCRYPT_DES_ALGORITHM L"DES"
#define BCRYPT_DESX_ALGORITHM L"DESX"
#define BCRYPT_3DES_ALGORITHM L"3DES"
#define BCRYPT_3DES_112_ALGORITHM L"3DES_112"
#define BCRYPT_MD2_ALGORITHM L"MD2"
#define BCRYPT_MD4_ALGORITHM L"MD4"
#define BCRYPT_MD5_ALGORITHM L"MD5"
#define BCRYPT_SHA1_ALGORITHM L"SHA1"
#define BCRYPT_SHA256_ALGORITHM L"SHA256"
#define BCRYPT_SHA384_ALGORITHM L"SHA384"
#define BCRYPT_SHA512_ALGORITHM L"SHA512"
#define BCRYPT_AES_GMAC_ALGORITHM L"AES-GMAC"
#define BCRYPT_ECDSA_P256_ALGORITHM L"ECDSA_P256"
#define BCRYPT_ECDSA_P384_ALGORITHM L"ECDSA_P384"
#define BCRYPT_ECDSA_P521_ALGORITHM L"ECDSA_P521"
#define BCRYPT_ECDH_P256_ALGORITHM L"ECDH_P256"
#define BCRYPT_ECDH_P384_ALGORITHM L"ECDH_P384"
#define BCRYPT_ECDH_P521_ALGORITHM L"ECDH_P521"
#define BCRYPT_RNG_ALGORITHM L"RNG"
#define BCRYPT_RNG_FIPS186_DSA_ALGORITHM L"FIPS186DSARNG"
#define BCRYPT_RNG_DUAL_EC_ALGORITHM L"DUALECRNG"
#define BCRYPT_RSA_ALGORITHM (const WCHAR*)"R\x00S\x00A\x00\x00"
#define BCRYPT_RSA_SIGN_ALGORITHM (const WCHAR*)"R\x00S\x00A\x00_\x00S\x00I\x00G\x00N\x00\x00"
#define BCRYPT_DH_ALGORITHM (const WCHAR*)"D\x00H\x00\x00"
#define BCRYPT_DSA_ALGORITHM (const WCHAR*)"D\x00S\x00A\x00\x00"
#define BCRYPT_RC2_ALGORITHM (const WCHAR*)"R\x00C\x002\x00\x00"
#define BCRYPT_RC4_ALGORITHM (const WCHAR*)"R\x00C\x004\x00\x00"
#define BCRYPT_AES_ALGORITHM (const WCHAR*)"A\x00E\x00S\x00\x00"
#define BCRYPT_DES_ALGORITHM (const WCHAR*)"D\x00E\x00S\x00\x00"
#define BCRYPT_DESX_ALGORITHM (const WCHAR*)"D\x00E\x00S\x00X\x00\x00"
#define BCRYPT_3DES_ALGORITHM (const WCHAR*)"3\x00D\x00E\x00S\x00\x00"
#define BCRYPT_3DES_112_ALGORITHM (const WCHAR*)"3\x00D\x00E\x00S\x00_\x001\x001\x002\x00\x00"
#define BCRYPT_MD2_ALGORITHM (const WCHAR*)"M\x00D\x002\x00\x00"
#define BCRYPT_MD4_ALGORITHM (const WCHAR*)"M\x00D\x004\x00\x00"
#define BCRYPT_MD5_ALGORITHM (const WCHAR*)"M\x00D\x005\x00\x00"
#define BCRYPT_SHA1_ALGORITHM (const WCHAR*)"S\x00H\x00A\x001\x00\x00"
#define BCRYPT_SHA256_ALGORITHM (const WCHAR*)"S\x00H\x00A\x002\x005\x006\x00\x00"
#define BCRYPT_SHA384_ALGORITHM (const WCHAR*)"S\x00H\x00A\x003\x008\x004\x00\x00"
#define BCRYPT_SHA512_ALGORITHM (const WCHAR*)"S\x00H\x00A\x005\x001\x002\x00\x00"
#define BCRYPT_AES_GMAC_ALGORITHM (const WCHAR*)"A\x00E\x00S\x00-\x00G\x00M\x00A\x00C\x00\x00"
#define BCRYPT_ECDSA_ALGORITHM (const WCHAR*)"E\x00C\x00D\x00S\x00A\x00\x00"
#define BCRYPT_ECDSA_P256_ALGORITHM \
(const WCHAR*)"E\x00C\x00D\x00S\x00A\x00_\x00P\x002\x005\x006\x00\x00"
#define BCRYPT_ECDSA_P384_ALGORITHM \
(const WCHAR*)"E\x00C\x00D\x00S\x00A\x00_\x00P\x003\x008\x004\x00\x00"
#define BCRYPT_ECDSA_P521_ALGORITHM \
(const WCHAR*)"E\x00C\x00D\x00S\x00A\x00_\x00P\x005\x002\x001\x00\x00"
#define BCRYPT_ECDH_P256_ALGORITHM \
(const WCHAR*)"E\x00C\x00D\x00S\x00A\x00_\x00P\x002\x005\x006\x00\x00"
#define BCRYPT_ECDH_P384_ALGORITHM \
(const WCHAR*)"E\x00C\x00D\x00S\x00A\x00_\x00P\x003\x008\x004\x00\x00"
#define BCRYPT_ECDH_P521_ALGORITHM \
(const WCHAR*)"E\x00C\x00D\x00S\x00A\x00_\x00P\x005\x002\x001\x00\x00"
#define BCRYPT_RNG_ALGORITHM (const WCHAR*)"R\x00N\x00G\x00\x00"
#define BCRYPT_RNG_FIPS186_DSA_ALGORITHM \
(const WCHAR*)"F\x00I\x00P\x00S\x001\x008\x006\x00D\x00S\x00A\x00R\x00N\x00G\x00\x00"
#define BCRYPT_RNG_DUAL_EC_ALGORITHM (const WCHAR*)"D\x00U\x00A\x00L\x00E\x00R\x00N\x00G\x00\x00"
#define MS_PRIMITIVE_PROVIDER L"Microsoft Primitive Provider"
#define MS_PRIMITIVE_PROVIDER \
(const WCHAR*)"M\x00i\x00c\x00r\x00o\x00s\x00o\x00f\x00t\x00 " \
"\x00P\x00r\x00i\x00m\x00i\x00t\x00i\x00v\x00e\x00 " \
"\x00P\x00r\x00o\x00v\x00i\x00d\x00e\x00r\x00\x00"
#define BCRYPT_ALG_HANDLE_HMAC_FLAG 0x00000008
#define BCRYPT_PROV_DISPATCH 0x00000001
#define BCRYPT_OBJECT_LENGTH L"ObjectLength"
#define BCRYPT_ALGORITHM_NAME L"AlgorithmName"
#define BCRYPT_PROVIDER_HANDLE L"ProviderHandle"
#define BCRYPT_CHAINING_MODE L"ChainingMode"
#define BCRYPT_BLOCK_LENGTH L"BlockLength"
#define BCRYPT_KEY_LENGTH L"KeyLength"
#define BCRYPT_KEY_OBJECT_LENGTH L"KeyObjectLength"
#define BCRYPT_KEY_STRENGTH L"KeyStrength"
#define BCRYPT_KEY_LENGTHS L"KeyLengths"
#define BCRYPT_BLOCK_SIZE_LIST L"BlockSizeList"
#define BCRYPT_EFFECTIVE_KEY_LENGTH L"EffectiveKeyLength"
#define BCRYPT_HASH_LENGTH L"HashDigestLength"
#define BCRYPT_HASH_OID_LIST L"HashOIDList"
#define BCRYPT_PADDING_SCHEMES L"PaddingSchemes"
#define BCRYPT_SIGNATURE_LENGTH L"SignatureLength"
#define BCRYPT_HASH_BLOCK_LENGTH L"HashBlockLength"
#define BCRYPT_AUTH_TAG_LENGTH L"AuthTagLength"
#define BCRYPT_PRIMITIVE_TYPE L"PrimitiveType"
#define BCRYPT_IS_KEYED_HASH L"IsKeyedHash"
#define BCRYPT_OBJECT_LENGTH \
(const WCHAR*)"O\x00b\x00j\x00e\x00c\x00t\x00L\x00e\x00n\x00g\x00t\x00h\x00\x00"
#define BCRYPT_ALGORITHM_NAME \
(const WCHAR*)"A\x00l\x00g\x00o\x00r\x00i\x00t\x00h\x00m\x00N\x00a\x00m\x00e\x00\x00"
#define BCRYPT_PROVIDER_HANDLE \
(const WCHAR*)"P\x00r\x00o\x00v\x00i\x00d\x00e\x00r\x00H\x00a\x00n\x00d\x00l\x00e\x00\x00"
#define BCRYPT_CHAINING_MODE \
(const WCHAR*)"C\x00h\x00a\x00i\x00n\x00i\x00n\x00g\x00M\x00o\x00d\x00e\x00\x00"
#define BCRYPT_BLOCK_LENGTH \
(const WCHAR*)"B\x00l\x00o\x00c\x00k\x00L\x00e\x00n\x00g\x00t\x00h\x00\x00"
#define BCRYPT_KEY_LENGTH (const WCHAR*)"K\x00e\x00y\x00L\x00e\x00n\x00g\x00t\x00h\x00\x00"
#define BCRYPT_KEY_OBJECT_LENGTH \
(const WCHAR*)"K\x00e\x00y\x00O\x00b\x00j\x00e\x00c\x00t\x00L\x00e\x00n\x00g\x00t\x00h\x00" \
"\x00"
#define BCRYPT_KEY_STRENGTH \
(const WCHAR*)"K\x00e\x00y\x00S\x00t\x00r\x00e\x00n\x00g\x00t\x00h\x00\x00"
#define BCRYPT_KEY_LENGTHS (const WCHAR*)"K\x00e\x00y\x00L\x00e\x00n\x00g\x00t\x00h\x00s\x00\x00"
#define BCRYPT_BLOCK_SIZE_LIST \
(const WCHAR*)"B\x00l\x00o\x00c\x00k\x00S\x00i\x00z\x00e\x00L\x00i\x00s\x00t\x00\x00"
#define BCRYPT_EFFECTIVE_KEY_LENGTH \
(const WCHAR*)"E\x00f\x00f\x00e\x00c\x00t\x00i\x00v\x00e\x00K\x00e\x00y\x00L\x00e\x00n\x00g" \
"\x00t\x00h\x00\x00"
#define BCRYPT_HASH_LENGTH \
(const WCHAR*)"H\x00a\x00s\x00h\x00D\x00i\x00g\x00e\x00s\x00t\x00L\x00e\x00n\x00g\x00t\x00h" \
"\x00\x00"
#define BCRYPT_HASH_OID_LIST \
(const WCHAR*)"H\x00a\x00s\x00h\x00O\x00I\x00D\x00L\x00i\x00s\x00t\x00\x00"
#define BCRYPT_PADDING_SCHEMES \
(const WCHAR*)"P\x00a\x00d\x00d\x00i\x00n\x00g\x00S\x00c\x00h\x00e\x00m\x00e\x00s\x00\x00"
#define BCRYPT_SIGNATURE_LENGTH \
(const WCHAR*)"S\x00i\x00g\x00n\x00a\x00t\x00u\x00r\x00e\x00L\x00e\x00n\x00g\x00t\x00h\x00" \
"\x00"
#define BCRYPT_HASH_BLOCK_LENGTH \
(const WCHAR*)"H\x00a\x00s\x00h\x00B\x00l\x00o\x00c\x00k\x00L\x00e\x00n\x00g\x00t\x00h\x00" \
"\x00"
#define BCRYPT_AUTH_TAG_LENGTH \
(const WCHAR*)"A\x00u\x00t\x00h\x00T\x00a\x00g\x00L\x00e\x00n\x00g\x00t\x00h\x00\x00"
#define BCRYPT_PRIMITIVE_TYPE \
(const WCHAR*)"P\x00r\x00i\x00m\x00i\x00t\x00i\x00v\x00e\x00T\x00y\x00p\x00e\x00\x00"
#define BCRYPT_IS_KEYED_HASH \
(const WCHAR*)"I\x00s\x00K\x00e\x00y\x00e\x00d\x00H\x00a\x00s\x00h\x00\x00"
#ifdef __cplusplus
extern "C"
@ -138,4 +175,6 @@ extern "C"
#ifdef __cplusplus
}
#endif
#endif /* _WIN32 */
#endif /* WINPR_BCRYPT_MEMORY_H */

View File

@ -275,6 +275,16 @@ typedef struct _CERT_CONTEXT
} CERT_CONTEXT, *PCERT_CONTEXT;
typedef const CERT_CONTEXT* PCCERT_CONTEXT;
#if !defined(AT_KEYEXCHANGE)
#define AT_KEYEXCHANGE (1)
#endif
#if !defined(AT_SIGNATURE)
#define AT_SIGNATURE (2)
#endif
#if !defined(AT_AUTHENTICATE)
#define AT_AUTHENTICATE (3)
#endif
#define CERT_ENCODING_TYPE_MASK 0x0000FFFF
#define CMSG_ENCODING_TYPE_MASK 0xFFFF0000
#define GET_CERT_ENCODING_TYPE(x) (x & CERT_ENCODING_TYPE_MASK)

View File

@ -2990,6 +2990,46 @@
#define WS_E_SECURITY_SYSTEM_FAILURE 0x803D0023
#endif
#define NTE_BAD_UID (0x80090001)
#define NTE_BAD_HASH (0x80090002)
#define NTE_BAD_KEY (0x80090003)
#define NTE_BAD_LEN (0x80090004)
#define NTE_BAD_DATA (0x80090005)
#define NTE_BAD_SIGNATURE (0x80090006)
#define NTE_BAD_VER (0x80090007)
#define NTE_BAD_ALGID (0x80090008)
#define NTE_BAD_FLAGS (0x80090009)
#define NTE_BAD_TYPE (0x8009000A)
#define NTE_BAD_KEY_STATE (0x8009000B)
#define NTE_BAD_HASH_STATE (0x8009000C)
#define NTE_NO_KEY (0x8009000D)
#define NTE_NO_MEMORY (0x8009000E)
#define NTE_EXISTS (0x8009000F)
#define NTE_PERM (0x80090010)
#define NTE_NOT_FOUND (0x80090011)
#define NTE_DOUBLE_ENCRYPT (0x80090012)
#define NTE_BAD_PROVIDER (0x80090013)
#define NTE_BAD_PROV_TYPE (0x80090014)
#define NTE_BAD_PUBLIC_KEY (0x80090015)
#define NTE_BAD_KEYSET (0x80090016)
#define NTE_PROV_TYPE_NOT_DEF (0x80090017)
#define NTE_PROV_TYPE_ENTRY_BAD (0x80090018)
#define NTE_KEYSET_NOT_DEF (0x80090019)
#define NTE_KEYSET_ENTRY_BAD (0x8009001A)
#define NTE_PROV_TYPE_NO_MATCH (0x8009001B)
#define NTE_SIGNATURE_FILE_BAD (0x8009001C)
#define NTE_PROVIDER_DLL_FAIL (0x8009001D)
#define NTE_PROV_DLL_NOT_FOUND (0x8009001E)
#define NTE_BAD_KEYSET_PARAM (0x8009001F)
#define NTE_FAIL (0x80090020)
#define NTE_SYS_ERR (0x80090021)
#define NTE_SILENT_CONTEXT (0x80090022)
#define NTE_TOKEN_KEYSET_STORAGE_FULL (0x80090023)
#define NTE_TEMPORARY_PROFILE (0x80090024)
#define NTE_FIXEDPARAMETER (0x80090025)
#define NTE_NO_MORE_ITEMS ERROR_NO_MORE_ITEMS
#define NTE_NOT_SUPPORTED ERROR_NOT_SUPPORTED
#define EXCEPTION_MAXIMUM_PARAMETERS 15
typedef struct _EXCEPTION_RECORD EXCEPTION_RECORD;

View File

@ -0,0 +1,123 @@
/**
* WinPR: Windows Portable Runtime
* NCrypt library
*
* Copyright 2021 David Fort <contact@hardening-consulting.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WINPR_INCLUDE_WINPR_NCRYPT_H_
#define WINPR_INCLUDE_WINPR_NCRYPT_H_
#ifdef _WIN32
#include <wincrypt.h>
#include <ncrypt.h>
#else
#include <winpr/wtypes.h>
#ifndef __SECSTATUS_DEFINED__
typedef LONG SECURITY_STATUS;
#define __SECSTATUS_DEFINED__
#endif
typedef ULONG_PTR NCRYPT_HANDLE;
typedef ULONG_PTR NCRYPT_PROV_HANDLE;
typedef ULONG_PTR NCRYPT_KEY_HANDLE;
#define MS_KEY_STORAGE_PROVIDER \
(const WCHAR*)"M\x00i\x00c\x00r\x00o\x00s\x00o\x00f\x00t\x00 " \
"\x00S\x00o\x00f\x00t\x00w\x00a\x00r\x00e\x00 \x00K\x00e\x00y\x00 " \
"\x00S\x00t\x00o\x00r\x00a\x00g\x00e\x00 " \
"\x00P\x00r\x00o\x00v\x00i\x00d\x00e\x00r\x00\x00"
#define MS_SMART_CARD_KEY_STORAGE_PROVIDER \
(const WCHAR*)"M\x00i\x00c\x00r\x00o\x00s\x00o\x00f\x00t\x00 \x00S\x00m\x00a\x00r\x00t\x00 " \
"\x00C\x00a\x00r\x00d\x00 \x00K\x00e\x00y\x00 " \
"\x00S\x00t\x00o\x00r\x00a\x00g\x00e\x00 " \
"\x00P\x00r\x00o\x00v\x00i\x00d\x00e\x00r\x00"
#define MS_SCARD_PROV \
(const WCHAR*)"M\x00i\x00c\x00r\x00o\x00s\x00o\x00f\x00t\x00 \x00B\x00a\x00s\x00e\x00 " \
"\x00S\x00m\x00a\x00r\x00t\x00 \x00C\x00a\x00r\x00d\x00 " \
"\x00C\x00r\x00y\x00p\x00t\x00o\x00 " \
"\x00P\x00r\x00o\x00v\x00i\x00d\x00e\x00r\x00\x00"
#define MS_PLATFORM_KEY_STORAGE_PROVIDER \
(const WCHAR*)"M\x00i\x00c\x00r\x00o\x00s\x00o\x00f\x00t\x00 " \
"\x00P\x00l\x00a\x00t\x00f\x00o\x00r\x00m\x00 " \
"\x00C\x00r\x00y\x00p\x00t\x00o\x00 " \
"\x00P\x00r\x00o\x00v\x00i\x00d\x00e\x00r\x00\x00"
#define NCRYPT_CERTIFICATE_PROPERTY \
(const WCHAR*)"S\x00m\x00a\x00r\x00t\x00C\x00a\x00r\x00d\x00K\x00e\x00y\x00C\x00e\x00r\x00t" \
"\x00i\x00f\x00i\x00c\x00a\x00t\x00e\x00\x00"
#define NCRYPT_MACHINE_KEY_FLAG 0x20
#define NCRYPT_SILENT_FLAG 0x40
/** @brief a key name descriptor */
typedef struct NCryptKeyName
{
LPWSTR pszName;
LPWSTR pszAlgid;
DWORD dwLegacyKeySpec;
DWORD dwFlags;
} NCryptKeyName;
#ifdef __cplusplus
extern "C"
{
#endif
SECURITY_STATUS NCryptOpenStorageProvider(NCRYPT_PROV_HANDLE* phProvider,
LPCWSTR pszProviderName, DWORD dwFlags);
SECURITY_STATUS NCryptEnumKeys(NCRYPT_PROV_HANDLE hProvider, LPCWSTR pszScope,
NCryptKeyName** ppKeyName, PVOID* ppEnumState, DWORD dwFlags);
SECURITY_STATUS NCryptOpenKey(NCRYPT_PROV_HANDLE hProvider, NCRYPT_KEY_HANDLE* phKey,
LPCWSTR pszKeyName, DWORD dwLegacyKeySpec, DWORD dwFlags);
SECURITY_STATUS NCryptGetProperty(NCRYPT_HANDLE hObject, LPCWSTR pszProperty, PBYTE pbOutput,
DWORD cbOutput, DWORD* pcbResult, DWORD dwFlags);
SECURITY_STATUS NCryptFreeObject(NCRYPT_HANDLE hObject);
SECURITY_STATUS NCryptFreeBuffer(PVOID pvInput);
#ifdef __cplusplus
}
#endif
#endif /* _WIN32 */
#ifdef __cplusplus
extern "C"
{
#endif
/**
* custom NCryptOpenStorageProvider that allows to provide a list of modules to load
*
* @param phProvider [out] resulting provider handle
* @param dwFlags [in] the flags to use
* @param modulePaths [in] an array of library path to try to load ended with a NULL string
* @return ERROR_SUCCESS or an NTE error code something failed
*/
SECURITY_STATUS winpr_NCryptOpenStorageProviderEx(NCRYPT_PROV_HANDLE* phProvider,
LPCWSTR pszProviderName, DWORD dwFlags,
LPCSTR* modulePaths);
#ifdef __cplusplus
}
#endif
#endif /* WINPR_INCLUDE_WINPR_NCRYPT_H_ */

View File

@ -96,7 +96,7 @@ endif()
# Level "1" API as defined for MinCore.lib
set(WINPR_CORE synch library file comm pipe interlocked security
environment crypto registry credentials path io memory input shell
environment crypto registry credentials path io memory ncrypt input shell
heap utils error timezone sysinfo pool handle thread)
foreach(DIR ${WINPR_CORE})

View File

@ -21,6 +21,7 @@
#include "config.h"
#endif
#ifndef _WIN32
#include <winpr/bcrypt.h>
/**
@ -111,3 +112,5 @@ NTSTATUS BCryptDecrypt(BCRYPT_KEY_HANDLE hKey, PUCHAR pbInput, ULONG cbInput, VO
{
return 0;
}
#endif /* _WIN32 */

View File

@ -0,0 +1,26 @@
# WinPR: Windows Portable Runtime
# libwinpr-ncrypt cmake build script
#
# Copyright 2021 David Fort <contact@hardening-consulting.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
winpr_module_add(
ncrypt.c
ncrypt.h
ncrypt_pkcs11.c
)
if(BUILD_TESTING)
add_subdirectory(test)
endif()

View File

@ -0,0 +1,9 @@
set(MINWIN_LAYER "1")
set(MINWIN_GROUP "core")
set(MINWIN_MAJOR_VERSION "1")
set(MINWIN_MINOR_VERSION "0")
set(MINWIN_SHORT_NAME "ncrypt")
set(MINWIN_LONG_NAME "NCrypt Functions")
set(MODULE_LIBRARY_NAME "ncrypt")

View File

@ -0,0 +1,222 @@
/**
* WinPR: Windows Portable Runtime
* NCrypt library
*
* Copyright 2021 David Fort <contact@hardening-consulting.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/assert.h>
#include <winpr/ncrypt.h>
#ifndef _WIN32
#include <winpr/print.h>
#include "../log.h"
#include "ncrypt.h"
#define TAG WINPR_TAG("ncrypt")
const static char NCRYPT_MAGIC[6] = { 'N', 'C', 'R', 'Y', 'P', 'T' };
SECURITY_STATUS checkNCryptHandle(NCRYPT_HANDLE handle, NCryptHandleType matchType)
{
NCryptBaseHandle* base;
if (!handle)
return ERROR_INVALID_PARAMETER;
base = (NCryptBaseHandle*)handle;
if (memcmp(base->magic, NCRYPT_MAGIC, 6) != 0)
return ERROR_INVALID_PARAMETER;
switch (base->type)
{
case WINPR_NCRYPT_PROVIDER:
case WINPR_NCRYPT_KEY:
break;
default:
return ERROR_INVALID_PARAMETER;
}
if (matchType != WINPR_NCRYPT_INVALID && base->type != matchType)
return ERROR_INVALID_PARAMETER;
return ERROR_SUCCESS;
}
void* ncrypt_new_handle(NCryptHandleType kind, size_t len, NCryptGetPropertyFn getProp,
NCryptReleaseFn dtor)
{
NCryptBaseHandle* ret = calloc(1, len);
if (!ret)
return NULL;
memcpy(ret->magic, NCRYPT_MAGIC, sizeof(ret->magic));
ret->type = kind;
ret->getPropertyFn = getProp;
ret->releaseFn = dtor;
return ret;
}
SECURITY_STATUS winpr_NCryptDefault_dtor(NCryptBaseHandle* h)
{
memset(h->magic, 0, sizeof(h->magic));
h->type = WINPR_NCRYPT_INVALID;
h->releaseFn = NULL;
free(h);
return ERROR_SUCCESS;
}
SECURITY_STATUS NCryptOpenStorageProvider(NCRYPT_PROV_HANDLE* phProvider, LPCWSTR pszProviderName,
DWORD dwFlags)
{
#ifdef WITH_PKCS11
if (_wcscmp(pszProviderName, MS_SMART_CARD_KEY_STORAGE_PROVIDER) == 0)
{
static LPCSTR openscPaths[] = { "/usr/lib/x86_64-linux-gnu/pkcs11/opensc-pkcs11.so", NULL };
return winpr_NCryptOpenStorageProviderEx(phProvider, pszProviderName, dwFlags, openscPaths);
}
#endif
return ERROR_NOT_SUPPORTED;
}
SECURITY_STATUS winpr_NCryptOpenStorageProviderEx(NCRYPT_PROV_HANDLE* phProvider,
LPCWSTR pszProviderName, DWORD dwFlags,
LPCSTR* modulePaths)
{
#ifdef WITH_PKCS11
if (_wcscmp(pszProviderName, MS_SMART_CARD_KEY_STORAGE_PROVIDER) == 0 ||
_wcscmp(pszProviderName, MS_SCARD_PROV) == 0)
{
SECURITY_STATUS NCryptOpenP11StorageProviderEx(NCRYPT_PROV_HANDLE * phProvider,
LPCWSTR pszProviderName, DWORD dwFlags,
LPCSTR * modulePaths);
return NCryptOpenP11StorageProviderEx(phProvider, pszProviderName, dwFlags, modulePaths);
}
#endif
return ERROR_NOT_SUPPORTED;
}
SECURITY_STATUS NCryptEnumKeys(NCRYPT_PROV_HANDLE hProvider, LPCWSTR pszScope,
NCryptKeyName** ppKeyName, PVOID* ppEnumState, DWORD dwFlags)
{
SECURITY_STATUS ret;
NCryptBaseProvider* provider = (NCryptBaseProvider*)hProvider;
ret = checkNCryptHandle((NCRYPT_HANDLE)hProvider, WINPR_NCRYPT_PROVIDER);
if (ret != ERROR_SUCCESS)
return ret;
return provider->enumKeysFn(hProvider, pszScope, ppKeyName, ppEnumState, dwFlags);
}
SECURITY_STATUS NCryptOpenKey(NCRYPT_PROV_HANDLE hProvider, NCRYPT_KEY_HANDLE* phKey,
LPCWSTR pszKeyName, DWORD dwLegacyKeySpec, DWORD dwFlags)
{
SECURITY_STATUS ret;
NCryptBaseProvider* provider = (NCryptBaseProvider*)hProvider;
ret = checkNCryptHandle((NCRYPT_HANDLE)hProvider, WINPR_NCRYPT_PROVIDER);
if (ret != ERROR_SUCCESS)
return ret;
if (!phKey || !pszKeyName)
return ERROR_INVALID_PARAMETER;
return provider->openKeyFn(hProvider, phKey, pszKeyName, dwLegacyKeySpec, dwFlags);
}
static NCryptKeyGetPropertyEnum propertyStringToEnum(LPCWSTR pszProperty)
{
if (_wcscmp(pszProperty, NCRYPT_CERTIFICATE_PROPERTY) == 0)
{
return NCRYPT_PROPERTY_CERTIFICATE;
}
return NCRYPT_PROPERTY_UNKNOWN;
}
SECURITY_STATUS NCryptGetProperty(NCRYPT_HANDLE hObject, LPCWSTR pszProperty, PBYTE pbOutput,
DWORD cbOutput, DWORD* pcbResult, DWORD dwFlags)
{
NCryptKeyGetPropertyEnum property;
NCryptBaseHandle* base;
if (!hObject)
return ERROR_INVALID_PARAMETER;
base = (NCryptBaseHandle*)hObject;
if (memcmp(base->magic, NCRYPT_MAGIC, 6) != 0)
return ERROR_INVALID_HANDLE;
property = propertyStringToEnum(pszProperty);
if (property == NCRYPT_PROPERTY_UNKNOWN)
return ERROR_NOT_SUPPORTED;
return base->getPropertyFn(hObject, property, pbOutput, cbOutput, pcbResult, dwFlags);
}
SECURITY_STATUS NCryptFreeObject(NCRYPT_HANDLE hObject)
{
NCryptBaseHandle* base;
SECURITY_STATUS ret = checkNCryptHandle((NCRYPT_HANDLE)hObject, WINPR_NCRYPT_INVALID);
if (ret != ERROR_SUCCESS)
return ret;
base = (NCryptBaseHandle*)hObject;
if (base->releaseFn)
ret = base->releaseFn(hObject);
return ret;
}
SECURITY_STATUS NCryptFreeBuffer(PVOID pvInput)
{
if (!pvInput)
return ERROR_INVALID_PARAMETER;
free(pvInput);
return ERROR_SUCCESS;
}
#else
SECURITY_STATUS winpr_NCryptOpenStorageProviderEx(NCRYPT_PROV_HANDLE* phProvider,
LPCWSTR pszProviderName, DWORD dwFlags,
LPCSTR* modulePaths)
{
typedef SECURITY_STATUS (*NCryptOpenStorageProviderFn)(NCRYPT_PROV_HANDLE * phProvider,
LPCWSTR pszProviderName, DWORD dwFlags);
NCryptOpenStorageProviderFn ncryptOpenStorageProviderFn;
SECURITY_STATUS ret;
HANDLE lib = LoadLibraryA("ncrypt.dll");
if (!lib)
return NTE_PROV_DLL_NOT_FOUND;
ncryptOpenStorageProviderFn =
(NCryptOpenStorageProviderFn)GetProcAddress(lib, "NCryptOpenStorageProvider");
if (!ncryptOpenStorageProviderFn)
{
ret = NTE_PROV_DLL_NOT_FOUND;
goto out_free_lib;
}
ret = ncryptOpenStorageProviderFn(phProvider, pszProviderName, dwFlags);
out_free_lib:
FreeLibrary(lib);
return ret;
}
#endif

View File

@ -0,0 +1,81 @@
/**
* WinPR: Windows Portable Runtime
* NCrypt library
*
* Copyright 2021 David Fort <contact@hardening-consulting.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WINPR_LIBWINPR_NCRYPT_NCRYPT_H_
#define WINPR_LIBWINPR_NCRYPT_NCRYPT_H_
#include <winpr/bcrypt.h>
#include <winpr/crypto.h>
#include <winpr/ncrypt.h>
#include <winpr/error.h>
#include <winpr/string.h>
/** @brief type of ncrypt object */
typedef enum
{
WINPR_NCRYPT_INVALID,
WINPR_NCRYPT_PROVIDER,
WINPR_NCRYPT_KEY
} NCryptHandleType;
/** @brief dtor function for ncrypt object */
typedef SECURITY_STATUS (*NCryptReleaseFn)(NCRYPT_HANDLE handle);
/** @brief an enum for the kind of property to retrieve */
typedef enum
{
NCRYPT_PROPERTY_CERTIFICATE,
NCRYPT_PROPERTY_UNKNOWN
} NCryptKeyGetPropertyEnum;
typedef SECURITY_STATUS (*NCryptGetPropertyFn)(NCRYPT_HANDLE hObject,
NCryptKeyGetPropertyEnum property, PBYTE pbOutput,
DWORD cbOutput, DWORD* pcbResult, DWORD dwFlags);
/** @brief common ncrypt handle items */
typedef struct
{
char magic[6];
NCryptHandleType type;
NCryptGetPropertyFn getPropertyFn;
NCryptReleaseFn releaseFn;
} NCryptBaseHandle;
typedef SECURITY_STATUS (*NCryptEnumKeysFn)(NCRYPT_PROV_HANDLE hProvider, LPCWSTR pszScope,
NCryptKeyName** ppKeyName, PVOID* ppEnumState,
DWORD dwFlags);
typedef SECURITY_STATUS (*NCryptOpenKeyFn)(NCRYPT_PROV_HANDLE hProvider, NCRYPT_KEY_HANDLE* phKey,
LPCWSTR pszKeyName, DWORD dwLegacyKeySpec,
DWORD dwFlags);
/** @brief common ncrypt provider items */
typedef struct
{
NCryptBaseHandle baseHandle;
NCryptEnumKeysFn enumKeysFn;
NCryptOpenKeyFn openKeyFn;
} NCryptBaseProvider;
SECURITY_STATUS checkNCryptHandle(NCRYPT_HANDLE handle, NCryptHandleType matchType);
void* ncrypt_new_handle(NCryptHandleType kind, size_t len, NCryptGetPropertyFn getProp,
NCryptReleaseFn dtor);
SECURITY_STATUS winpr_NCryptDefault_dtor(NCryptBaseHandle* h);
#endif /* WINPR_LIBWINPR_NCRYPT_NCRYPT_H_ */

View File

@ -0,0 +1,771 @@
/**
* WinPR: Windows Portable Runtime
* NCrypt pkcs11 provider
*
* Copyright 2021 David Fort <contact@hardening-consulting.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef WITH_PKCS11
#include <pkcs11-helper-1.0/pkcs11.h>
#include <winpr/library.h>
#include "../log.h"
#include "ncrypt.h"
#define TAG WINPR_TAG("ncryptp11")
#define ARRAY_LENGTH(a) (sizeof(a) / sizeof(a)[0])
/** @brief ncrypt provider handle */
typedef struct
{
NCryptBaseProvider baseProvider;
HANDLE library;
CK_FUNCTION_LIST_PTR p11;
} NCryptP11ProviderHandle;
static SECURITY_STATUS NCryptP11StorageProvider_dtor(NCryptP11ProviderHandle* provider)
{
CK_RV rv = provider->p11->C_Finalize(NULL);
if (rv != CKR_OK)
{
}
if (provider->library)
FreeLibrary(provider->library);
return winpr_NCryptDefault_dtor(&provider->baseProvider.baseHandle);
}
#define MAX_SLOTS 64
#define MAX_PRIVATE_KEYS 64
#define MAX_KEYS_PER_SLOT 64
/** @brief */
typedef struct
{
CK_SLOT_ID slotId;
CK_SLOT_INFO slotInfo;
CK_KEY_TYPE keyType;
CK_CHAR keyLabel[256];
CK_ULONG idLen;
CK_BYTE id[64];
} NCryptPrivateKeyEnum;
/** @brief */
typedef struct
{
CK_ULONG nslots;
CK_SLOT_ID slots[MAX_SLOTS];
CK_ULONG nprivateKeys;
NCryptPrivateKeyEnum privateKeys[MAX_PRIVATE_KEYS];
CK_ULONG privateKeyIndex;
} P11EnumKeysState;
static CK_OBJECT_CLASS object_class_private_key = CKO_PRIVATE_KEY;
static CK_BBOOL object_sign = CK_TRUE;
static CK_KEY_TYPE object_ktype_rsa = CKK_RSA;
static CK_ATTRIBUTE private_key_filter[] = {
{ CKA_CLASS, &object_class_private_key, sizeof(object_class_private_key) },
{ CKA_SIGN, &object_sign, sizeof(object_sign) },
{ CKA_KEY_TYPE, &object_ktype_rsa, sizeof(object_ktype_rsa) }
};
#if 0
/**
* @return the real length of string padded with pad
*
*/
static size_t padded_strlen(const char *str, size_t maxlen, char pad)
{
size_t ret = strnlen(str, maxlen);
while ((ret > 0) && str[ret-1] == pad)
ret--;
return ret;
}
#endif
static BOOL attributes_have_unallocated_buffers(CK_ATTRIBUTE_PTR attributes, CK_ULONG count)
{
CK_ULONG i;
for (i = 0; i < count; i++)
{
if (!attributes[i].pValue && (attributes[i].ulValueLen != CK_UNAVAILABLE_INFORMATION))
return TRUE;
}
return FALSE;
}
static BOOL attribute_allocate_attribute_array(CK_ATTRIBUTE_PTR attribute)
{
attribute->pValue = calloc(attribute->ulValueLen, sizeof(void*));
return !!attribute->pValue;
}
static BOOL attribute_allocate_ulong_array(CK_ATTRIBUTE_PTR attribute)
{
attribute->pValue = calloc(attribute->ulValueLen, sizeof(CK_ULONG));
return !!attribute->pValue;
}
static BOOL attribute_allocate_buffer(CK_ATTRIBUTE_PTR attribute)
{
attribute->pValue = calloc(attribute->ulValueLen, 1);
return !!attribute->pValue;
}
static BOOL attributes_allocate_buffers(CK_ATTRIBUTE_PTR attributes, CK_ULONG count)
{
CK_ULONG i;
BOOL ret = TRUE;
for (i = 0; i < count; i++)
{
if (attributes[i].pValue || (attributes[i].ulValueLen == CK_UNAVAILABLE_INFORMATION))
continue;
switch (attributes[i].type)
{
case CKA_WRAP_TEMPLATE:
case CKA_UNWRAP_TEMPLATE:
ret &= attribute_allocate_attribute_array(&attributes[i]);
break;
case CKA_ALLOWED_MECHANISMS:
ret &= attribute_allocate_ulong_array(&attributes[i]);
break;
default:
ret &= attribute_allocate_buffer(&attributes[i]);
break;
}
}
return ret;
}
CK_RV object_load_attributes(NCryptP11ProviderHandle* provider, CK_SESSION_HANDLE session,
CK_OBJECT_HANDLE object, CK_ATTRIBUTE_PTR attributes, CK_ULONG count)
{
CK_RV rv = provider->p11->C_GetAttributeValue(session, object, attributes, count);
switch (rv)
{
case CKR_OK:
if (!attributes_have_unallocated_buffers(attributes, count))
return rv;
/* fallthrought */
case CKR_ATTRIBUTE_SENSITIVE:
case CKR_ATTRIBUTE_TYPE_INVALID:
case CKR_BUFFER_TOO_SMALL:
/* attributes need some buffers for the result value */
if (!attributes_allocate_buffers(attributes, count))
return CKR_HOST_MEMORY;
rv = provider->p11->C_GetAttributeValue(session, object, attributes, count);
break;
default:
return rv;
}
switch (rv)
{
case CKR_ATTRIBUTE_SENSITIVE:
case CKR_ATTRIBUTE_TYPE_INVALID:
case CKR_BUFFER_TOO_SMALL:
WLog_ERR(TAG, "C_GetAttributeValue return %d even after buffer allocation", rv);
break;
}
return rv;
}
static SECURITY_STATUS collect_private_keys(NCryptP11ProviderHandle* provider,
P11EnumKeysState* state)
{
CK_RV rv;
CK_SESSION_HANDLE session = (CK_SESSION_HANDLE)NULL;
CK_ULONG i, j, nslotObjects;
CK_OBJECT_HANDLE slotObjects[MAX_KEYS_PER_SLOT];
const char* step = NULL;
CK_FUNCTION_LIST_PTR p11 = provider->p11;
state->nprivateKeys = 0;
for (i = 0; i < state->nslots; i++)
{
CK_SLOT_INFO slotInfo;
rv = p11->C_GetSlotInfo(state->slots[i], &slotInfo);
if (rv != CKR_OK)
{
WLog_ERR(TAG, "unable to retrieve information for slot #%d(%d)", i, state->slots[i]);
continue;
}
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]);
continue;
}
rv = p11->C_FindObjectsInit(session, private_key_filter, ARRAY_LENGTH(private_key_filter));
if (rv != CKR_OK)
{
// TODO: shall it be fatal ?
WLog_ERR(TAG, "unable to initiate search for slot #%d(%d)", i, state->slots[i]);
step = "C_FindObjectsInit";
goto cleanup_FindObjectsInit;
}
rv = p11->C_FindObjects(session, &slotObjects[0], ARRAY_LENGTH(slotObjects), &nslotObjects);
if (rv != CKR_OK)
{
WLog_ERR(TAG, "unable to findObjects for slot #%d(%d)", i, state->slots[i]);
step = "C_FindObjects";
goto cleanup_FindObjects;
}
for (j = 0; j < nslotObjects; j++)
{
NCryptPrivateKeyEnum* privKey = &state->privateKeys[state->nprivateKeys];
CK_OBJECT_CLASS dataClass = CKO_PRIVATE_KEY;
CK_ATTRIBUTE key_or_certAttrs[] = {
{ CKA_ID, &privKey->id, sizeof(privKey->id) },
{ CKA_CLASS, &dataClass, sizeof(dataClass) },
{ CKA_LABEL, &privKey->keyLabel, sizeof(privKey->keyLabel) },
{ CKA_KEY_TYPE, &privKey->keyType, sizeof(privKey->keyType) }
};
rv = object_load_attributes(provider, session, slotObjects[j], key_or_certAttrs,
ARRAY_LENGTH(key_or_certAttrs));
if (rv != CKR_OK)
{
WLog_ERR(TAG, "error getting attributes");
continue;
}
privKey->idLen = key_or_certAttrs[0].ulValueLen;
privKey->slotId = state->slots[i];
privKey->slotInfo = slotInfo;
state->nprivateKeys++;
}
cleanup_FindObjects:
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);
}
cleanup_FindObjectsInit:
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);
}
}
return ERROR_SUCCESS;
}
static LPWSTR convertKeyType(CK_KEY_TYPE k)
{
const WCHAR* r = NULL;
#define ALGO_CASE(V, S) \
case V: \
r = S; \
break
switch (k)
{
ALGO_CASE(CKK_RSA, BCRYPT_RSA_ALGORITHM);
ALGO_CASE(CKK_DSA, BCRYPT_DSA_ALGORITHM);
ALGO_CASE(CKK_DH, BCRYPT_DH_ALGORITHM);
ALGO_CASE(CKK_ECDSA, BCRYPT_ECDSA_ALGORITHM);
ALGO_CASE(CKK_RC2, BCRYPT_RC2_ALGORITHM);
ALGO_CASE(CKK_RC4, BCRYPT_RC4_ALGORITHM);
ALGO_CASE(CKK_DES, BCRYPT_DES_ALGORITHM);
ALGO_CASE(CKK_DES3, BCRYPT_3DES_ALGORITHM);
case CKK_DES2:
case CKK_X9_42_DH:
case CKK_KEA:
case CKK_GENERIC_SECRET:
case CKK_CAST:
case CKK_CAST3:
case CKK_CAST128:
case CKK_RC5:
case CKK_IDEA:
case CKK_SKIPJACK:
case CKK_BATON:
case CKK_JUNIPER:
case CKK_CDMF:
case CKK_AES:
case CKK_BLOWFISH:
case CKK_TWOFISH:
break;
}
#undef ALGO_CASE
// ConvertToUnicode(CP_UTF8, 0, (LPCSTR)r, -1, &ret, 0);
return _wcsdup(r);
}
static void wprintKeyName(LPWSTR str, CK_SLOT_ID slotId, CK_BYTE* id, CK_ULONG idLen)
{
char asciiName[128];
char* ptr;
CK_ULONG i;
snprintf(asciiName, sizeof(asciiName), "\\%.8x\\", (UINT32)slotId);
ptr = asciiName + strlen(asciiName);
for (i = 0; i < idLen; i++, id++, ptr += 2)
snprintf(ptr, 3, "%.2x", *id);
MultiByteToWideChar(CP_UTF8, 0, asciiName, strlen(asciiName), str, (strlen(asciiName) + 1) * 2);
}
static size_t parseHex(const char* str, const char* end, CK_BYTE* target)
{
int ret = 0;
for (ret = 0; str != end && *str; str++, ret++, target++)
{
CK_BYTE v = 0;
if (*str <= '9' && *str >= '0')
{
v = (*str - '0');
}
else if (*str <= 'f' && *str >= 'a')
{
v = (10 + *str - 'a');
}
else if (*str <= 'F' && *str >= 'A')
{
v |= (10 + *str - 'A');
}
else
{
return 0;
}
v <<= 4;
str++;
if (!*str || str == end)
return 0;
if (*str <= '9' && *str >= '0')
{
v |= (*str - '0');
}
else if (*str <= 'f' && *str >= 'a')
{
v |= (10 + *str - 'a');
}
else if (*str <= 'F' && *str >= 'A')
{
v |= (10 + *str - 'A');
}
else
{
return 0;
}
*target = v;
}
return ret;
}
static SECURITY_STATUS parseKeyName(LPCWSTR pszKeyName, CK_SLOT_ID* slotId, CK_BYTE* id,
CK_ULONG* idLen)
{
char asciiKeyName[128];
char* pos;
if (WideCharToMultiByte(CP_UTF8, 0, pszKeyName, _wcslen(pszKeyName), asciiKeyName,
sizeof(asciiKeyName), "?", FALSE) <= 0)
return NTE_BAD_KEY;
if (*asciiKeyName != '\\')
return NTE_BAD_KEY;
pos = strchr(&asciiKeyName[1], '\\');
if (!pos)
return NTE_BAD_KEY;
if (pos - &asciiKeyName[1] > 8)
return NTE_BAD_KEY;
*slotId = (CK_SLOT_ID)0;
if (parseHex(&asciiKeyName[1], pos, (CK_BYTE*)slotId) != 4)
return NTE_BAD_KEY;
*idLen = parseHex(pos + 1, NULL, id);
if (!*idLen)
return NTE_BAD_KEY;
return ERROR_SUCCESS;
}
/** @brief a handle returned by NCryptOpenKey */
typedef struct
{
NCryptBaseHandle base;
NCryptP11ProviderHandle* provider;
CK_SLOT_ID slotId;
CK_BYTE keyCertId[64];
CK_ULONG keyCertIdLen;
} NCryptP11KeyHandle;
static SECURITY_STATUS NCryptP11EnumKeys(NCRYPT_PROV_HANDLE hProvider, LPCWSTR pszScope,
NCryptKeyName** ppKeyName, PVOID* ppEnumState,
DWORD dwFlags)
{
SECURITY_STATUS ret;
NCryptP11ProviderHandle* provider = (NCryptP11ProviderHandle*)hProvider;
P11EnumKeysState* state = (P11EnumKeysState*)*ppEnumState;
CK_RV rv;
CK_SLOT_ID currentSlot;
CK_SESSION_HANDLE currentSession = (CK_SESSION_HANDLE)NULL;
NCryptKeyName* keyName = NULL;
ret = checkNCryptHandle((NCRYPT_HANDLE)hProvider, WINPR_NCRYPT_PROVIDER);
if (ret != ERROR_SUCCESS)
return ret;
if (!state)
{
state = (P11EnumKeysState*)calloc(1, sizeof(*state));
if (!state)
return NTE_NO_MEMORY;
rv = provider->p11->C_GetSlotList(CK_TRUE, NULL, &state->nslots);
if (rv != CKR_OK)
{
/* TODO: perhaps convert rv to NTE_*** errors */
return NTE_FAIL;
}
if (state->nslots > MAX_SLOTS)
state->nslots = MAX_SLOTS;
rv = provider->p11->C_GetSlotList(CK_TRUE, state->slots, &state->nslots);
if (rv != CKR_OK)
{
free(state);
/* TODO: perhaps convert rv to NTE_*** errors */
return NTE_FAIL;
}
ret = collect_private_keys(provider, state);
if (ret != ERROR_SUCCESS)
{
free(state);
return ret;
}
*ppEnumState = state;
}
for (; state->privateKeyIndex < state->nprivateKeys; state->privateKeyIndex++)
{
NCryptPrivateKeyEnum* privKey = &state->privateKeys[state->privateKeyIndex];
CK_OBJECT_CLASS oclass = CKO_CERTIFICATE;
CK_CERTIFICATE_TYPE ctype = CKC_X_509;
CK_ATTRIBUTE certificateFilter[] = { { CKA_CLASS, &oclass, sizeof(oclass) },
{ CKA_CERTIFICATE_TYPE, &ctype, sizeof(ctype) },
{ CKA_ID, privKey->id, privKey->idLen } };
CK_ULONG ncertObjects;
CK_OBJECT_HANDLE certObject;
if (!currentSession || (currentSlot != privKey->slotId))
{
/* if the current session doesn't match the current private key's slot, open a new one
*/
if (currentSession)
{
rv = provider->p11->C_CloseSession(currentSession);
currentSession = (CK_SESSION_HANDLE)NULL;
}
rv = provider->p11->C_OpenSession(privKey->slotId, CKF_SERIAL_SESSION, NULL, NULL,
&currentSession);
if (rv != CKR_OK)
{
WLog_ERR(TAG, "unable to openSession for slot %d", privKey->slotId);
continue;
}
currentSlot = privKey->slotId;
}
/* look if we can find a certificate that matches the private key's id */
rv = provider->p11->C_FindObjectsInit(currentSession, certificateFilter,
ARRAY_LENGTH(certificateFilter));
if (rv != CKR_OK)
{
WLog_ERR(TAG, "unable to initiate search for slot %d", privKey->slotId);
continue;
}
rv = provider->p11->C_FindObjects(currentSession, &certObject, 1, &ncertObjects);
if (rv != CKR_OK)
{
WLog_ERR(TAG, "unable to findObjects for slot %d", currentSlot);
goto cleanup_FindObjects;
}
if (ncertObjects)
{
/* sizeof keyName struct + "\<slotId>\<certId>" */
#define KEYNAME_SZ (1 + 8 /*slotId*/ + 1 + (privKey->idLen * 2) + 1) * 2
keyName = calloc(1, sizeof(*keyName) + KEYNAME_SZ);
if (!keyName)
{
WLog_ERR(TAG, "unable to allocate keyName");
goto cleanup_FindObjects;
}
keyName->dwLegacyKeySpec = AT_KEYEXCHANGE | AT_SIGNATURE;
keyName->dwFlags = NCRYPT_MACHINE_KEY_FLAG;
keyName->pszAlgid = convertKeyType(privKey->keyType);
keyName->pszName = (LPWSTR)(keyName + 1);
wprintKeyName(keyName->pszName, privKey->slotId, privKey->id, privKey->idLen);
}
cleanup_FindObjects:
rv = provider->p11->C_FindObjectsFinal(currentSession);
if (keyName)
{
*ppKeyName = keyName;
state->privateKeyIndex++;
return ERROR_SUCCESS;
}
}
return NTE_NO_MORE_ITEMS;
}
static SECURITY_STATUS NCryptP11KeyGetProperties(NCryptP11KeyHandle* keyHandle,
NCryptKeyGetPropertyEnum property, PBYTE pbOutput,
DWORD cbOutput, DWORD* pcbResult, DWORD dwFlags)
{
SECURITY_STATUS ret = NTE_FAIL;
CK_RV rv;
CK_SESSION_HANDLE session;
CK_OBJECT_HANDLE objectHandle;
CK_ULONG objectCount;
NCryptP11ProviderHandle* provider = keyHandle->provider;
CK_OBJECT_CLASS oclass = CKO_CERTIFICATE;
CK_CERTIFICATE_TYPE ctype = CKC_X_509;
CK_ATTRIBUTE certificateFilter[] = { { CKA_CLASS, &oclass, sizeof(oclass) },
{ CKA_CERTIFICATE_TYPE, &ctype, sizeof(ctype) },
{ CKA_ID, keyHandle->keyCertId,
keyHandle->keyCertIdLen } };
CK_ATTRIBUTE* objectFilter = certificateFilter;
CK_ULONG objectFilterLen = ARRAY_LENGTH(certificateFilter);
if (property == NCRYPT_PROPERTY_UNKNOWN)
return NTE_NOT_SUPPORTED;
/* TODO: shall adjust objectFilter and objectFilterLen depending on requested
* the property when we add new ones */
switch (property)
{
case NCRYPT_PROPERTY_CERTIFICATE:
break;
default:
return NTE_NOT_SUPPORTED;
}
rv = provider->p11->C_OpenSession(keyHandle->slotId, CKF_SERIAL_SESSION, NULL, NULL, &session);
if (rv != CKR_OK)
{
WLog_ERR(TAG, "error opening session on slot %d", keyHandle->slotId);
return NTE_FAIL;
}
rv = provider->p11->C_FindObjectsInit(session, objectFilter, objectFilterLen);
if (rv != CKR_OK)
{
WLog_ERR(TAG, "unable to initiate search for slot %d", keyHandle->slotId);
goto out;
}
rv = provider->p11->C_FindObjects(session, &objectHandle, 1, &objectCount);
if (rv != CKR_OK)
{
WLog_ERR(TAG, "unable to findObjects for slot %d", keyHandle->slotId);
goto out_final;
}
if (!objectCount)
{
ret = NTE_NOT_FOUND;
goto out_final;
}
switch (property)
{
case NCRYPT_PROPERTY_CERTIFICATE:
{
CK_ATTRIBUTE certValue = { CKA_VALUE, pbOutput, cbOutput };
rv = provider->p11->C_GetAttributeValue(session, objectHandle, &certValue, 1);
if (rv != CKR_OK)
{
// TODO: do a kind of translation from CKR_* to NTE_*
}
*pcbResult = certValue.ulValueLen;
ret = ERROR_SUCCESS;
break;
}
default:
ret = NTE_NOT_SUPPORTED;
break;
}
out_final:
rv = provider->p11->C_FindObjectsFinal(session);
if (rv != CKR_OK)
{
WLog_ERR(TAG, "error in C_FindObjectsFinal() for slot %d", keyHandle->slotId);
}
out:
rv = provider->p11->C_CloseSession(session);
if (rv != CKR_OK)
{
WLog_ERR(TAG, "error in C_CloseSession() for slot %d", keyHandle->slotId);
}
return ret;
}
static SECURITY_STATUS NCryptP11GetProperty(NCRYPT_HANDLE hObject, NCryptKeyGetPropertyEnum prop,
PBYTE pbOutput, DWORD cbOutput, DWORD* pcbResult,
DWORD dwFlags)
{
NCryptBaseHandle* base = (NCryptBaseHandle*)hObject;
switch (base->type)
{
case WINPR_NCRYPT_PROVIDER:
return ERROR_CALL_NOT_IMPLEMENTED;
case WINPR_NCRYPT_KEY:
return NCryptP11KeyGetProperties((NCryptP11KeyHandle*)hObject, prop, pbOutput, cbOutput,
pcbResult, dwFlags);
default:
return ERROR_INVALID_HANDLE;
}
return ERROR_SUCCESS;
}
static SECURITY_STATUS NCryptP11OpenKey(NCRYPT_PROV_HANDLE hProvider, NCRYPT_KEY_HANDLE* phKey,
LPCWSTR pszKeyName, DWORD dwLegacyKeySpec, DWORD dwFlags)
{
SECURITY_STATUS ret;
CK_SLOT_ID slotId;
CK_BYTE keyCertId[64];
CK_ULONG keyCertIdLen;
NCryptP11KeyHandle* keyHandle;
ret = parseKeyName(pszKeyName, &slotId, keyCertId, &keyCertIdLen);
if (ret != ERROR_SUCCESS)
return ret;
keyHandle = (NCryptP11KeyHandle*)ncrypt_new_handle(WINPR_NCRYPT_KEY, sizeof(*keyHandle),
(NCryptGetPropertyFn)NCryptP11GetProperty,
(NCryptReleaseFn)winpr_NCryptDefault_dtor);
if (!keyHandle)
return NTE_NO_MEMORY;
keyHandle->provider = (NCryptP11ProviderHandle*)hProvider;
keyHandle->slotId = slotId;
memcpy(keyHandle->keyCertId, keyCertId, sizeof(keyCertId));
keyHandle->keyCertIdLen = keyCertIdLen;
*phKey = (NCRYPT_KEY_HANDLE)keyHandle;
return ERROR_SUCCESS;
}
SECURITY_STATUS NCryptOpenP11StorageProviderEx(NCRYPT_PROV_HANDLE* phProvider,
LPCWSTR pszProviderName, DWORD dwFlags,
LPCSTR* modulePaths)
{
SECURITY_STATUS status;
NCryptP11ProviderHandle* ret = NULL;
CK_RV rv;
CK_RV (*c_get_function_list)(CK_FUNCTION_LIST_PTR_PTR);
if (!phProvider)
return ERROR_INVALID_PARAMETER;
ret = (NCryptP11ProviderHandle*)ncrypt_new_handle(
WINPR_NCRYPT_PROVIDER, sizeof(*ret), (NCryptGetPropertyFn)NCryptP11GetProperty,
(NCryptReleaseFn)NCryptP11StorageProvider_dtor);
if (!ret)
return NTE_NO_MEMORY;
ret->baseProvider.enumKeysFn = NCryptP11EnumKeys;
ret->baseProvider.openKeyFn = NCryptP11OpenKey;
while (*modulePaths)
{
ret->library = LoadLibrary(*modulePaths);
if (!ret->library)
{
status = NTE_PROV_DLL_NOT_FOUND;
continue;
}
c_get_function_list = GetProcAddress(ret->library, "C_GetFunctionList");
if (!c_get_function_list)
{
status = NTE_PROV_TYPE_ENTRY_BAD;
goto out_lib_entry;
}
rv = c_get_function_list(&ret->p11);
if (rv != CKR_OK)
{
status = NTE_PROVIDER_DLL_FAIL;
goto out_lib_entry;
}
rv = ret->p11->C_Initialize(NULL);
if (rv != CKR_OK)
{
status = NTE_PROVIDER_DLL_FAIL;
goto out_lib_entry;
}
*phProvider = (NCRYPT_PROV_HANDLE)ret;
return ERROR_SUCCESS;
out_lib_entry:
FreeLibrary(ret->library);
modulePaths++;
}
free(ret);
return status;
}
#endif

View File

@ -0,0 +1,27 @@
set(MODULE_NAME "TestNCrypt")
set(MODULE_PREFIX "TEST_NCRYPT")
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
set(${MODULE_PREFIX}_TESTS
TestNCryptSmartcard.c)
create_test_sourcelist(${MODULE_PREFIX}_SRCS
${${MODULE_PREFIX}_DRIVER}
${${MODULE_PREFIX}_TESTS})
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
foreach(test ${${MODULE_PREFIX}_TESTS})
get_filename_component(TestName ${test} NAME_WE)
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
endforeach()
target_link_libraries(${MODULE_NAME} winpr)
if(WIN32)
target_link_libraries(${MODULE_NAME} ncrypt)
endif()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")

View File

@ -0,0 +1,81 @@
/**
* WinPR: Windows Portable Runtime
* Test for NCrypt library
*
* Copyright 2021 David Fort <contact@hardening-consulting.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/error.h>
#include <winpr/ncrypt.h>
#include <winpr/string.h>
#include <winpr/wlog.h>
#include <winpr/smartcard.h>
#define TAG "testNCrypt"
int TestNCryptSmartcard(int argc, char* argv[])
{
SECURITY_STATUS status;
NCRYPT_PROV_HANDLE provider;
PVOID enumState = NULL;
NCryptKeyName* keyName = NULL;
status = NCryptOpenStorageProvider(&provider, MS_SMART_CARD_KEY_STORAGE_PROVIDER, 0);
if (status != ERROR_SUCCESS)
return 0;
while ((status = NCryptEnumKeys(provider, NULL, &keyName, &enumState, NCRYPT_SILENT_FLAG)) ==
ERROR_SUCCESS)
{
NCRYPT_KEY_HANDLE phKey;
DWORD dwFlags = 0, cbOutput;
char keyNameStr[256];
PBYTE certBytes = NULL;
WideCharToMultiByte(CP_UTF8, 0, keyName->pszName, -1, keyNameStr, sizeof(keyNameStr), NULL,
FALSE);
status =
NCryptOpenKey(provider, &phKey, keyName->pszName, keyName->dwLegacyKeySpec, dwFlags);
if (status != ERROR_SUCCESS)
{
WLog_ERR(TAG, "unable to open key %s", keyNameStr);
continue;
}
status = NCryptGetProperty(phKey, NCRYPT_CERTIFICATE_PROPERTY, NULL, 0, &cbOutput, dwFlags);
if (status != ERROR_SUCCESS)
{
WLog_ERR(TAG, "unable to retrieve certificate for key %s", keyNameStr);
NCryptFreeObject((NCRYPT_HANDLE)phKey);
continue;
}
certBytes = calloc(1, cbOutput);
status = NCryptGetProperty(phKey, NCRYPT_CERTIFICATE_PROPERTY, certBytes, cbOutput,
&cbOutput, dwFlags);
if (status != ERROR_SUCCESS)
{
WLog_ERR(TAG, "unable to retrieve certificate for key %s", keyNameStr);
NCryptFreeObject((NCRYPT_HANDLE)phKey);
continue;
}
NCryptFreeObject((NCRYPT_HANDLE)phKey);
}
NCryptFreeObject((NCRYPT_HANDLE)enumState);
NCryptFreeObject((NCRYPT_HANDLE)provider);
return 0;
}