Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Client] select the most secure User Identity Token if a server offers multiple ones #2611

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
27 changes: 3 additions & 24 deletions Stack/Opc.Ua.Core/Schema/ApplicationConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
using System.Runtime.Serialization;
using System.Security.Cryptography.X509Certificates;
using Opc.Ua.Bindings;
using Opc.Ua.Security;

namespace Opc.Ua
{
Expand Down Expand Up @@ -650,7 +651,7 @@ public TransportConfigurationCollection(int capacity) : base(capacity) { }

#region ServerSecurityPolicy Class
/// <summary>
/// A class that defines a group of sampling rates supported by the server.
/// A class that defines a group of security policies supported by the server.
/// </summary>
[DataContract(Namespace = Namespaces.OpcUaConfig)]
public class ServerSecurityPolicy
Expand Down Expand Up @@ -689,29 +690,7 @@ private void Initialize()
/// </summary>
public static byte CalculateSecurityLevel(MessageSecurityMode mode, string policyUri)
{
if ((mode == MessageSecurityMode.Invalid) || (mode == MessageSecurityMode.None))
{
return 0;
}

byte result = 0;
switch (policyUri)
{
case SecurityPolicies.Basic128Rsa15: result = 2; break;
case SecurityPolicies.Basic256: result = 4; break;
case SecurityPolicies.Basic256Sha256: result = 6; break;
case SecurityPolicies.Aes128_Sha256_RsaOaep: result = 8; break;
case SecurityPolicies.Aes256_Sha256_RsaPss: result = 10; break;
case SecurityPolicies.None:
default: return 0;
}

if (mode == MessageSecurityMode.SignAndEncrypt)
{
result += 100;
}

return result;
return SecuredApplication.CalculateSecurityLevel(mode, policyUri);
}

/// <summary>
Expand Down
32 changes: 32 additions & 0 deletions Stack/Opc.Ua.Core/Schema/SecuredApplicationHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,38 @@
return policies;
}

/// <summary>
/// Calculates the security level, given the security mode and policy
/// Invalid and none is discouraged
/// Just signing is always weaker than any use of encryption
/// </summary>
public static byte CalculateSecurityLevel(MessageSecurityMode mode, string policyUri)
{
if ((mode == MessageSecurityMode.Invalid) || (mode == MessageSecurityMode.None))
{
return 0;

Check warning on line 383 in Stack/Opc.Ua.Core/Schema/SecuredApplicationHelpers.cs

View check run for this annotation

Codecov / codecov/patch

Stack/Opc.Ua.Core/Schema/SecuredApplicationHelpers.cs#L383

Added line #L383 was not covered by tests
romanett marked this conversation as resolved.
Show resolved Hide resolved
}

byte result = 0;
switch (policyUri)
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit - I wonder which stringcomparison policy is used here...

case SecurityPolicies.Basic128Rsa15: result = 2; break;
case SecurityPolicies.Basic256: result = 4; break;
case SecurityPolicies.Basic256Sha256: result = 6; break;
case SecurityPolicies.Aes128_Sha256_RsaOaep: result = 8; break;
case SecurityPolicies.Aes256_Sha256_RsaPss: result = 10; break;
case SecurityPolicies.None:
default: return 0;
}
romanett marked this conversation as resolved.
Show resolved Hide resolved

if (mode == MessageSecurityMode.SignAndEncrypt)
{
result += 100;
}

return result;
}

/// <summary>
/// Creates a new policy object.
/// Always uses sign and encrypt for all security policies except none
Expand Down
7 changes: 4 additions & 3 deletions Stack/Opc.Ua.Core/Stack/Configuration/EndpointDescription.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using Opc.Ua.Security;

namespace Opc.Ua
{
Expand Down Expand Up @@ -124,8 +125,8 @@ public UserTokenPolicy FindUserTokenPolicy(UserTokenType tokenType, string issue
// construct issuer type.
string issuedTokenTypeText = issuedTokenType;

// find matching policy.
foreach (UserTokenPolicy policy in m_userIdentityTokens)
// find matching policy, return most secure matching policy first.
foreach (UserTokenPolicy policy in m_userIdentityTokens.OrderByDescending(token => SecuredApplication.CalculateSecurityLevel(MessageSecurityMode.Sign, token.SecurityPolicyUri)))
romanett marked this conversation as resolved.
Show resolved Hide resolved
{
// check token type.
if (tokenType != policy.TokenType)
Expand Down
71 changes: 71 additions & 0 deletions Tests/Opc.Ua.Core.Tests/Schema/SecuredApplicationHelpersTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using Opc.Ua.Security;
using NUnit.Framework;

namespace Opc.Ua.Core.Tests.Schema
{
/// <summary>
/// Tests for the CertificateValidator class.
/// </summary>
[TestFixture, Category("SecuredApplicationHelpers")]
[Parallelizable]
[SetCulture("en-us")]
public class SecuredApplicationHelpersTests
{
/// <summary>
/// Verify CalculateSecurityLevel encryption is a higher security Level than signing
/// </summary>
[Test]
public void CalculateSecurityLevelEncryptionStrongerSigning()
{
Assert.That(
SecuredApplication.CalculateSecurityLevel(MessageSecurityMode.Sign, SecurityPolicies.Basic128Rsa15)
<
SecuredApplication.CalculateSecurityLevel(MessageSecurityMode.SignAndEncrypt, SecurityPolicies.Basic128Rsa15));
Assert.That(
SecuredApplication.CalculateSecurityLevel(MessageSecurityMode.Sign, SecurityPolicies.Basic128Rsa15)
<
SecuredApplication.CalculateSecurityLevel(MessageSecurityMode.SignAndEncrypt, SecurityPolicies.Aes256_Sha256_RsaPss));
}
/// <summary>
/// Verify CalculateSecurityLevel none or Invalid MessageSecurityMode return 0
/// </summary>
[Test]
public void CalculateSecurityLevelNoneOrInvalidZero()
{
Assert.That(
SecuredApplication.CalculateSecurityLevel(MessageSecurityMode.None, SecurityPolicies.Basic128Rsa15)
== 0);
Assert.That(
SecuredApplication.CalculateSecurityLevel(MessageSecurityMode.Invalid, SecurityPolicies.Basic128Rsa15)
== 0);
}

/// <summary>
/// Verify CalculateSecurityLevel none or Invalid MessageSecurityMode return 0
/// </summary>
[Test]
public void CalculateSecurityLevelOrderValid()
{
Assert.That(
SecuredApplication.CalculateSecurityLevel(MessageSecurityMode.Sign, SecurityPolicies.Basic128Rsa15)
<
SecuredApplication.CalculateSecurityLevel(MessageSecurityMode.Sign, SecurityPolicies.Basic256));

Assert.That(
SecuredApplication.CalculateSecurityLevel(MessageSecurityMode.Sign, SecurityPolicies.Basic256)
<
SecuredApplication.CalculateSecurityLevel(MessageSecurityMode.Sign, SecurityPolicies.Basic256Sha256));

Assert.That(
SecuredApplication.CalculateSecurityLevel(MessageSecurityMode.Sign, SecurityPolicies.Basic256Sha256)
<
SecuredApplication.CalculateSecurityLevel(MessageSecurityMode.Sign, SecurityPolicies.Aes128_Sha256_RsaOaep));

Assert.That(
SecuredApplication.CalculateSecurityLevel(MessageSecurityMode.Sign, SecurityPolicies.Aes128_Sha256_RsaOaep)
<
SecuredApplication.CalculateSecurityLevel(MessageSecurityMode.Sign, SecurityPolicies.Aes256_Sha256_RsaPss));

}
}
}
Loading