From a29c01d90e0035d069dc6a40743c23fdc44b7f88 Mon Sep 17 00:00:00 2001 From: Martin Toman Date: Tue, 15 Oct 2024 15:30:12 +0000 Subject: [PATCH] new draft --- .../RSAEncryptedFileKeyManager.cs | 31 +++++++++++++------ .../Configuration/IRSAKeyManager.cs | 7 +++-- .../Configuration/OAuthCredential.cs | 2 +- .../Configuration/RSAFileKeyManager.cs | 4 +-- src/Agent.Listener/MessageListener.cs | 6 ++-- 5 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/Agent.Listener/Configuration.Windows/RSAEncryptedFileKeyManager.cs b/src/Agent.Listener/Configuration.Windows/RSAEncryptedFileKeyManager.cs index a64c9d3c2b..2bbcd7cf06 100644 --- a/src/Agent.Listener/Configuration.Windows/RSAEncryptedFileKeyManager.cs +++ b/src/Agent.Listener/Configuration.Windows/RSAEncryptedFileKeyManager.cs @@ -132,12 +132,12 @@ public void DeleteKey() } } - public RSA GetKey() + public RSA GetKey(bool useLegacyRsaImpl) { - return GetKeyFromFile(); + return GetKeyFromFile(useLegacyRsaImpl); } - private RSA GetKeyFromNamedContainer() + private RSA GetKeyFromNamedContainer(bool useLegacyRsaImpl) { if (!File.Exists(_keyFile)) { @@ -151,7 +151,7 @@ private RSA GetKeyFromNamedContainer() if (string.IsNullOrEmpty(result.containerName)) { // we should not get here. GetKeyFromNamedContainer is only called from GetKeyFromFile when result.containerName is not empty - return GetKeyFromFile(); + return GetKeyFromFile(useLegacyRsaImpl); } if (result.useCng) @@ -170,13 +170,24 @@ private RSA GetKeyFromNamedContainer() Trace.Info("Using RSACryptoServiceProvider"); CspParameters Params = new CspParameters(); Params.KeyContainerName = result.containerName; - Params.Flags |= CspProviderFlags.UseNonExportableKey | CspProviderFlags.UseMachineKeyStore; - var rsa = new RSACryptoServiceProvider(Params); - return rsa; + if (useLegacyRsaImpl) + { + Params.Flags |= CspProviderFlags.UseNonExportableKey | CspProviderFlags.UseMachineKeyStore; + var rsa = new RSACryptoServiceProvider(Params); + return rsa; + } + else + { + Params.Flags |= CspProviderFlags.UseMachineKeyStore; + using (var csp = new RSACryptoServiceProvider(Params)) + { + return RSA.Create(csp.ExportParameters(includePrivateParameters: true)); + } + } } } - private RSA GetKeyFromFile() + private RSA GetKeyFromFile(bool useLegacyRsaImpl) { if (!File.Exists(_keyFile)) { @@ -190,10 +201,10 @@ private RSA GetKeyFromFile() if(!string.IsNullOrEmpty(result.containerName)) { Trace.Info("Keyfile has ContainerName, reading from NamedContainer"); - return GetKeyFromNamedContainer(); + return GetKeyFromNamedContainer(useLegacyRsaImpl); } - var rsa = new RSACryptoServiceProvider(); + var rsa = useLegacyRsaImpl ? new RSACryptoServiceProvider() : RSA.Create(); rsa.ImportParameters(result.rsaParameters); return rsa; } diff --git a/src/Agent.Listener/Configuration/IRSAKeyManager.cs b/src/Agent.Listener/Configuration/IRSAKeyManager.cs index f6f5dce38e..9f259a8181 100644 --- a/src/Agent.Listener/Configuration/IRSAKeyManager.cs +++ b/src/Agent.Listener/Configuration/IRSAKeyManager.cs @@ -35,11 +35,12 @@ public interface IRSAKeyManager : IAgentService void DeleteKey(); /// - /// Gets the RSACryptoServiceProvider instance currently stored by the key manager. + /// Gets the RSA instance currently stored by the key manager. /// - /// An RSACryptoServiceProvider instance representing the key for the agent + /// Use RSACryptoServiceProvider as the underlying implementation. + /// An RSA implementation representing the key for the agent /// No key exists in the store - RSA GetKey(); + RSA GetKey(bool useLegacyRsaImpl); } public static class IRSAKeyManagerExtensions diff --git a/src/Agent.Listener/Configuration/OAuthCredential.cs b/src/Agent.Listener/Configuration/OAuthCredential.cs index 82dc71780c..86b5c36848 100644 --- a/src/Agent.Listener/Configuration/OAuthCredential.cs +++ b/src/Agent.Listener/Configuration/OAuthCredential.cs @@ -42,7 +42,7 @@ public override VssCredentials GetVssCredentials(IHostContext context) // We expect the key to be in the machine store at this point. Configuration should have set all of // this up correctly so we can use the key to generate access tokens. var keyManager = context.GetService(); - var signingCredentials = VssSigningCredentials.Create(() => keyManager.GetKey()); + var signingCredentials = VssSigningCredentials.Create(() => keyManager.GetKey(useLegacyRsaImpl: true)); // RSACryptoServiceProvider is fine for signatures var clientCredential = new VssOAuthJwtBearerClientCredential(clientId, authorizationUrl, signingCredentials); var agentCredential = new VssOAuthCredential(new Uri(oathEndpointUrl, UriKind.Absolute), VssOAuthGrant.ClientCredentials, clientCredential); diff --git a/src/Agent.Listener/Configuration/RSAFileKeyManager.cs b/src/Agent.Listener/Configuration/RSAFileKeyManager.cs index 03d1fe43bf..f9a3830236 100644 --- a/src/Agent.Listener/Configuration/RSAFileKeyManager.cs +++ b/src/Agent.Listener/Configuration/RSAFileKeyManager.cs @@ -70,7 +70,7 @@ public void DeleteKey() } } - public RSA GetKey() + public RSA GetKey(bool useLegacyRsaImpl) { if (!File.Exists(_keyFile)) { @@ -80,7 +80,7 @@ public RSA GetKey() Trace.Info("Loading RSA key parameters from file {0}", _keyFile); var parameters = IOUtil.LoadObject(_keyFile).RSAParameters; - var rsa = new RSACryptoServiceProvider(); + var rsa = useLegacyRsaImpl ? new RSACryptoServiceProvider() : RSA.Create(); rsa.ImportParameters(parameters); return rsa; } diff --git a/src/Agent.Listener/MessageListener.cs b/src/Agent.Listener/MessageListener.cs index eebca9d1f7..d3900a8402 100644 --- a/src/Agent.Listener/MessageListener.cs +++ b/src/Agent.Listener/MessageListener.cs @@ -95,6 +95,7 @@ public async Task CreateSessionAsync(CancellationToken token) await _agentServer.ConnectAsync(new Uri(serverUrl), creds); Trace.Info("VssConnection created"); + taskAgentSession.AgentCanHandleOaepSHA256 = true; _session = await _agentServer.CreateAgentSessionAsync( _settings.PoolId, taskAgentSession, @@ -336,9 +337,10 @@ private ICryptoTransform GetMessageDecryptor( { // The agent session encryption key uses the AES symmetric algorithm var keyManager = HostContext.GetService(); - using (var rsa = keyManager.GetKey()) + RSAEncryptionPadding rsaPadding = _session.EncryptionKey.EncryptionPadding == "OaepSHA256" ? RSAEncryptionPadding.OaepSHA256 : RSAEncryptionPadding.OaepSHA1; + using (var rsa = keyManager.GetKey(useLegacyRsaImpl: rsaPadding == RSAEncryptionPadding.OaepSHA1)) { - return aes.CreateDecryptor(rsa.Decrypt(_session.EncryptionKey.Value, RSAEncryptionPadding.OaepSHA1), message.IV); + return aes.CreateDecryptor(rsa.Decrypt(_session.EncryptionKey.Value, rsaPadding), message.IV); } } else