From 171011567abbffac60cf1e61f9fa4bb7ad081ad6 Mon Sep 17 00:00:00 2001 From: Santosh Kulkarni <66682828+kr-santosh@users.noreply.github.com> Date: Thu, 19 Jan 2023 20:02:16 +0530 Subject: [PATCH] Client Encryption: Adds validation code to check if the Key Vault URI provided in wrap metadata is a valid key identifier. (#3642) * Check if the key vault uri provided is a valid Kid * test fix. * update changelog and build props * Update Directory.Build.props * Update Microsoft.Azure.Cosmos.Encryption.csproj * Fixed preview version * Refactor * Update EncryptionDatabaseExtensions.cs --- Directory.Build.props | 5 +- .../changelog.md | 10 +++ .../src/EncryptionDatabaseExtensions.cs | 22 +++++++ .../Microsoft.Azure.Cosmos.Encryption.csproj | 4 +- .../tests/EmulatorTests/MdeEncryptionTests.cs | 63 +++++++++++++++++++ 5 files changed, 99 insertions(+), 5 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index b163dedaac..2891c05569 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,12 +1,11 @@ - 3.31.2 3.31.2 preview 3.30.1 - 2.0.0 - 2.0.0 + 2.0.1 + 2.0.1 preview 1.0.0-preview04 1.1.0-preview3 diff --git a/Microsoft.Azure.Cosmos.Encryption/changelog.md b/Microsoft.Azure.Cosmos.Encryption/changelog.md index e3274bce7e..a5e7101074 100644 --- a/Microsoft.Azure.Cosmos.Encryption/changelog.md +++ b/Microsoft.Azure.Cosmos.Encryption/changelog.md @@ -3,6 +3,16 @@ Preview features are treated as a separate branch and will not be included in th The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +### [2.0.1](https://www.nuget.org/packages/Microsoft.Azure.Cosmos.Encryption/2.0.1) - 2023-03-11 + +#### Added +- [#3642](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/3642) Adds validation code to check if the Key Vault URI provided in wrap metadata is a valid key identifier. + +### [2.0.1-preview](https://www.nuget.org/packages/Microsoft.Azure.Cosmos.Encryption/2.0.1-preview) - 2023-01-11 + +#### Added +- [#3642](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/3642) Adds validation code to check if the Key Vault URI provided in wrap metadata is a valid key identifier. + ### [2.0.0](https://www.nuget.org/packages/Microsoft.Azure.Cosmos.Encryption/2.0.0) - 2022-06-28 #### Added diff --git a/Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabaseExtensions.cs b/Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabaseExtensions.cs index 47a68b38ae..f867921946 100644 --- a/Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabaseExtensions.cs +++ b/Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabaseExtensions.cs @@ -91,6 +91,17 @@ public static async Task CreateClientEncryptionKeyA + " Please refer to https://aka.ms/CosmosClientEncryption for more details."); } + if (string.Equals(encryptionCosmosClient.KeyEncryptionKeyResolverName, KeyEncryptionKeyResolverName.AzureKeyVault)) + { + // https://KEYVAULTNAME.vault.azure.net/keys/KEYNAME/KEYVERSION + string[] keyVaultUriSegments = new Uri(encryptionKeyWrapMetadata.Value).Segments; + + if (keyVaultUriSegments.Length != 4 || !string.Equals(keyVaultUriSegments[1], "keys/", StringComparison.InvariantCultureIgnoreCase)) + { + throw new ArgumentException($"Invalid Key Vault URI'{encryptionKeyWrapMetadata.Value}' passed. Pass the complete Azure keyvault key identifier. Please refer to https://aka.ms/CosmosClientEncryption for more details."); + } + } + KeyEncryptionKey keyEncryptionKey = KeyEncryptionKey.GetOrCreate( encryptionKeyWrapMetadata.Name, encryptionKeyWrapMetadata.Value, @@ -192,6 +203,17 @@ public static async Task RewrapClientEncryptionKeyA + " Please refer to https://aka.ms/CosmosClientEncryption for more details."); } + if (string.Equals(encryptionCosmosClient.KeyEncryptionKeyResolverName, KeyEncryptionKeyResolverName.AzureKeyVault)) + { + // https://KEYVAULTNAME.vault.azure.net/keys/KEYNAME/KEYVERSION + string[] keyVaultUriSegments = new Uri(newEncryptionKeyWrapMetadata.Value).Segments; + + if (keyVaultUriSegments.Length != 4 || !string.Equals(keyVaultUriSegments[1], "keys/", StringComparison.InvariantCultureIgnoreCase)) + { + throw new ArgumentException($"Invalid Key Vault URI'{newEncryptionKeyWrapMetadata.Value}' passed. Pass the complete Azure keyvault key identifier. Please refer to https://aka.ms/CosmosClientEncryption for more details."); + } + } + ClientEncryptionKeyProperties clientEncryptionKeyProperties = await clientEncryptionKey.ReadAsync(cancellationToken: cancellationToken); RequestOptions requestOptions = new RequestOptions diff --git a/Microsoft.Azure.Cosmos.Encryption/src/Microsoft.Azure.Cosmos.Encryption.csproj b/Microsoft.Azure.Cosmos.Encryption/src/Microsoft.Azure.Cosmos.Encryption.csproj index 6aa1f85932..9fe41b765f 100644 --- a/Microsoft.Azure.Cosmos.Encryption/src/Microsoft.Azure.Cosmos.Encryption.csproj +++ b/Microsoft.Azure.Cosmos.Encryption/src/Microsoft.Azure.Cosmos.Encryption.csproj @@ -28,11 +28,11 @@ - + - + diff --git a/Microsoft.Azure.Cosmos.Encryption/tests/EmulatorTests/MdeEncryptionTests.cs b/Microsoft.Azure.Cosmos.Encryption/tests/EmulatorTests/MdeEncryptionTests.cs index 6ab6d8c333..65efd425aa 100644 --- a/Microsoft.Azure.Cosmos.Encryption/tests/EmulatorTests/MdeEncryptionTests.cs +++ b/Microsoft.Azure.Cosmos.Encryption/tests/EmulatorTests/MdeEncryptionTests.cs @@ -296,6 +296,69 @@ await MdeEncryptionTests.CreateClientEncryptionKeyAsync( if (ex is CosmosException cosmosException) Assert.AreEqual(HttpStatusCode.Conflict, cosmosException.StatusCode); } + + cekId = "testAkvKid"; + CosmosClient client = TestCommon.CreateCosmosClient(); + TestKeyEncryptionKeyResolver testKeyEncryptionKeyResolver = new TestKeyEncryptionKeyResolver(); + + EncryptionKeyWrapMetadata metadata = MdeEncryptionTests.CreateEncryptionKeyWrapMetadata(KeyEncryptionKeyResolverName.AzureKeyVault, "key1", "https://testkeyvault.vault.azure.net/keys/testkey/12345678"); + + CosmosClient encryptionCosmosClient = client.WithEncryption( + testKeyEncryptionKeyResolver, + KeyEncryptionKeyResolverName.AzureKeyVault, + TimeSpan.Zero); + + Database database = await encryptionCosmosClient.CreateDatabaseAsync(Guid.NewGuid().ToString()); + + ClientEncryptionKeyResponse clientEncrytionKeyResponse = await database.CreateClientEncryptionKeyAsync( + cekId, + DataEncryptionAlgorithm.AeadAes256CbcHmacSha256, + metadata); + + Assert.AreEqual(HttpStatusCode.Created, clientEncrytionKeyResponse.StatusCode); + + metadata = MdeEncryptionTests.CreateEncryptionKeyWrapMetadata(KeyEncryptionKeyResolverName.AzureKeyVault, "key1", "https://testkeyvault.vault.azure.net/keys/testkey/9101112"); + + clientEncrytionKeyResponse = await database.RewrapClientEncryptionKeyAsync( + cekId, + metadata); + + Assert.AreEqual(HttpStatusCode.OK, clientEncrytionKeyResponse.StatusCode); + + // complete key identifier not passed + metadata = MdeEncryptionTests.CreateEncryptionKeyWrapMetadata(KeyEncryptionKeyResolverName.AzureKeyVault, "key1", "https://testkeyvault.vault.azure.net/keys/testkey"); + + try + { + clientEncrytionKeyResponse = await database.CreateClientEncryptionKeyAsync( + cekId, + DataEncryptionAlgorithm.AeadAes256CbcHmacSha256, + metadata); + + Assert.Fail("Key creation should have failed."); + + } + catch(Exception ex) + { + Assert.AreEqual(true, ex.Message.Contains("Invalid Key Vault URI")); + } + + // rewrap old key with new key vault uri without complete key identifier + try + { + clientEncrytionKeyResponse = await database.RewrapClientEncryptionKeyAsync( + cekId, + metadata); + + Assert.Fail("Key rewrap should have failed."); + + } + catch (Exception ex) + { + Assert.AreEqual(true, ex.Message.Contains("Invalid Key Vault URI")); + } + + encryptionCosmosClient.Dispose(); } [TestMethod]