Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace Azure.Core.Shared
{
internal class EventSourceEventFormatting
internal static class EventSourceEventFormatting
{
public static string Format(EventWrittenEventArgs eventData)
{
Expand Down
1 change: 1 addition & 0 deletions sdk/core/Azure.Core/tests/TestFramework.props
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)\TestFramework\*.cs" Link="TestFramework\%(RecursiveDir)\%(Filename)%(Extension)" />
<Compile Include="$(MSBuildThisFileDirectory)\..\src\Shared\ContentTypeUtilities.cs" Link="TestFramework\ContentTypeUtilities.cs" />
<Compile Include="$(MSBuildThisFileDirectory)\..\src\Shared\EventSourceEventFormatting.cs" Link="TestFramework\EventSourceEventFormatting.cs" />
<Compile Include="$(MSBuildThisFileDirectory)\..\src\Shared\NullableAttributes.cs" Link="TestFramework\NullableAttributes.cs" Condition="'$(UseAzureCoreNullableAttributes)'!='true'" />
<None Update="SessionRecords\**\*.json" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<!-- Import the Azure.Core project -->
<Import Project="$(MSBuildThisFileDirectory)..\..\..\core\Azure.Core\src\Azure.Core.props" />

<Import Project="..\..\Azure.Security.KeyVault.Shared\Azure.Security.KeyVault.Shared.projitems" Label="Shared" />
<Import Project="..\..\Azure.Security.KeyVault.Shared\src\Azure.Security.KeyVault.Shared.projitems" Label="Shared" />

<ItemGroup>
<PackageReference Include="System.Memory" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

</PropertyGroup>

<Import Project="..\..\Azure.Security.KeyVault.Shared\Azure.Security.KeyVault.Shared.projitems" Label="Shared" />
<Import Project="..\..\Azure.Security.KeyVault.Shared\src\Azure.Security.KeyVault.Shared.projitems" Label="Shared" />
<ItemGroup>
<Compile Include="$(AzureCoreSharedSources)Argument.cs" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public override UnwrapResult UnwrapKey(KeyWrapAlgorithm algorithm, byte[] encryp
int algorithmKeySizeBytes = algorithm.GetKeySizeInBytes();
if (algorithmKeySizeBytes == 0)
{
// TODO: Log that we don't support the algorithm locally.
KeysEventSource.Singleton.AlgorithmNotSupported(nameof(UnwrapKey), algorithm);
return null;
}

Expand Down Expand Up @@ -66,7 +66,7 @@ public override WrapResult WrapKey(KeyWrapAlgorithm algorithm, byte[] key, Cance
int algorithmKeySizeBytes = algorithm.GetKeySizeInBytes();
if (algorithmKeySizeBytes == 0)
{
// TODO: Log that we don't support the algorithm locally.
KeysEventSource.Singleton.AlgorithmNotSupported(nameof(WrapKey), algorithm);
return null;
}

Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace Azure.Security.KeyVault.Keys.Cryptography
internal class EcCryptographyProvider : LocalCryptographyProvider
{
private readonly KeyCurveName _curve;
private readonly JsonWebKey _keyMaterial;

internal EcCryptographyProvider(KeyVaultKey key) : base(key)
{
Expand All @@ -21,25 +22,24 @@ internal EcCryptographyProvider(KeyVaultKey key) : base(key)
JsonWebKey keyMaterial = key.Key;
if (keyMaterial != null && keyMaterial.CurveName.HasValue)
{
// Save the key material to use for operational support validation.
_keyMaterial = keyMaterial;

_curve = keyMaterial.CurveName.Value;
if (_curve.IsSupported)
{
KeyMaterial = keyMaterial;
}
else
{
// TODO: Log that we don't support the algorithm locally.
}
}
}

public override bool SupportsOperation(KeyOperation operation)
{
if (KeyMaterial != null)
if (_keyMaterial != null)
{
if (operation == KeyOperation.Sign || operation == KeyOperation.Verify)
{
return KeyMaterial.SupportsOperation(operation);
return _keyMaterial.SupportsOperation(operation);
}
}

Expand All @@ -55,13 +55,14 @@ public override SignResult Sign(SignatureAlgorithm algorithm, byte[] digest, Can
// The JWK is not supported by this client. Send to the server.
if (KeyMaterial is null)
{
KeysEventSource.Singleton.AlgorithmNotSupported(nameof(Sign), _curve);
return null;
}

// A private key is required to sign. Send to the server.
if (MustRemote)
{
// TODO: Log that we need a private key.
KeysEventSource.Singleton.PrivateKeyRequired(nameof(Sign));
return null;
}

Expand Down Expand Up @@ -100,6 +101,7 @@ public override VerifyResult Verify(SignatureAlgorithm algorithm, byte[] digest,
// The JWK is not supported by this client. Send to the server.
if (KeyMaterial is null)
{
KeysEventSource.Singleton.AlgorithmNotSupported(nameof(Verify), _curve);
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Azure.Core.Diagnostics;

namespace Azure.Security.KeyVault.Keys.Cryptography
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,13 @@ public override EncryptResult Encrypt(EncryptionAlgorithm algorithm, byte[] plai
ThrowIfTimeInvalid();

RSAEncryptionPadding padding = algorithm.GetRsaEncryptionPadding();
byte[] ciphertext = Encrypt(plaintext, padding);
if (padding is null)
{
KeysEventSource.Singleton.AlgorithmNotSupported(nameof(Encrypt), algorithm);
return null;
}

byte[] ciphertext = Encrypt(plaintext, padding);
EncryptResult result = null;

if (ciphertext != null)
Expand All @@ -54,9 +59,21 @@ public override DecryptResult Decrypt(EncryptionAlgorithm algorithm, byte[] ciph
{
Argument.AssertNotNull(ciphertext, nameof(ciphertext));

if (MustRemote)
{
// A private key is required to decrypt. Send to the server.
KeysEventSource.Singleton.PrivateKeyRequired(nameof(Decrypt));
return null;
}

RSAEncryptionPadding padding = algorithm.GetRsaEncryptionPadding();
byte[] plaintext = Decrypt(ciphertext, padding);
if (padding is null)
{
KeysEventSource.Singleton.AlgorithmNotSupported(nameof(Decrypt), algorithm);
return null;
}

byte[] plaintext = Decrypt(ciphertext, padding);
DecryptResult result = null;

if (plaintext != null)
Expand All @@ -81,21 +98,21 @@ public override SignResult Sign(SignatureAlgorithm algorithm, byte[] digest, Can
// A private key is required to sign. Send to the server.
if (MustRemote)
{
// TODO: Log that we need a private key.
KeysEventSource.Singleton.PrivateKeyRequired(nameof(Sign));
return null;
}

HashAlgorithmName hashAlgorithm = algorithm.GetHashAlgorithmName();
if (hashAlgorithm == default)
{
// TODO: Log that we don't support the given algorithm.
KeysEventSource.Singleton.AlgorithmNotSupported(nameof(Sign), algorithm);
return null;
}

RSASignaturePadding padding = algorithm.GetRsaSignaturePadding();
if (padding is null)
{
// TODO: Log that we don't support the given algorithm.
KeysEventSource.Singleton.AlgorithmNotSupported(nameof(Sign), algorithm);
return null;
}

Expand All @@ -118,14 +135,14 @@ public override VerifyResult Verify(SignatureAlgorithm algorithm, byte[] digest,
HashAlgorithmName hashAlgorithm = algorithm.GetHashAlgorithmName();
if (hashAlgorithm == default)
{
// TODO: Log that we don't support the given algorithm.
KeysEventSource.Singleton.AlgorithmNotSupported(nameof(Verify), algorithm);
return null;
}

RSASignaturePadding padding = algorithm.GetRsaSignaturePadding();
if (padding is null)
{
// TODO: Log that we don't support the given algorithm.
KeysEventSource.Singleton.AlgorithmNotSupported(nameof(Verify), algorithm);
return null;
}

Expand All @@ -147,8 +164,13 @@ public override WrapResult WrapKey(KeyWrapAlgorithm algorithm, byte[] key, Cance
ThrowIfTimeInvalid();

RSAEncryptionPadding padding = algorithm.GetRsaEncryptionPadding();
byte[] encryptedKey = Encrypt(key, padding);
if (padding is null)
{
KeysEventSource.Singleton.AlgorithmNotSupported(nameof(WrapKey), algorithm);
return null;
}

byte[] encryptedKey = Encrypt(key, padding);
WrapResult result = null;

if (encryptedKey != null)
Expand All @@ -168,9 +190,21 @@ public override UnwrapResult UnwrapKey(KeyWrapAlgorithm algorithm, byte[] encryp
{
Argument.AssertNotNull(encryptedKey, nameof(encryptedKey));

if (MustRemote)
{
// A private key is required to decrypt. Send to the server.
KeysEventSource.Singleton.PrivateKeyRequired(nameof(UnwrapKey));
return null;
}

RSAEncryptionPadding padding = algorithm.GetRsaEncryptionPadding();
byte[] key = Decrypt(encryptedKey, padding);
if (padding is null)
{
KeysEventSource.Singleton.AlgorithmNotSupported(nameof(UnwrapKey), algorithm);
return null;
}

byte[] key = Decrypt(encryptedKey, padding);
UnwrapResult result = null;

if (key != null)
Expand All @@ -188,31 +222,12 @@ public override UnwrapResult UnwrapKey(KeyWrapAlgorithm algorithm, byte[] encryp

private byte[] Encrypt(byte[] data, RSAEncryptionPadding padding)
{
if (padding is null)
{
// TODO: Log that we don't support the given algorithm.
return null;
}

using RSA rsa = KeyMaterial.ToRSA(true);
return rsa.Encrypt(data, padding);
}

private byte[] Decrypt(byte[] data, RSAEncryptionPadding padding)
{
// A private key is required to decrypt. Send to the server.
if (MustRemote)
{
// TODO: Log that we need a private key.
return null;
}

if (padding is null)
{
// TODO: Log that we don't support the given algorithm.
return null;
}

using RSA rsa = KeyMaterial.ToRSA();
return rsa.Decrypt(data, padding);
}
Expand Down
96 changes: 96 additions & 0 deletions sdk/keyvault/Azure.Security.KeyVault.Keys/src/KeysEventSource.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Diagnostics.Tracing;
using System.Globalization;
using System.Text;
using Azure.Core.Diagnostics;

namespace Azure.Security.KeyVault.Keys
{
[EventSource(Name = EventSourceName)]
internal sealed class KeysEventSource : EventSource
{
internal const int AlgorithmNotSupportedEvent = 1;
internal const int KeyTypeNotSupportedEvent = 2;
internal const int PrivateKeyRequiredEvent = 3;
internal const int CryptographicExceptionEvent = 4;

private const string EventSourceName = "Azure-Security-KeyVault-Keys";

private KeysEventSource() : base(EventSourceName, EventSourceSettings.Default, AzureEventSourceListener.TraitName, AzureEventSourceListener.TraitValue) { }

public static KeysEventSource Singleton { get; } = new KeysEventSource();

[NonEvent]
public void AlgorithmNotSupported<T>(string operation, T algorithm) where T : notnull
{
if (IsEnabled())
{
AlgorithmNotSupported(operation, algorithm.ToString());
}
}

[Event(AlgorithmNotSupportedEvent, Level = EventLevel.Verbose, Message = "The algorithm {1} is not supported on this machine. Will try the {0} operation in the service.")]
public void AlgorithmNotSupported(string operation, string algorithm) => WriteEvent(AlgorithmNotSupportedEvent, operation, algorithm);

[NonEvent]
public void KeyTypeNotSupported(string operation, KeyVaultKey key)
{
if (IsEnabled())
{
string keyType = key?.KeyType.ToString() ?? "(null)";
KeyTypeNotSupported(operation, keyType);
}
}

[Event(KeyTypeNotSupportedEvent, Level = EventLevel.Verbose, Message = "The key type {1} is not supported on this machine. Will try the {0} operation in the service.")]
public void KeyTypeNotSupported(string operation, string keyType) => WriteEvent(KeyTypeNotSupportedEvent, operation, keyType);

[Event(PrivateKeyRequiredEvent, Level = EventLevel.Verbose, Message = "A private key is required for a {0} operation")]
public void PrivateKeyRequired(string operation) => WriteEvent(PrivateKeyRequiredEvent, operation);

[NonEvent]
public void CryptographicException(string operation, Exception ex)
{
if (IsEnabled())
{
string message = FormatException(ex);
CryptographicException(operation, message);
}
}

[Event(CryptographicExceptionEvent, Level = EventLevel.Informational, Message = "A cryptographic exception occured: {1}.\r\nWill try the {0} operation in the service.")]
public void CryptographicException(string operation, string message) => WriteEvent(CryptographicExceptionEvent, operation, message);

private static string FormatException(Exception ex)
Comment thread
heaths marked this conversation as resolved.
Outdated
{
StringBuilder sb = new StringBuilder();
bool nest = false;

do
{
if (nest)
{
// Format how Exception.ToString() would.
sb.AppendLine()
.Append(" ---> ");
}

// Do not include StackTrace, but do include HResult (often useful for CryptographicExceptions or IOExceptions).
sb.Append(ex.GetType().FullName)
.Append(" (0x")
.Append(ex.HResult.ToString("x", CultureInfo.InvariantCulture))
.Append("): ")
.Append(ex.Message);

ex = ex.InnerException;
nest = true;
}
while (ex != null);

return sb.ToString();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
</PropertyGroup>

<Import Project="..\..\..\core\Azure.Core\tests\TestFramework.props" />
<Import Project="..\..\Azure.Security.KeyVault.Shared\tests\Azure.Security.KeyVault.Shared.Tests.projitems" Label="Shared" />

<ItemGroup>
<PackageReference Include="nunit" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ public void SupportsOperationUnsupportedCurve()

EcCryptographyProvider client = new EcCryptographyProvider(new KeyVaultKey { Key = jwk });

Assert.IsFalse(client.SupportsOperation(KeyOperation.Sign));
// The provider caches the original allow key operations to facilitate tracing. Operation will still be sent to the service.
Assert.IsTrue(client.SupportsOperation(KeyOperation.Sign));
}

[Test]
Expand Down
Loading