| | 1 | | // Copyright (c) Microsoft Corporation. All rights reserved. |
| | 2 | | // Licensed under the MIT License. |
| | 3 | |
|
| | 4 | | using System; |
| | 5 | | using System.Security.Cryptography; |
| | 6 | | using System.Threading; |
| | 7 | | using Azure.Core; |
| | 8 | |
|
| | 9 | | namespace Azure.Security.KeyVault.Keys.Cryptography |
| | 10 | | { |
| | 11 | | internal class EcCryptographyProvider : LocalCryptographyProvider |
| | 12 | | { |
| | 13 | | private readonly KeyCurveName _curve; |
| | 14 | | private readonly JsonWebKey _keyMaterial; |
| | 15 | |
|
| 124 | 16 | | internal EcCryptographyProvider(KeyVaultKey key) : base(key) |
| | 17 | | { |
| | 18 | | // Unset the KeyMaterial since we want to conditionally set it if supported. |
| 124 | 19 | | KeyMaterial = null; |
| | 20 | |
|
| | 21 | | // Only set the JWK if we support the algorithm locally. |
| 124 | 22 | | JsonWebKey keyMaterial = key.Key; |
| 124 | 23 | | if (keyMaterial != null && keyMaterial.CurveName.HasValue) |
| | 24 | | { |
| | 25 | | // Save the key material to use for operational support validation. |
| 124 | 26 | | _keyMaterial = keyMaterial; |
| | 27 | |
|
| 124 | 28 | | _curve = keyMaterial.CurveName.Value; |
| 124 | 29 | | if (_curve.IsSupported) |
| | 30 | | { |
| 108 | 31 | | KeyMaterial = keyMaterial; |
| | 32 | | } |
| | 33 | | } |
| 124 | 34 | | } |
| | 35 | |
|
| | 36 | | public override bool SupportsOperation(KeyOperation operation) |
| | 37 | | { |
| 64 | 38 | | if (_keyMaterial != null) |
| | 39 | | { |
| 64 | 40 | | if (operation == KeyOperation.Sign || operation == KeyOperation.Verify) |
| | 41 | | { |
| 56 | 42 | | return _keyMaterial.SupportsOperation(operation); |
| | 43 | | } |
| | 44 | | } |
| | 45 | |
|
| 8 | 46 | | return false; |
| | 47 | | } |
| | 48 | |
|
| | 49 | | public override SignResult Sign(SignatureAlgorithm algorithm, byte[] digest, CancellationToken cancellationToken |
| | 50 | | { |
| 70 | 51 | | Argument.AssertNotNull(digest, nameof(digest)); |
| | 52 | |
|
| 68 | 53 | | ThrowIfTimeInvalid(); |
| | 54 | |
|
| | 55 | | // The JWK is not supported by this client. Send to the server. |
| 64 | 56 | | if (KeyMaterial is null) |
| | 57 | | { |
| 6 | 58 | | KeysEventSource.Singleton.AlgorithmNotSupported(nameof(Sign), _curve); |
| 6 | 59 | | return null; |
| | 60 | | } |
| | 61 | |
|
| | 62 | | // A private key is required to sign. Send to the server. |
| 58 | 63 | | if (MustRemote) |
| | 64 | | { |
| 18 | 65 | | KeysEventSource.Singleton.PrivateKeyRequired(nameof(Sign)); |
| 18 | 66 | | return null; |
| | 67 | | } |
| | 68 | |
|
| 40 | 69 | | KeyCurveName algorithmCurve = algorithm.GetEcKeyCurveName(); |
| 40 | 70 | | if (_curve.KeySize != algorithmCurve.KeySize) |
| | 71 | | { |
| 20 | 72 | | throw new ArgumentException($"Signature algorithm {algorithm} key size {algorithmCurve.KeySize} does not |
| | 73 | | } |
| | 74 | |
|
| 20 | 75 | | if (_curve != algorithmCurve) |
| | 76 | | { |
| 4 | 77 | | throw new ArgumentException($"Signature algorithm {algorithm} key curve name does not correspond to unde |
| | 78 | | } |
| | 79 | |
|
| 16 | 80 | | using ECDsa ecdsa = KeyMaterial.ToECDsa(true, false); |
| 16 | 81 | | if (ecdsa is null) |
| | 82 | | { |
| 0 | 83 | | return null; |
| | 84 | | } |
| | 85 | |
|
| 16 | 86 | | byte[] signature = ecdsa.SignHash(digest); |
| 16 | 87 | | return new SignResult |
| 16 | 88 | | { |
| 16 | 89 | | Algorithm = algorithm, |
| 16 | 90 | | KeyId = KeyMaterial.Id, |
| 16 | 91 | | Signature = signature, |
| 16 | 92 | | }; |
| 16 | 93 | | } |
| | 94 | |
|
| | 95 | | public override VerifyResult Verify(SignatureAlgorithm algorithm, byte[] digest, byte[] signature, CancellationT |
| | 96 | | { |
| | 97 | | // The JWK is not supported by this client. Send to the server. |
| 48 | 98 | | Argument.AssertNotNull(digest, nameof(digest)); |
| 46 | 99 | | Argument.AssertNotNull(signature, nameof(signature)); |
| | 100 | |
|
| | 101 | | // The JWK is not supported by this client. Send to the server. |
| 44 | 102 | | if (KeyMaterial is null) |
| | 103 | | { |
| 6 | 104 | | KeysEventSource.Singleton.AlgorithmNotSupported(nameof(Verify), _curve); |
| 6 | 105 | | return null; |
| | 106 | | } |
| | 107 | |
|
| 38 | 108 | | KeyCurveName algorithmCurve = algorithm.GetEcKeyCurveName(); |
| 38 | 109 | | if (_curve.KeySize != algorithmCurve.KeySize) |
| | 110 | | { |
| 20 | 111 | | throw new ArgumentException($"Signature algorithm {algorithm} key size {algorithmCurve.KeySize} does not |
| | 112 | | } |
| | 113 | |
|
| 18 | 114 | | if (_curve != algorithmCurve) |
| | 115 | | { |
| 4 | 116 | | throw new ArgumentException($"Signature algorithm {algorithm} key curve name does not correspond to unde |
| | 117 | | } |
| | 118 | |
|
| 14 | 119 | | using ECDsa ecdsa = KeyMaterial.ToECDsa(false, false); |
| 14 | 120 | | if (ecdsa is null) |
| | 121 | | { |
| 0 | 122 | | return null; |
| | 123 | | } |
| | 124 | |
|
| 14 | 125 | | bool isValid = ecdsa.VerifyHash(digest, signature); |
| 14 | 126 | | return new VerifyResult |
| 14 | 127 | | { |
| 14 | 128 | | Algorithm = algorithm, |
| 14 | 129 | | IsValid = isValid, |
| 14 | 130 | | KeyId = KeyMaterial.Id, |
| 14 | 131 | | }; |
| 14 | 132 | | } |
| | 133 | | } |
| | 134 | | } |