diff --git a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/AlgorithmResolver.cs b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/AlgorithmResolver.cs index aaf05d00cb62..0f1393a48381 100644 --- a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/AlgorithmResolver.cs +++ b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/AlgorithmResolver.cs @@ -33,7 +33,7 @@ static AlgorithmResolver() Default.AddAlgorithm( Rs256.AlgorithmName, new Rs256() ); -#if NET45 +#if FullNetFx Default.AddAlgorithm( RsNull.AlgorithmName, new RsNull() ); #endif } diff --git a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/Algorithms/NativeMethods.cs b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/Algorithms/NativeMethods.cs index 5d46ffbe1935..52629b8f9d55 100644 --- a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/Algorithms/NativeMethods.cs +++ b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/Algorithms/NativeMethods.cs @@ -2,7 +2,7 @@ // Licensed under the MIT License. See License.txt in the project root for // license information. -#if NET45 +#if FullNetFx using System; using System.IO; diff --git a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/Algorithms/Rs256.cs b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/Algorithms/Rs256.cs index 8b193279a95b..874e73e8a7f0 100644 --- a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/Algorithms/Rs256.cs +++ b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/Algorithms/Rs256.cs @@ -53,7 +53,7 @@ public byte[] Sign( byte[] digest ) if ( digest.Length != 32 ) throw new ArgumentOutOfRangeException( "digest", "The digest must be 32 bytes for SHA-256" ); -#if NET45 +#if FullNetFx if ( _key is RSACryptoServiceProvider ) { return ((RSACryptoServiceProvider)_key).SignHash( digest, OID_OIWSEC_SHA256 ); @@ -79,7 +79,7 @@ public bool Verify( byte[] digest, byte[] signature ) throw new ArgumentNullException( "signature" ); -#if NET45 +#if FullNetFx if ( _key is RSACryptoServiceProvider ) { return ((RSACryptoServiceProvider)_key).VerifyHash( digest, OID_OIWSEC_SHA256, signature ); diff --git a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/Algorithms/RsNull.cs b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/Algorithms/RsNull.cs index 2388ad61a2b1..4caab9f9c056 100644 --- a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/Algorithms/RsNull.cs +++ b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/Algorithms/RsNull.cs @@ -4,7 +4,7 @@ // license information. // -#if NET45 +#if FullNetFx using System; using System.Security.Cryptography; diff --git a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/Algorithms/Rsa15.cs b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/Algorithms/Rsa15.cs index 0432048d3975..e1122dfd3b85 100644 --- a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/Algorithms/Rsa15.cs +++ b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/Algorithms/Rsa15.cs @@ -82,7 +82,7 @@ public byte[] TransformFinalBlock( byte[] inputBuffer, int inputOffset, int inpu { byte[] block = inputBuffer.Skip( inputOffset ).Take( inputCount ).ToArray(); -#if NET45 +#if FullNetFx if ( _csp is RSACryptoServiceProvider ) { return ( ( RSACryptoServiceProvider )_csp ).Decrypt( block, false ); @@ -147,7 +147,7 @@ public byte[] TransformFinalBlock( byte[] inputBuffer, int inputOffset, int inpu { byte[] block = inputBuffer.Skip( inputOffset ).Take( inputCount ).ToArray(); -#if NET45 +#if FullNetFx if ( _csp is RSACryptoServiceProvider ) { return ( ( RSACryptoServiceProvider )_csp ).Encrypt( block, false ); diff --git a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/Algorithms/RsaOaep.cs b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/Algorithms/RsaOaep.cs index 7f6aac52e382..fddea5f2f62b 100644 --- a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/Algorithms/RsaOaep.cs +++ b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/Algorithms/RsaOaep.cs @@ -85,7 +85,7 @@ public byte[] TransformFinalBlock( byte[] inputBuffer, int inputOffset, int inpu { byte[] block = inputBuffer.Skip( inputOffset ).Take( inputCount ).ToArray(); -#if NET45 +#if FullNetFx if ( _csp is RSACryptoServiceProvider ) { return ( ( RSACryptoServiceProvider )_csp ).Decrypt( block, true ); @@ -150,7 +150,7 @@ public byte[] TransformFinalBlock( byte[] inputBuffer, int inputOffset, int inpu { byte[] block = inputBuffer.Skip( inputOffset ).Take( inputCount ).ToArray(); -#if NET45 +#if FullNetFx if ( _csp is RSACryptoServiceProvider ) { return ( ( RSACryptoServiceProvider )_csp ).Encrypt( block, true ); diff --git a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/IncrementalHash.cs b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/IncrementalHash.cs index 9fdb364106e4..54e7cf89cd54 100644 --- a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/IncrementalHash.cs +++ b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/IncrementalHash.cs @@ -4,7 +4,7 @@ // license information. // -#if NET45 +#if FullNetFx using System; using System.Security.Cryptography; diff --git a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/TaskExtensions.cs b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/TaskExtensions.cs index e7553eb9c86d..cb21a358577e 100644 --- a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/TaskExtensions.cs +++ b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.Cryptography/TaskExtensions.cs @@ -4,7 +4,7 @@ // license information. // -#if NET45 +#if FullNetFx using System; using System.Threading.Tasks; diff --git a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey.Tests/WebKeyEcValidationTest.cs b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey.Tests/WebKeyEcValidationTest.cs new file mode 100644 index 000000000000..d0a250052213 --- /dev/null +++ b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey.Tests/WebKeyEcValidationTest.cs @@ -0,0 +1,204 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for +// license information. +// +using System; +using System.Linq; +using System.Security.Cryptography; +using Xunit; + +// ReSharper disable InconsistentNaming + +namespace Microsoft.Azure.KeyVault.WebKey.Tests +{ + public class WebKeyEcValidationTest + { + + // Encrypt and Decrypt methods used by the test cases. + private static byte[] _data = new byte[] { 1, 3, 2, 7 }; + private static string[] signOperations = new[] { JsonWebKeyOperation.Sign, JsonWebKeyOperation.Verify }; + private static CngKeyCreationParameters cngKeyCreationParameters = new CngKeyCreationParameters + { + ExportPolicy = CngExportPolicies.AllowPlaintextExport, + KeyCreationOptions = CngKeyCreationOptions.OverwriteExistingKey, + KeyUsage = CngKeyUsages.Signing + }; + + private void SignVerify(ECDsa privateKey, ECDsa publicKey) + { + using (var sha256 = SHA256.Create()) + { + byte[] hash = sha256.ComputeHash(_data); + + var signedHash = privateKey.SignHash(hash); + var verifiedHash = publicKey.VerifyHash(hash, signedHash); + Assert.True(verifiedHash); + } + } + + private void SignVerify(ECDsa ecdsa) + { + SignVerify(ecdsa, ecdsa); + } + + [Fact] + public void RoundTripP256Test() + { + if (!IsECDsaSupported()) + return; + + var usePrivateKey = true; + + using (var ecdsa = new ECDsaCng(CngKey.Create(CngAlgorithm.ECDsaP256, "P256ecdsa", cngKeyCreationParameters))) + { + var jwk = new JsonWebKey(ecdsa, usePrivateKey); + VerifyJsonWebKeyEcdsa(jwk, usePrivateKey, JsonWebKeyECCurve.P256, signOperations); + + var ecdsa_jwk = jwk.ToECDsa(usePrivateKey); + + Assert.Equal(ecdsa_jwk.KeySize, ecdsa.KeySize); +#if FullNetFx + Assert.Equal(ecdsa_jwk.SignatureAlgorithm, ecdsa.SignatureAlgorithm); +#endif + SignVerify(ecdsa_jwk); + } + } + + [Fact] + public void RoundTripP384Test() + { + if (!IsECDsaSupported()) + return; + + var usePrivateKey = true; + + using (var ecdsa = new ECDsaCng(CngKey.Create(CngAlgorithm.ECDsaP384, "P384ecdsa", cngKeyCreationParameters))) + { + var jwk = new JsonWebKey(ecdsa, usePrivateKey); + VerifyJsonWebKeyEcdsa(jwk, usePrivateKey, JsonWebKeyECCurve.P384, signOperations); + + var ecdsa_jwk = jwk.ToECDsa(usePrivateKey); + + Assert.Equal(ecdsa_jwk.KeySize, ecdsa.KeySize); +#if FullNetFx + Assert.Equal(ecdsa_jwk.SignatureAlgorithm, ecdsa.SignatureAlgorithm); +#endif + SignVerify(ecdsa_jwk); + } + } + + [Fact] + public void RoundTripP521Test() + { + if (!IsECDsaSupported()) + return; + + var usePrivateKey = true; + + using (var ecdsa = new ECDsaCng(CngKey.Create(CngAlgorithm.ECDsaP521, "P521ecdsa", cngKeyCreationParameters))) + { + var jwk = new JsonWebKey(ecdsa, usePrivateKey); + VerifyJsonWebKeyEcdsa(jwk, usePrivateKey, JsonWebKeyECCurve.P521, signOperations); + + var ecdsa_jwk = jwk.ToECDsa(usePrivateKey); + + Assert.Equal(ecdsa_jwk.KeySize, ecdsa.KeySize); +#if FullNetFx + Assert.Equal(ecdsa_jwk.SignatureAlgorithm, ecdsa.SignatureAlgorithm); +#endif + SignVerify(ecdsa_jwk); + } + } + + [Fact] + public void PublicOnlyKeyTest() + { + if (!IsECDsaSupported()) + return; + + var usePrivateKey = false; + + using (var ecdsa = new ECDsaCng(CngKey.Create(CngAlgorithm.ECDsaP256, "P256ecdsa", cngKeyCreationParameters))) + { + var jwk = new JsonWebKey(ecdsa, usePrivateKey); + VerifyJsonWebKeyEcdsa(jwk, usePrivateKey, JsonWebKeyECCurve.P256, signOperations); + + var ecdsa_jwk = jwk.ToECDsa(usePrivateKey); + + Assert.Equal(ecdsa_jwk.KeySize, ecdsa.KeySize); +#if FullNetFx + Assert.Equal(ecdsa_jwk.SignatureAlgorithm, ecdsa.SignatureAlgorithm); + // Private key doesn't exist. Sign should fail with Key is missing. + Assert.Throws(()=>SignVerify(ecdsa_jwk)); +#endif + } + } + + [Fact] + public void PrivateSignPublicVerifyTest() + { + if (!IsECDsaSupported()) + return; + + using (var ecdsa = new ECDsaCng(CngKey.Create(CngAlgorithm.ECDsaP256, "P256ecdsa", cngKeyCreationParameters))) + { + var publicKey = new JsonWebKey(ecdsa, false); + var privateKey = new JsonWebKey(ecdsa, true); + SignVerify(privateKey.ToECDsa(true), publicKey.ToECDsa(false)); + } + } + + [Fact] + public void PublicSignPrivateVerifyTest() + { + if (!IsECDsaSupported()) + return; + + using (var ecdsa = new ECDsaCng(CngKey.Create(CngAlgorithm.ECDsaP256, "P256ecdsa", cngKeyCreationParameters))) + { + var publicKey = new JsonWebKey(ecdsa, false); + Assert.Throws(() => publicKey.ToECDsa(true)); + } + } + + /// + /// Temporary hack to make build pass on Linux with .NET Core. + /// + private static bool IsECDsaSupported() + { + try + { + Console.WriteLine("Attempting to access property {0}...", CngAlgorithm.ECDsaP256); + return true; + } catch (PlatformNotSupportedException) + { + return false; + } + } + + private void VerifyJsonWebKeyEcdsa(JsonWebKey jwk, bool usePrivateKey, string eccurve, string[] ops) + { + if(usePrivateKey) + Assert.NotNull(jwk.D); + else + Assert.Null(jwk.D); + + Assert.NotNull(jwk.X); + Assert.NotNull(jwk.Y); + Assert.Equal(jwk.ECCurve, eccurve); + Assert.True(ops.SequenceEqual(jwk.KeyOps)); + Assert.Equal(jwk.Kty, JsonWebKeyType.EllipticCurve); + + Assert.Null(jwk.DP); + Assert.Null(jwk.DQ); + Assert.Null(jwk.E); + Assert.Null(jwk.K); + Assert.Null(jwk.N); + Assert.Null(jwk.P); + Assert.Null(jwk.Q); + Assert.Null(jwk.QI); + Assert.Null(jwk.T); + } + } +} \ No newline at end of file diff --git a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey.Tests/WebKeyHsmRsaValidationTest.cs b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey.Tests/WebKeyHsmRsaValidationTest.cs index b5a7c6d75d17..825734832670 100644 --- a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey.Tests/WebKeyHsmRsaValidationTest.cs +++ b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey.Tests/WebKeyHsmRsaValidationTest.cs @@ -4,11 +4,6 @@ // using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Security.Cryptography; using Xunit; namespace Microsoft.Azure.KeyVault.WebKey.Tests diff --git a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey.Tests/WebKeyOperationsTest.cs b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey.Tests/WebKeyOperationsTest.cs index 7f99d813f23d..df7d139b8d56 100644 --- a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey.Tests/WebKeyOperationsTest.cs +++ b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey.Tests/WebKeyOperationsTest.cs @@ -62,6 +62,8 @@ private static void CheckInstance(object key, string kty) switch (kty) { case JsonWebKeyType.Octet: + case JsonWebKeyType.EllipticCurve: + case JsonWebKeyType.EllipticCurveHsm: case JsonWebKeyType.Rsa: case JsonWebKeyType.RsaHsm: // Supported types must have ClearMemory() implemented. diff --git a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey.Tests/WebKeyRsaValidationTest.cs b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey.Tests/WebKeyRsaValidationTest.cs index 29e8d8d9d7d8..8c2bfede1fae 100644 --- a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey.Tests/WebKeyRsaValidationTest.cs +++ b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey.Tests/WebKeyRsaValidationTest.cs @@ -27,7 +27,7 @@ private static byte[] Decrypt( RSA key, byte[] cipherText ) { byte[] plainText = null; -#if NET452 +#if FullNetFx if ( key is RSACryptoServiceProvider ) { plainText = ( ( RSACryptoServiceProvider )key ).Decrypt( cipherText, true ); @@ -52,7 +52,7 @@ private static byte[] Encrypt( RSA key ) { byte[] cipherText = null; -#if NET452 +#if FullNetFx if ( key is RSACryptoServiceProvider ) { cipherText = ( ( RSACryptoServiceProvider )key ).Encrypt( _plainText, true ); diff --git a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey/ECParameters.cs b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey/ECParameters.cs new file mode 100644 index 000000000000..d313246ae505 --- /dev/null +++ b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey/ECParameters.cs @@ -0,0 +1,107 @@ +using System; +using System.Linq; +using System.Security.Cryptography; + +namespace Microsoft.Azure.KeyVault.WebKey +{ + /// + /// EC paramters class. This is supported in .NET framework v4.7 but not in the current .net version. + /// + public class ECParameters + { + /// + /// X coordinate for the Elliptic Curve point. + /// + public byte[] X { get; set; } + + /// + /// Y coordinate for the Elliptic Curve point. + /// + public byte[] Y { get; set; } + + /// + /// ECC private key. + /// + public byte[] D { get; set; } + + /// + /// The curve for Elliptic Curve Cryptography(ECC) algorithms + /// + public string Curve { get; set; } + + internal EcKeyBlob GetKeyBlob(bool includePrivateParameters) + { + if (X == null || Y == null) + throw new ArgumentException("Invalid EC parameter(s)."); + + KeyBlobMagicNumber magic; + int length = X.Length; + var cngKeyBlobFormat = CngKeyBlobFormat.EccPublicBlob; + + if (includePrivateParameters) + { + if (D == null) + throw new CryptographicException("Private key material D is missing."); + + switch (Curve) + { + case JsonWebKeyECCurve.P256: + magic = KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_P256_MAGIC; + break; + case JsonWebKeyECCurve.P384: + magic = KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_P384_MAGIC; + break; + case JsonWebKeyECCurve.P521: + magic = KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_P521_MAGIC; + break; + default: + throw new CryptographicException(string.Format("Invalid curve {0}.", Curve)); + } + + cngKeyBlobFormat = CngKeyBlobFormat.EccPrivateBlob; + } + else + { + switch (Curve) + { + case JsonWebKeyECCurve.P256: + magic = KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_P256_MAGIC; + break; + case JsonWebKeyECCurve.P384: + magic = KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_P384_MAGIC; + break; + case JsonWebKeyECCurve.P521: + magic = KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_P521_MAGIC; + break; + default: + throw new CryptographicException(string.Format("Invalid curve {0}.", Curve)); + } + } + var bMagic = BitConverter.GetBytes((int)magic); + var bLength = BitConverter.GetBytes(length); + return new EcKeyBlob() + { + KeyBlob = includePrivateParameters ? ConcatBytes(bMagic, bLength, X, Y, D) : ConcatBytes(bMagic, bLength, X, Y), + KeyBlobFormat = cngKeyBlobFormat + }; + } + + private byte[] ConcatBytes(params byte[][] bytes) + { + byte[] result = new byte[bytes.Sum(b => b.Length)]; + int offset = 0; + foreach (byte[] b in bytes) + { + Buffer.BlockCopy(b, 0, result, offset, b.Length); + offset += b.Length; + } + return result; + } + + internal class EcKeyBlob + { + public byte[] KeyBlob { get; internal set; } + public CngKeyBlobFormat KeyBlobFormat { get; internal set; } + } + } +} diff --git a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey/EccExtension.cs b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey/EccExtension.cs new file mode 100644 index 000000000000..a0bd71e33b4e --- /dev/null +++ b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey/EccExtension.cs @@ -0,0 +1,110 @@ +using System; +using System.Linq; +using System.Security.Cryptography; + +namespace Microsoft.Azure.KeyVault.WebKey +{ + + /// + /// Numbers that indicate the type of blob. + /// + enum KeyBlobMagicNumber : int + { + BCRYPT_ECDSA_PUBLIC_P256_MAGIC = 0x31534345, + BCRYPT_ECDSA_PRIVATE_P256_MAGIC = 0x32534345, + BCRYPT_ECDSA_PUBLIC_P384_MAGIC = 0x33534345, + BCRYPT_ECDSA_PRIVATE_P384_MAGIC = 0x34534345, + BCRYPT_ECDSA_PUBLIC_P521_MAGIC = 0x35534345, + BCRYPT_ECDSA_PRIVATE_P521_MAGIC = 0x36534345 + } + + /// + /// Because the current version of ECC is not supporting some of the operations needed for WebKey, + /// those operations are added as ECC extension. + /// + public static class EccExtension + { + // Blob structure based on https://msdn.microsoft.com/en-us/library/windows/desktop/aa375520(v=vs.85).aspx + // and bcrypt https://github.com/dotnet/corefx/blob/master/src/Common/src/Interop/Windows/BCrypt/Interop.Blobs.cs + + /// + /// Exports EC parameters by exporting the key blob material and deserializing the blob to + /// its constructive EC parameters. + /// + /// The ECDsa CNG provider + /// Determines whether the private key part is to be exported. + /// + public static ECParameters ExportParameters(this ECDsaCng ecdsaProvider, bool includePrivateParameters) + { + + if (ecdsaProvider == null) + throw new ArgumentNullException(nameof(ecdsaProvider)); + + var cngKeyBlobFormat = includePrivateParameters ? CngKeyBlobFormat.EccPrivateBlob : CngKeyBlobFormat.EccPublicBlob; + var ecBlob = ecdsaProvider.Key.Export(cngKeyBlobFormat); + + // BLOB structure + //------------------------------------------------------- + // MAGIC | Key size (L) | X | Y | [D] | + // 4 bytes | 4 bytes | L bytes | L bytes | L bytes | + //------------------------------------------------------- + var offset = 0; + var bMagic = new byte[4]; + var bLength = new byte[4]; + Array.Copy(ecBlob, offset, bMagic, 0, bMagic.Length); + Array.Copy(ecBlob, offset += 4, bLength, 0, bLength.Length); + + var length = BitConverter.ToInt32(bLength, 0); + var magic = BitConverter.ToInt32(bMagic, 0); + VerifyMagic(magic, length, includePrivateParameters); + + var ecParameters = new ECParameters(); + ecParameters.Curve = length == 32 ? JsonWebKeyECCurve.P256 : length == 48 ? JsonWebKeyECCurve.P384 : JsonWebKeyECCurve.P521; + + ecParameters.X = new byte[length]; + ecParameters.Y = new byte[length]; + Array.Copy(ecBlob, offset += 4, ecParameters.X, 0, length); + Array.Copy(ecBlob, offset += length, ecParameters.Y, 0, length); + + if (includePrivateParameters) + { + ecParameters.D = new byte[length]; + Array.Copy(ecBlob, offset += length, ecParameters.D, 0, length); + } + return ecParameters; + } + + private static void VerifyMagic(int magic, int length, bool isPrivate) + { + if (!validLength.Contains(length)) + throw new CryptographicException(string.Format("Invalid key length {0}. Valid lengths are {1}", length, string.Join(",", validLength))); + + var isValid = false; + switch (magic) + { + case (int)KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_P256_MAGIC: + isValid = isPrivate && length == 32; + break; + case (int)KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_P256_MAGIC: + isValid = !isPrivate && length == 32; + break; + case (int)KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_P384_MAGIC: + isValid = isPrivate && length == 48; + break; + case (int)KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_P384_MAGIC: + isValid = !isPrivate && length == 48; + break; + case (int)KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_P521_MAGIC: + isValid = isPrivate && length == 66; + break; + case (int)KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_P521_MAGIC: + isValid = !isPrivate && length == 66; + break; + } + if (!isValid) + throw new CryptographicException(string.Format("Invalid magic {0}.", magic)); + } + + private static int[] validLength = new[] { 32, 48, 66 }; + } +} diff --git a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey/JsonWebKey.cs b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey/JsonWebKey.cs index bd56cf4d5278..0f144851e27f 100644 --- a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey/JsonWebKey.cs +++ b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey/JsonWebKey.cs @@ -24,25 +24,31 @@ public class JsonWebKey internal const string Property_KeyOps = "key_ops"; // RSA Key Property Names - internal const string Property_D = "d"; - internal const string Property_DP = "dp"; - internal const string Property_DQ = "dq"; - internal const string Property_E = "e"; - internal const string Property_QI = "qi"; - internal const string Property_N = "n"; - internal const string Property_P = "p"; - internal const string Property_Q = "q"; + internal const string Property_D = "d"; + internal const string Property_DP = "dp"; + internal const string Property_DQ = "dq"; + internal const string Property_E = "e"; + internal const string Property_QI = "qi"; + internal const string Property_N = "n"; + internal const string Property_P = "p"; + internal const string Property_Q = "q"; + + // ECC Key Property Names + // Property_D the same as RSA Key + internal const string Property_Crv = "crv"; + internal const string Property_X = "x"; + internal const string Property_Y = "y"; // Symmetric Key Property Names - internal const string Property_K = "k"; + internal const string Property_K = "k"; // HSM Token Property Names - internal const string Property_T = "key_hsm"; + internal const string Property_T = "key_hsm"; /// /// Key Identifier /// - [JsonProperty( DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, PropertyName = Property_Kid, Required = Required.Default )] + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, PropertyName = Property_Kid, Required = Required.Default)] public string Kid { get; set; } /// @@ -50,79 +56,106 @@ public class JsonWebKey /// Curve, RSA, HSM, Octet, usually RSA. Possible values include: /// 'EC', 'RSA', 'RSA-HSM', 'oct' /// - [JsonProperty( DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, PropertyName = Property_Kty, Required = Required.Always )] + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, PropertyName = Property_Kty, Required = Required.Always)] public string Kty { get; set; } /// /// Supported Key Operations /// - [JsonProperty( DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, PropertyName = Property_KeyOps, Required = Required.Default )] + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, PropertyName = Property_KeyOps, Required = Required.Default)] public IList KeyOps { get; set; } + /// + /// The curve for Elliptic Curve Cryptography (ECC) algorithms + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, PropertyName = Property_Crv, Required = Required.Default)] + public string ECCurve { get; set; } + #region RSA Public Key Parameters /// /// RSA modulus, in Base64. /// - [JsonProperty( DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, PropertyName = Property_N, Required = Required.Default )] - [JsonConverter( typeof( Base64UrlJsonConverter ) )] + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, PropertyName = Property_N, Required = Required.Default)] + [JsonConverter(typeof(Base64UrlJsonConverter))] public byte[] N { get; set; } /// /// RSA public exponent, in Base64. /// - [JsonProperty( DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, PropertyName = Property_E, Required = Required.Default )] - [JsonConverter( typeof( Base64UrlJsonConverter ) )] + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, PropertyName = Property_E, Required = Required.Default)] + [JsonConverter(typeof(Base64UrlJsonConverter))] public byte[] E { get; set; } #endregion #region RSA Private Key Parameters - /// - /// RSA private exponent - /// - [JsonProperty( DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, PropertyName = Property_D, Required = Required.Default )] - [JsonConverter( typeof( Base64UrlJsonConverter ) )] - public byte[] D { get; set; } - /// /// RSA Private Key Parameter /// - [JsonProperty( DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, PropertyName = Property_DP, Required = Required.Default )] - [JsonConverter( typeof( Base64UrlJsonConverter ) )] + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, PropertyName = Property_DP, Required = Required.Default)] + [JsonConverter(typeof(Base64UrlJsonConverter))] public byte[] DP { get; set; } /// /// RSA Private Key Parameter /// - [JsonProperty( DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, PropertyName = Property_DQ, Required = Required.Default )] - [JsonConverter( typeof( Base64UrlJsonConverter ) )] + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, PropertyName = Property_DQ, Required = Required.Default)] + [JsonConverter(typeof(Base64UrlJsonConverter))] public byte[] DQ { get; set; } /// /// RSA Private Key Parameter /// - [JsonProperty( DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, PropertyName = Property_QI, Required = Required.Default )] - [JsonConverter( typeof( Base64UrlJsonConverter ) )] + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, PropertyName = Property_QI, Required = Required.Default)] + [JsonConverter(typeof(Base64UrlJsonConverter))] public byte[] QI { get; set; } /// /// RSA secret prime /// - [JsonProperty( DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, PropertyName = Property_P, Required = Required.Default )] - [JsonConverter( typeof( Base64UrlJsonConverter ) )] + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, PropertyName = Property_P, Required = Required.Default)] + [JsonConverter(typeof(Base64UrlJsonConverter))] public byte[] P { get; set; } /// /// RSA secret prime, with p < q /// - [JsonProperty( DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, PropertyName = Property_Q, Required = Required.Default )] - [JsonConverter( typeof( Base64UrlJsonConverter ) )] + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, PropertyName = Property_Q, Required = Required.Default)] + [JsonConverter(typeof(Base64UrlJsonConverter))] public byte[] Q { get; set; } #endregion + #region EC Public Key Parameters + + /// + /// X coordinate for the Elliptic Curve point. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, PropertyName = Property_X, Required = Required.Default)] + [JsonConverter(typeof(Base64UrlJsonConverter))] + public byte[] X { get; set; } + + /// + /// Y coordinate for the Elliptic Curve point. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, PropertyName = Property_Y, Required = Required.Default)] + [JsonConverter(typeof(Base64UrlJsonConverter))] + public byte[] Y { get; set; } + + #endregion + + #region EC and RSA Private Key Parameters + + /// + /// RSA private exponent or ECC private key. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, PropertyName = Property_D, Required = Required.Default)] + [JsonConverter(typeof(Base64UrlJsonConverter))] + public byte[] D { get; set; } + + #endregion #region Symmetric Key Parameters @@ -130,7 +163,7 @@ public class JsonWebKey /// Symmetric key /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, PropertyName = Property_K, Required = Required.Default)] - [JsonConverter(typeof( Base64UrlJsonConverter ))] + [JsonConverter(typeof(Base64UrlJsonConverter))] public byte[] K { get; set; } #endregion @@ -139,7 +172,7 @@ public class JsonWebKey /// HSM Token, used with "Bring Your Own Key" /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, PropertyName = Property_T, Required = Required.Default)] - [JsonConverter(typeof( Base64UrlJsonConverter ))] + [JsonConverter(typeof(Base64UrlJsonConverter))] public byte[] T { get; set; } /// @@ -155,7 +188,6 @@ public JsonWebKey() /// Converts an AES object to a WebKey of type Octet /// /// - /// public JsonWebKey(Aes aesProvider) { if (aesProvider == null) @@ -165,13 +197,39 @@ public JsonWebKey(Aes aesProvider) K = aesProvider.Key; } + /// + /// Converts an ECDSA object to a WebKey of type EC + /// + /// + public JsonWebKey(ECDsaCng ecdsaProvider, bool includePrivateParameters = false) + : this(ecdsaProvider.ExportParameters(includePrivateParameters)) + { + KeyOps = JsonWebKeyOperation.GetKeyOperations(ecdsaProvider.Key.KeyUsage); + } + + /// + /// Converts a ECParameters object to a WebKey of type EC. + /// + /// The EC object to convert + /// A WebKey representing the EC object + public JsonWebKey(ECParameters ecParameters) + { + Kty = JsonWebKeyType.EllipticCurve; + + ECCurve = ecParameters.Curve; + D = ecParameters.D; + X = ecParameters.X; + Y = ecParameters.Y; + } + /// /// Converts a RSA object to a WebKey of type RSA. /// /// The RSA object to convert /// True to include the RSA private key parameters /// A WebKey representing the RSA object - public JsonWebKey(RSA rsaProvider, bool includePrivateParameters = false) : this(rsaProvider.ExportParameters(includePrivateParameters)) + public JsonWebKey(RSA rsaProvider, bool includePrivateParameters = false) + : this(rsaProvider.ExportParameters(includePrivateParameters)) { } @@ -195,9 +253,9 @@ public JsonWebKey(RSAParameters rsaParameters) Q = rsaParameters.Q; } - public override bool Equals( object obj ) + public override bool Equals(object obj) { - if ( obj == null ) + if (obj == null) return false; if (obj == this) @@ -205,10 +263,10 @@ public override bool Equals( object obj ) JsonWebKey other = obj as JsonWebKey; - if ( other == null ) + if (other == null) return false; - return this.Equals( other ); + return this.Equals(other); } /// @@ -216,9 +274,9 @@ public override bool Equals( object obj ) /// /// the object to compare with /// whether the objects are equals - public bool Equals( JsonWebKey other ) + public bool Equals(JsonWebKey other) { - if ( other == null ) + if (other == null) return false; if (!string.Equals(Kid, other.Kid)) @@ -230,6 +288,9 @@ public bool Equals( JsonWebKey other ) if (!AreEqual(KeyOps, other.KeyOps)) return false; + if (!string.Equals(ECCurve, other.ECCurve)) + return false; + if (!AreEqual(K, other.K)) return false; @@ -240,6 +301,12 @@ public bool Equals( JsonWebKey other ) if (!AreEqual(E, other.E)) return false; + if (!AreEqual(X, other.X)) + return false; + + if (!AreEqual(Y, other.Y)) + return false; + // Private parameters if (!AreEqual(D, other.D)) return false; @@ -280,16 +347,20 @@ public override int GetHashCode() hashCode += Kid.GetHashCode(); } - switch ( Kty ) + switch (Kty) { + case JsonWebKeyType.EllipticCurve: + case JsonWebKeyType.EllipticCurveHsm: + return hashCode += GetHashCode(X); + case JsonWebKeyType.Octet: - return hashCode += GetHashCode( K ); + return hashCode += GetHashCode(K); case JsonWebKeyType.Rsa: - return hashCode += GetHashCode( N ); + return hashCode += GetHashCode(N); case JsonWebKeyType.RsaHsm: - return hashCode += GetHashCode( T ); + return hashCode += GetHashCode(T); default: return hashCode; @@ -297,17 +368,17 @@ public override int GetHashCode() } - private int GetHashCode( byte[] obj ) + private int GetHashCode(byte[] obj) { - if ( obj == null || obj.Length == 0 ) + if (obj == null || obj.Length == 0) return 0; var hashCode = 0; // Rotate by 3 bits and XOR the new value. - for ( var i = 0; i < obj.Length; i++ ) - hashCode = ( hashCode << 3 ) | ( hashCode >> ( 29 ) ) ^ obj[i]; - + for (var i = 0; i < obj.Length; i++) + hashCode = (hashCode << 3) | (hashCode >> (29)) ^ obj[i]; + return hashCode; } @@ -317,15 +388,19 @@ private int GetHashCode( byte[] obj ) /// True if the object has private key; false otherwise. public virtual bool HasPrivateKey() { - switch ( Kty ) + switch (Kty) { + case JsonWebKeyType.EllipticCurve: + case JsonWebKeyType.EllipticCurveHsm: + return D != null; + case JsonWebKeyType.Octet: return K != null; case JsonWebKeyType.Rsa: case JsonWebKeyType.RsaHsm: var privateParameters = new bool[] { D != null, DP != null, DQ != null, QI != null, P != null, Q != null }; - return privateParameters.All( ( value ) => value ); + return privateParameters.All((value) => value); default: return false; @@ -340,7 +415,7 @@ public virtual bool HasPrivateKey() public virtual bool IsValid() { // MUST have kty - if ( string.IsNullOrEmpty( Kty ) ) + if (string.IsNullOrEmpty(Kty)) return false; // Validate Key Operations @@ -351,10 +426,11 @@ public virtual bool IsValid() } // Per-kty validation - switch ( Kty ) + switch (Kty) { case JsonWebKeyType.EllipticCurve: - break; + case JsonWebKeyType.EllipticCurveHsm: + return IsValidEc(); case JsonWebKeyType.Octet: return IsValidOctet(); @@ -369,6 +445,24 @@ public virtual bool IsValid() return false; } + private bool IsValidEc() + { + // MUST have public key parameters + if (X == null || Y == null || ECCurve == null || X.Length != Y.Length) + return false; + + switch(ECCurve) + { + case JsonWebKeyECCurve.P256: + return X.Length == 32; + case JsonWebKeyECCurve.P384: + return X.Length == 48; + case JsonWebKeyECCurve.P521: + return X.Length == 66; + } + return true; + } + private bool IsValidOctet() { if ( K != null ) @@ -506,6 +600,23 @@ public RSAParameters ToRSAParameters(bool includePrivateParameters = false) return result; } + /// + /// Converts a WebKey of type EC or EC-HSM to a ECDsa object + /// + /// Determines whether private key material, if available, is included + /// An initialized ECDsa instance + public ECDsa ToECDsa(bool includePrivateParameters = false) + { + if (!string.Equals(JsonWebKeyType.EllipticCurve, Kty) + && !string.Equals(JsonWebKeyType.EllipticCurveHsm, Kty)) + throw new ArgumentException("JsonWebKey is not an Elliptic Curve key"); + + var ecParameters = new ECParameters { Curve = ECCurve, D = this.D, X = this.X, Y = this.Y }; + var ecKeyblob = ecParameters.GetKeyBlob(includePrivateParameters); + + return new ECDsaCng(CngKey.Import(ecKeyblob.KeyBlob, ecKeyblob.KeyBlobFormat)); + } + private static void VerifyNonZero(string name, byte[] value) { if (value != null && value.Length > 0) @@ -609,8 +720,15 @@ public void ClearMemory() ZeroArray(T); T = null; + // Elliptic curve + ZeroArray(X); + ZeroArray(Y); + X = Y = null; + switch (Kty) { + case JsonWebKeyType.EllipticCurve: + case JsonWebKeyType.EllipticCurveHsm: case JsonWebKeyType.Octet: case JsonWebKeyType.Rsa: case JsonWebKeyType.RsaHsm: diff --git a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey/JsonWebKeyECCurve.cs b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey/JsonWebKeyECCurve.cs new file mode 100644 index 000000000000..556edd90d422 --- /dev/null +++ b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey/JsonWebKeyECCurve.cs @@ -0,0 +1,43 @@ + +using System.Security.Cryptography; +using System.Linq; +using System.Collections.Generic; + +namespace Microsoft.Azure.KeyVault.WebKey +{ + /// + /// The curve for Elliptic Curve Cryptography (ECC) algorithms. + /// + public static class JsonWebKeyECCurve + { + public const string P256 = "P-256"; + public const string P384 = "P-384"; + public const string P521 = "P-521"; + + private static Dictionary cngAlgorithms; + + static JsonWebKeyECCurve() + { + cngAlgorithms = new Dictionary() + { + { P256, CngAlgorithm.ECDsaP256 }, + { P384, CngAlgorithm.ECDsaP384 }, + { P521, CngAlgorithm.ECDsaP521 } + }; + } + + public static CngAlgorithm GetECDsaCngAlgorithm(string curve) + { + if (!cngAlgorithms.ContainsKey(curve)) + throw new CryptographicException(string.Format("Unknown curve {0}", curve)); + return cngAlgorithms[curve]; + } + + /// + /// All curves for EC. Use clone to avoid FxCop violation + /// + public static string[] AllCurves => (string[])_allCurves.Clone(); + + private static readonly string[] _allCurves = { P256, P384, P521 }; + } +} diff --git a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey/JsonWebKeyOperations.cs b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey/JsonWebKeyOperations.cs index b8431f97f853..71d976222eeb 100644 --- a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey/JsonWebKeyOperations.cs +++ b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey/JsonWebKeyOperations.cs @@ -3,6 +3,11 @@ // license information. // +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; + namespace Microsoft.Azure.KeyVault.WebKey { @@ -18,6 +23,27 @@ public static class JsonWebKeyOperation public const string Wrap = "wrapKey"; public const string Unwrap = "unwrapKey"; + private static Dictionary cngOperations; + + static JsonWebKeyOperation() + { + cngOperations = new Dictionary() + { + { CngKeyUsages.None, new string[0] }, + { CngKeyUsages.Signing, new[] { Sign, Verify } }, + { CngKeyUsages.Decryption, new[] { Encrypt, Decrypt, Wrap, Unwrap } }, + { CngKeyUsages.AllUsages, AllOperations } + }; + } + + public static string[] GetKeyOperations(CngKeyUsages cngKeyUsages) + { + if (!cngOperations.ContainsKey(cngKeyUsages)) + throw new CryptographicException(string.Format("Unknown key usage {0}", cngKeyUsages)); + + return cngOperations[cngKeyUsages]; + } + /// /// All operations names. Use clone to avoid FxCop violation /// diff --git a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey/JsonWebKeySignatureAlgorithms.cs b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey/JsonWebKeySignatureAlgorithms.cs index c62f071ab8d7..a9c2759842ef 100644 --- a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey/JsonWebKeySignatureAlgorithms.cs +++ b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey/JsonWebKeySignatureAlgorithms.cs @@ -3,6 +3,8 @@ // license information. // +using System.Linq; + namespace Microsoft.Azure.KeyVault.WebKey { /// @@ -23,14 +25,29 @@ public static class JsonWebKeySignatureAlgorithm // RSASSA-PSS using SHA-512 and MGF1 with SHA-512 public const string PS512 = "PS512"; + // ECDSA using P-256 and SHA-256 + public const string ES256 = "ES256"; + // ECDSA using P-384 and SHA-384 + public const string ES384 = "ES384"; + // ECDSA using P-521 and SHA-512 + public const string ES512 = "ES512"; + /// /// All algorithms names. Use clone to avoid FxCop violation /// public static string[] AllAlgorithms { - get { return (string[])_allAlgorithms.Clone(); } + get { return AllRsaAlgorithms.Concat(AllEcAlgorithms).ToArray(); } } - private static readonly string[] _allAlgorithms = { RS256, RS384, RS512, RSNULL, PS256, PS384, PS512 }; + public static string[] AllRsaAlgorithms + { + get { return new[] { RS256, RS384, RS512, RSNULL, PS256, PS384, PS512 }; } + } + + public static string[] AllEcAlgorithms + { + get { return new[] { ES256, ES384, ES512 }; } + } } } diff --git a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey/JsonWebKeyTypes.cs b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey/JsonWebKeyTypes.cs index e24c6ae1e6c4..574164e11439 100644 --- a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey/JsonWebKeyTypes.cs +++ b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey/JsonWebKeyTypes.cs @@ -10,10 +10,11 @@ namespace Microsoft.Azure.KeyVault.WebKey /// public static class JsonWebKeyType { - public const string EllipticCurve = "EC"; - public const string Rsa = "RSA"; - public const string RsaHsm = "RSA-HSM"; - public const string Octet = "oct"; + public const string EllipticCurve = "EC"; + public const string EllipticCurveHsm = "EC-HSM"; + public const string Rsa = "RSA"; + public const string RsaHsm = "RSA-HSM"; + public const string Octet = "oct"; /// /// All types names. Use clone to avoid FxCop violation @@ -23,6 +24,6 @@ public static string[] AllTypes get { return (string[])_allTypes.Clone(); } } - private static readonly string[] _allTypes = { EllipticCurve, Rsa, RsaHsm, Octet }; + private static readonly string[] _allTypes = { EllipticCurve, EllipticCurveHsm, Rsa, RsaHsm, Octet }; } } diff --git a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey/Microsoft.Azure.KeyVault.WebKey.csproj b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey/Microsoft.Azure.KeyVault.WebKey.csproj index 2d68d49d8896..8d86dbfa8cce 100644 --- a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey/Microsoft.Azure.KeyVault.WebKey.csproj +++ b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault.WebKey/Microsoft.Azure.KeyVault.WebKey.csproj @@ -4,8 +4,8 @@ Microsoft.Azure.KeyVault.WebKey Microsoft Azure Key Vault WebKey Class Library Microsoft Azure Key Vault WebKey + 2.0.8-alpha2 Microsoft.Azure.KeyVault.WebKey - 2.0.7 Microsoft Azure key vault WebKey @@ -17,13 +17,13 @@ - + - + diff --git a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault/Generated/Models/KeyVaultErrorException.cs b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault/Generated/Models/KeyVaultErrorException.cs index cc9154d49976..107deb8720da 100644 --- a/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault/Generated/Models/KeyVaultErrorException.cs +++ b/src/SDKs/KeyVault/dataPlane/Microsoft.Azure.KeyVault/Generated/Models/KeyVaultErrorException.cs @@ -19,7 +19,7 @@ namespace Microsoft.Azure.KeyVault.Models /// Exception thrown for an invalid response with KeyVaultError /// information. /// -#if NET45 +#if FullNetFx [System.Serializable] #endif public class KeyVaultErrorException : RestException @@ -78,7 +78,7 @@ public KeyVaultErrorException(string message, System.Exception innerException) { } -#if NET45 +#if FullNetFx /// /// Initializes a new instance of the KeyVaultErrorException class. ///