Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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
5 changes: 5 additions & 0 deletions Stack/Opc.Ua.Core/Security/Certificates/CertificateFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,11 @@ private static void SetSuitableDefaults(
subjectName = Utils.Format("CN={0}", subjectName);
}

if (!subjectName.Contains("O=", StringComparison.Ordinal))
{
subjectName += Utils.Format(", O={0}", "OPC Foundation");
}

if (domainNames != null && domainNames.Count > 0)
{
if (!subjectName.Contains("DC=", StringComparison.Ordinal) &&
Expand Down
22 changes: 17 additions & 5 deletions Stack/Opc.Ua.Core/Security/Certificates/CertificateIdentifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
Expand Down Expand Up @@ -423,14 +424,25 @@ public static X509Certificate2 Find(
}
}

collection = collection.Find(X509FindType.FindBySubjectName, subjectName, false);
var simpleNameMatches = collection.Find(X509FindType.FindBySubjectName, subjectName, false)
.Cast<X509Certificate2>()
.Where(cert => string.Equals(
cert.GetNameInfo(X509NameType.SimpleName, forIssuer: false),
subjectName,
StringComparison.Ordinal))
.ToArray();

foreach (X509Certificate2 certificate in collection)
if (simpleNameMatches.Length > 0)
{
if (ValidateCertificateType(certificate, certificateType) &&
(!needPrivateKey || certificate.HasPrivateKey))
collection = [.. simpleNameMatches];

foreach (X509Certificate2 certificate in collection)
{
return certificate;
if (ValidateCertificateType(certificate, certificateType) &&
(!needPrivateKey || certificate.HasPrivateKey))
{
return certificate;
}
}
}
}
Expand Down
41 changes: 41 additions & 0 deletions Tests/Opc.Ua.Configuration.Tests/ApplicationInstanceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,47 @@ await applicationInstance
Assert.IsTrue(storedCertificates.Contains(cert));
}

/// <summary>
/// This tests that instantiating two application instances the second with a SubjectName being a substring of the first one's CN,
/// succeeds without throwing exceptions.
/// </summary>
/// <returns></returns>
[Test]
public async Task TestAddTwoAppCertificatesToTrustedStoreAsync()
{
var subjectName = SubjectName;
//Arrange Application Instance
var applicationInstance = new ApplicationInstance { ApplicationName = ApplicationName };
ApplicationConfiguration configuration = await applicationInstance
.Build(ApplicationUri, ProductUri)
.AsClient()
.AddSecurityConfigurationStores(subjectName,
$"{m_pkiRoot}/pki/own",
$"{m_pkiRoot}/pki/rusted",
$"{m_pkiRoot}/pki/issuer",
$"{m_pkiRoot}/pki/rejected")
.CreateAsync()
.ConfigureAwait(false);

Assert.DoesNotThrowAsync(async() => await applicationInstance.CheckApplicationInstanceCertificatesAsync(true).ConfigureAwait(false));

subjectName = "UA";// UA is a substring of the previous certificate SubjectName CN
var applicationInstance2 = new ApplicationInstance { ApplicationName = ApplicationName };
ApplicationConfiguration configuration2 = await applicationInstance2
.Build(ApplicationUri + "2", ProductUri + "2")
.AsClient()
.AddSecurityConfigurationStores(subjectName,
$"{m_pkiRoot}/pki/own",
$"{m_pkiRoot}/pki/trusted",
$"{m_pkiRoot}/pki/issuer",
$"{m_pkiRoot}/pki/rejected")
.CreateAsync()
.ConfigureAwait(false);

Assert.DoesNotThrowAsync(async() => await applicationInstance2.CheckApplicationInstanceCertificatesAsync(true).ConfigureAwait(false));

}

/// <summary>
/// Test to verify that a new cert is not recreated/replaced if DisableCertificateAutoCreation is set.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1149,7 +1149,7 @@ public async Task VerifyNotBeforeInvalidAsync(bool trusted)
Assert.NotNull(cert);
cert = new X509Certificate2(cert);
Assert.NotNull(cert);
Assert.True(X509Utils.CompareDistinguishedName("CN=" + applicationName, cert.Subject));
Assert.True(X509Utils.CompareDistinguishedName("CN=" + applicationName + " ,O=OPC Foundation", cert.Subject));
var validator = TemporaryCertValidator.Create(telemetry);
if (!trusted)
{
Expand Down Expand Up @@ -1204,7 +1204,7 @@ public async Task VerifyNotAfterInvalidAsync(bool trusted)
Assert.NotNull(cert);
cert = new X509Certificate2(cert);
Assert.NotNull(cert);
Assert.True(X509Utils.CompareDistinguishedName("CN=" + applicationName, cert.Subject));
Assert.True(X509Utils.CompareDistinguishedName("CN=" + applicationName + " ,O=OPC Foundation", cert.Subject));
var validator = TemporaryCertValidator.Create(telemetry);
if (!trusted)
{
Expand Down
Loading