diff --git a/build/VStudio/testing/winfsp-tests.vcxproj b/build/VStudio/testing/winfsp-tests.vcxproj index d2c93397..0352416a 100644 --- a/build/VStudio/testing/winfsp-tests.vcxproj +++ b/build/VStudio/testing/winfsp-tests.vcxproj @@ -204,6 +204,7 @@ + diff --git a/build/VStudio/testing/winfsp-tests.vcxproj.filters b/build/VStudio/testing/winfsp-tests.vcxproj.filters index 516a2310..b3fcf912 100644 --- a/build/VStudio/testing/winfsp-tests.vcxproj.filters +++ b/build/VStudio/testing/winfsp-tests.vcxproj.filters @@ -106,6 +106,9 @@ Source + + Source + diff --git a/build/VStudio/winfsp_sys.vcxproj b/build/VStudio/winfsp_sys.vcxproj index e341f18d..84a09e07 100644 --- a/build/VStudio/winfsp_sys.vcxproj +++ b/build/VStudio/winfsp_sys.vcxproj @@ -105,7 +105,7 @@ _X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions) - wdmsec.lib;%(AdditionalDependencies) + cng.lib;wdmsec.lib;%(AdditionalDependencies) true $(OutDir)$(TargetFileName).pdb $(OutDir)$(TargetFileName).map @@ -118,7 +118,7 @@ _X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions) - wdmsec.lib;%(AdditionalDependencies) + cng.lib;wdmsec.lib;%(AdditionalDependencies) true $(OutDir)$(TargetFileName).pdb $(OutDir)$(TargetFileName).map @@ -131,7 +131,7 @@ _WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions) - wdmsec.lib;%(AdditionalDependencies) + cng.lib;wdmsec.lib;%(AdditionalDependencies) true $(OutDir)$(TargetFileName).pdb $(OutDir)$(TargetFileName).map @@ -144,7 +144,7 @@ _WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions) - wdmsec.lib;%(AdditionalDependencies) + cng.lib;wdmsec.lib;%(AdditionalDependencies) true $(OutDir)$(TargetFileName).pdb $(OutDir)$(TargetFileName).map @@ -156,6 +156,7 @@ + diff --git a/build/VStudio/winfsp_sys.vcxproj.filters b/build/VStudio/winfsp_sys.vcxproj.filters index a6d6528e..7f0cf05d 100644 --- a/build/VStudio/winfsp_sys.vcxproj.filters +++ b/build/VStudio/winfsp_sys.vcxproj.filters @@ -113,6 +113,9 @@ Source\ku + + Source\ku + diff --git a/src/ku/uuid5.c b/src/ku/uuid5.c new file mode 100644 index 00000000..6a250913 --- /dev/null +++ b/src/ku/uuid5.c @@ -0,0 +1,134 @@ +/** + * @file dll/uuid5.c + * + * @copyright 2015-2019 Bill Zissimopoulos + */ +/* + * This file is part of WinFsp. + * + * You can redistribute it and/or modify it under the terms of the GNU + * General Public License version 3 as published by the Free Software + * Foundation. + * + * Licensees holding a valid commercial license may use this software + * in accordance with the commercial license agreement provided in + * conjunction with the software. The terms and conditions of any such + * commercial license agreement shall govern, supersede, and render + * ineffective any application of the GPLv3 license to this software, + * notwithstanding of any reference thereto in the software or + * associated repository. + */ + +#include +#include + +/* + * This module is used to create UUID v5 identifiers. UUID v5 identifiers + * are effectively SHA1 hashes that are modified to fit within the UUID + * format. The resulting identifiers use version 5 and variant 2. The hash + * is taken over the concatenation of a namespace ID and a name; the namespace + * ID is another UUID and the name can be any string of bytes ("octets"). + * + * For details see RFC 4122: https://tools.ietf.org/html/rfc4122 + */ + +NTSTATUS FspUuid5Make(const UUID *Namespace, const VOID *Buffer, ULONG Size, UUID *Uuid) +{ + BCRYPT_ALG_HANDLE ProvHandle = 0; + BCRYPT_HASH_HANDLE HashHandle = 0; + UINT8 Temp[20]; + NTSTATUS Result; + + /* + * Windows UUID's are encoded in little-endian format. RFC 4122 specifies that for + * UUID v5 computation, UUID's must be converted to/from big-endian. + * + * Note that Windows is always little-endian: + * https://community.osr.com/discussion/comment/146810/#Comment_146810 + */ + + /* copy Namespace to local buffer in network byte order (big-endian) */ + Temp[ 0] = ((PUINT8)Namespace)[ 3]; + Temp[ 1] = ((PUINT8)Namespace)[ 2]; + Temp[ 2] = ((PUINT8)Namespace)[ 1]; + Temp[ 3] = ((PUINT8)Namespace)[ 0]; + Temp[ 4] = ((PUINT8)Namespace)[ 5]; + Temp[ 5] = ((PUINT8)Namespace)[ 4]; + Temp[ 6] = ((PUINT8)Namespace)[ 7]; + Temp[ 7] = ((PUINT8)Namespace)[ 6]; + Temp[ 8] = ((PUINT8)Namespace)[ 8]; + Temp[ 9] = ((PUINT8)Namespace)[ 9]; + Temp[10] = ((PUINT8)Namespace)[10]; + Temp[11] = ((PUINT8)Namespace)[11]; + Temp[12] = ((PUINT8)Namespace)[12]; + Temp[13] = ((PUINT8)Namespace)[13]; + Temp[14] = ((PUINT8)Namespace)[14]; + Temp[15] = ((PUINT8)Namespace)[15]; + + /* + * Unfortunately we cannot reuse the hashing object, because BCRYPT_HASH_REUSABLE_FLAG + * is available in Windows 8 and later. (WinFsp currently supports Windows 7 or later). + */ + + Result = BCryptOpenAlgorithmProvider(&ProvHandle, BCRYPT_SHA1_ALGORITHM, 0, 0); + if (!NT_SUCCESS(Result)) + goto exit; + + Result = BCryptCreateHash(ProvHandle, &HashHandle, 0, 0, 0, 0, 0); + if (!NT_SUCCESS(Result)) + goto exit; + + Result = BCryptHashData(HashHandle, (PVOID)Temp, 16, 0); + if (!NT_SUCCESS(Result)) + goto exit; + + Result = BCryptHashData(HashHandle, (PVOID)Buffer, Size, 0); + if (!NT_SUCCESS(Result)) + goto exit; + + Result = BCryptFinishHash(HashHandle, Temp, 20, 0); + if (!NT_SUCCESS(Result)) + goto exit; + + /* copy local buffer to Uuid in host byte order (little-endian) */ + ((PUINT8)Uuid)[ 0] = Temp[ 3]; + ((PUINT8)Uuid)[ 1] = Temp[ 2]; + ((PUINT8)Uuid)[ 2] = Temp[ 1]; + ((PUINT8)Uuid)[ 3] = Temp[ 0]; + ((PUINT8)Uuid)[ 4] = Temp[ 5]; + ((PUINT8)Uuid)[ 5] = Temp[ 4]; + ((PUINT8)Uuid)[ 6] = Temp[ 7]; + ((PUINT8)Uuid)[ 7] = Temp[ 6]; + ((PUINT8)Uuid)[ 8] = Temp[ 8]; + ((PUINT8)Uuid)[ 9] = Temp[ 9]; + ((PUINT8)Uuid)[10] = Temp[10]; + ((PUINT8)Uuid)[11] = Temp[11]; + ((PUINT8)Uuid)[12] = Temp[12]; + ((PUINT8)Uuid)[13] = Temp[13]; + ((PUINT8)Uuid)[14] = Temp[14]; + ((PUINT8)Uuid)[15] = Temp[15]; + + /* [RFC 4122 Section 4.3] + * Set the four most significant bits (bits 12 through 15) of the + * time_hi_and_version field to the appropriate 4-bit version number + * from Section 4.1.3. + */ + Uuid->Data3 = (5 << 12) | (Uuid->Data3 & 0x0fff); + + /* [RFC 4122 Section 4.3] + * Set the two most significant bits (bits 6 and 7) of the + * clock_seq_hi_and_reserved to zero and one, respectively. + */ + Uuid->Data4[0] = (2 << 6) | (Uuid->Data4[0] & 0x3f); + + Result = STATUS_SUCCESS; + +exit: + if (0 != HashHandle) + BCryptDestroyHash(HashHandle); + + if (0 != ProvHandle) + BCryptCloseAlgorithmProvider(ProvHandle, 0); + + return Result; +} diff --git a/src/sys/driver.h b/src/sys/driver.h index 01ad8784..5d114ff2 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -493,6 +493,9 @@ NTSTATUS FspFileNameInExpression( PWCH UpcaseTable, PBOOLEAN PResult); +/* UUID5 creation (ku) */ +NTSTATUS FspUuid5Make(const UUID *Namespace, const VOID *Buffer, ULONG Size, UUID *Uuid); + /* utility */ PVOID FspAllocatePoolMustSucceed(POOL_TYPE PoolType, SIZE_T Size, ULONG Tag); PVOID FspAllocateIrpMustSucceed(CCHAR StackSize); diff --git a/tst/winfsp-tests/uuid5-test.c b/tst/winfsp-tests/uuid5-test.c new file mode 100644 index 00000000..f5f31e2c --- /dev/null +++ b/tst/winfsp-tests/uuid5-test.c @@ -0,0 +1,60 @@ +/** + * @file uuid5-test.c + * + * @copyright 2015-2019 Bill Zissimopoulos + */ +/* + * This file is part of WinFsp. + * + * You can redistribute it and/or modify it under the terms of the GNU + * General Public License version 3 as published by the Free Software + * Foundation. + * + * Licensees holding a valid commercial license may use this software + * in accordance with the commercial license agreement provided in + * conjunction with the software. The terms and conditions of any such + * commercial license agreement shall govern, supersede, and render + * ineffective any application of the GPLv3 license to this software, + * notwithstanding of any reference thereto in the software or + * associated repository. + */ + +#include +#include + +#include "winfsp-tests.h" + +#pragma comment(lib, "bcrypt.lib") +#include + +static void uuid5_test(void) +{ + // 6ba7b810-9dad-11d1-80b4-00c04fd430c8 + static const GUID GuidNs = + { 0x6ba7b810, 0x9dad, 0x11d1, { 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 } }; + // 74738ff5-5367-5958-9aee-98fffdcd1876 + static const GUID Guid0 = + { 0x74738ff5, 0x5367, 0x5958, { 0x9a, 0xee, 0x98, 0xff, 0xfd, 0xcd, 0x18, 0x76 } }; + // 63b5d721-0b97-5e7a-a550-2f0e589b5478 + static const GUID Guid1 = + { 0x63b5d721, 0x0b97, 0x5e7a, { 0xa5, 0x50, 0x2f, 0x0e, 0x58, 0x9b, 0x54, 0x78 } }; + + NTSTATUS Result; + GUID Guid; + + Result = FspUuid5Make(&GuidNs, "www.example.org", 15, &Guid); + ASSERT(NT_SUCCESS(Result)); + ASSERT(IsEqualGUID(&Guid0, &Guid)); + + Result = FspUuid5Make(&FspFsvrtDeviceClassGuid, "hello", 5, &Guid); + ASSERT(NT_SUCCESS(Result)); + ASSERT(IsEqualGUID(&Guid1, &Guid)); +} + +void uuid5_tests(void) +{ + if (OptExternal) + return; + + TEST(uuid5_test); +} diff --git a/tst/winfsp-tests/winfsp-tests.c b/tst/winfsp-tests/winfsp-tests.c index 93e033eb..9195e212 100644 --- a/tst/winfsp-tests/winfsp-tests.c +++ b/tst/winfsp-tests/winfsp-tests.c @@ -188,6 +188,7 @@ int main(int argc, char *argv[]) TESTSUITE(fuse_opt_tests); TESTSUITE(fuse_tests); TESTSUITE(posix_tests); + TESTSUITE(uuid5_tests); TESTSUITE(eventlog_tests); TESTSUITE(path_tests); TESTSUITE(dirbuf_tests);