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:
parent
a6cadd6f97
commit
d4020e2328
24
cmake/FindPkcs11.cmake
Normal file
24
cmake/FindPkcs11.cmake
Normal 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)
|
||||
|
||||
|
@ -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")
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
123
winpr/include/winpr/ncrypt.h
Normal file
123
winpr/include/winpr/ncrypt.h
Normal 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_ */
|
@ -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})
|
||||
|
@ -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 */
|
||||
|
26
winpr/libwinpr/ncrypt/CMakeLists.txt
Normal file
26
winpr/libwinpr/ncrypt/CMakeLists.txt
Normal 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()
|
9
winpr/libwinpr/ncrypt/ModuleOptions.cmake
Normal file
9
winpr/libwinpr/ncrypt/ModuleOptions.cmake
Normal 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")
|
||||
|
222
winpr/libwinpr/ncrypt/ncrypt.c
Normal file
222
winpr/libwinpr/ncrypt/ncrypt.c
Normal 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
|
81
winpr/libwinpr/ncrypt/ncrypt.h
Normal file
81
winpr/libwinpr/ncrypt/ncrypt.h
Normal 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_ */
|
771
winpr/libwinpr/ncrypt/ncrypt_pkcs11.c
Normal file
771
winpr/libwinpr/ncrypt/ncrypt_pkcs11.c
Normal 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,
|
||||
¤tSession);
|
||||
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
|
27
winpr/libwinpr/ncrypt/test/CMakeLists.txt
Normal file
27
winpr/libwinpr/ncrypt/test/CMakeLists.txt
Normal 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")
|
81
winpr/libwinpr/ncrypt/test/TestNCryptSmartcard.c
Normal file
81
winpr/libwinpr/ncrypt/test/TestNCryptSmartcard.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user