diff --git a/sdk/core/azure-core/CHANGELOG.md b/sdk/core/azure-core/CHANGELOG.md index a5636b849..7b700c084 100644 --- a/sdk/core/azure-core/CHANGELOG.md +++ b/sdk/core/azure-core/CHANGELOG.md @@ -12,6 +12,7 @@ This is useful when the UUID was generated outside the Azure SDK, or needs to be ### Bugs Fixed - [[#4490]](https://github.com/Azure/azure-sdk-for-cpp/issues/4490) Fixed WinHTTP memory leak during failed requests. +- Fixed the UUID generation so the variant is RFC 4122 conforming. ### Other Changes diff --git a/sdk/core/azure-core/inc/azure/core/uuid.hpp b/sdk/core/azure-core/inc/azure/core/uuid.hpp index 7dacecb1d..bc672830a 100644 --- a/sdk/core/azure-core/inc/azure/core/uuid.hpp +++ b/sdk/core/azure-core/inc/azure/core/uuid.hpp @@ -24,11 +24,6 @@ namespace Azure { namespace Core { static constexpr size_t UuidSize = 16; std::array m_uuid; - // The UUID reserved variants. - static constexpr uint8_t ReservedNCS = 0x80; - static constexpr uint8_t ReservedRFC4122 = 0x40; - static constexpr uint8_t ReservedMicrosoft = 0x20; - static constexpr uint8_t ReservedFuture = 0x00; private: Uuid(uint8_t const uuid[UuidSize]) { std::memcpy(m_uuid.data(), uuid, UuidSize); } diff --git a/sdk/core/azure-core/src/uuid.cpp b/sdk/core/azure-core/src/uuid.cpp index 9eb36b3d0..087c31516 100644 --- a/sdk/core/azure-core/src/uuid.cpp +++ b/sdk/core/azure-core/src/uuid.cpp @@ -67,8 +67,15 @@ namespace Azure { namespace Core { std::memcpy(uuid + i, &x, 4); } - // SetVariant to ReservedRFC4122 - uuid[8] = (uuid[8] | ReservedRFC4122) & 0x7F; + // The variant field consists of a variable number of the most significant bits of octet 8 of + // the UUID. + // https://www.rfc-editor.org/rfc/rfc4122.html#section-4.1.1 + // For setting the variant to conform to RFC4122, the high bits need to be of the form 10xx, + // which means the hex value of the first 4 bits can only be either 8, 9, A|a, B|b. The 0-7 + // values are reserved for backward compatibility. The C|c, D|d values are reserved for + // Microsoft, and the E|e, F|f values are reserved for future use. + // Therefore, we have to zero out the two high bits, and then set the highest bit to 1. + uuid[8] = (uuid[8] & 0x3F) | 0x80; constexpr uint8_t version = 4; // Version 4: Pseudo-random number diff --git a/sdk/core/azure-core/test/ut/uuid_test.cpp b/sdk/core/azure-core/test/ut/uuid_test.cpp index 157b4b453..1f47839da 100644 --- a/sdk/core/azure-core/test/ut/uuid_test.cpp +++ b/sdk/core/azure-core/test/ut/uuid_test.cpp @@ -36,6 +36,33 @@ TEST(Uuid, Randomness) EXPECT_EQ(uuids.size(), size); } +TEST(Uuid, Rfc4122Conforming) +{ + const int size = 100; + for (int i = 0; i < size; i++) + { + auto uuid = Uuid::CreateUuid(); + auto uuidStr = uuid.ToString(); + auto version = uuidStr[14]; + EXPECT_EQ(version, '4'); // Version 4: Pseudo-random number + + // The variant field consists of a variable number of the most significant bits of octet 8 of + // the UUID. + // https://www.rfc-editor.org/rfc/rfc4122.html#section-4.1.1 + // The high bits of the variant need to be of the form 10xx, which means they can only be either + // 8, 9, A|a, B|b. The 0-7 values are reserved for backward compatibility. The C|c, D|d values + // are reserved for Microsoft, and the E|e, F|f values are reserved for future use. + auto variant = uuidStr[19]; + + // The test is written this way to improve logging IF it was to fail, so we can see the value + // of the incorrect variant. + EXPECT_TRUE( + (variant == '8' || variant == '9' || variant == 'A' || variant == 'B' || variant == 'a' + || variant == 'b')) + << variant << " is not one of the expected values of 8, 9, A, B, a, b"; + } +} + TEST(Uuid, separatorPosition) { auto uuidKey = Uuid::CreateUuid().ToString();