Skip to content

Commit 7cbeee7

Browse files
authored
[Test] Add ECC Certificates to various tests (#2961)
* Generate ECC Certificates in Client Tests * Add more tests * reenable check of certificate * fix tests * Dont use random in test * fix unsupported certificate types * fix Hash algorithm for nistP384 curve on linux as the friendly name is ECDSA_P384 instead of nistP384 * use friendly name by default and add special case only for linux while taking care of nullability * disable special casing for finding correct certificates * fix tests on net 462 * update Certificate Identifier
1 parent cf82847 commit 7cbeee7

File tree

12 files changed

+254
-94
lines changed

12 files changed

+254
-94
lines changed

Libraries/Opc.Ua.Gds.Server.Common/CertificateGroup.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ [Optional] string trustedIssuerCertificatesStorePath
8282
{
8383
if (!Utils.IsSupportedCertificateType(certificateType))
8484
{
85-
throw new NotImplementedException($"Unsupported certificate type {certificateType}");
85+
Utils.LogError("Certificate type {0} specified for Certificate Group is not supported on this platform", certificateType);
86+
continue;
8687
}
8788

8889
CertificateTypes.Add(certificateType);
@@ -356,7 +357,10 @@ public virtual async Task<X509Certificate2> SigningRequestAsync(
356357

357358
#if ECC_SUPPORT
358359
certificate = TryGetECCCurve(certificateType, out ECCurve curve) ?
359-
builder.SetIssuer(signingKey).SetECDsaPublicKey(info.SubjectPublicKeyInfo.GetEncoded()).CreateForECDsa() :
360+
builder
361+
.SetIssuer(signingKey)
362+
.SetECDsaPublicKey(info.SubjectPublicKeyInfo.GetEncoded())
363+
.CreateForECDsa() :
360364
builder.SetHashAlgorithm(X509Utils.GetRSAHashAlgorithmName(Configuration.DefaultCertificateHashSize))
361365
.SetIssuer(signingKey)
362366
.SetRSAPublicKey(info.SubjectPublicKeyInfo.GetEncoded())

Libraries/Opc.Ua.Security.Certificates/X509Certificate/CertificateBuilderBase.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,9 @@ public virtual ICertificateBuilderIssuer SetIssuer(X509Certificate2 issuerCertif
291291
private void SetHashAlgorithmSize(ECCurve curve)
292292
{
293293
if (curve.Oid.FriendlyName.CompareTo(ECCurve.NamedCurves.nistP384.Oid.FriendlyName) == 0 ||
294-
(curve.Oid.FriendlyName.CompareTo(ECCurve.NamedCurves.brainpoolP384r1.Oid.FriendlyName) == 0))
294+
curve.Oid.FriendlyName.CompareTo(ECCurve.NamedCurves.brainpoolP384r1.Oid.FriendlyName) == 0 ||
295+
// special case for linux where friendly name could be ECDSA_P384 instead of nistP384
296+
(curve.Oid?.Value != null && curve.Oid.Value.CompareTo(ECCurve.NamedCurves.nistP384.Oid.Value) == 0))
295297
{
296298
SetHashAlgorithm(HashAlgorithmName.SHA384);
297299
}
@@ -388,7 +390,7 @@ protected virtual void NewSerialNumber()
388390
/// </summary>
389391
private protected ECCurve? m_curve;
390392
#endif
391-
#endregion
393+
#endregion
392394

393395
#region Private Fields
394396
private X509Certificate2 m_issuerCAKeyCert;

Libraries/Opc.Ua.Server/Configuration/ConfigurationNodeManager.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,7 @@ private ServiceResult UpdateCertificate(
433433
// identify the existing certificate to be updated
434434
// it should be of the same type and same subject name as the new certificate
435435
CertificateIdentifier existingCertIdentifier = certificateGroup.ApplicationCertificates.FirstOrDefault(cert =>
436-
X509Utils.CompareDistinguishedName(cert.Certificate.Subject, newCert.Subject) &&
436+
X509Utils.CompareDistinguishedName(cert.SubjectName, newCert.Subject) &&
437437
cert.CertificateType == certificateTypeId);
438438

439439
// if no cert was found search by ApplicationUri
@@ -566,6 +566,8 @@ private ServiceResult UpdateCertificate(
566566
var certOnly = X509CertificateLoader.LoadCertificate(updateCertificate.CertificateWithPrivateKey.RawData);
567567
updateCertificate.CertificateWithPrivateKey.Dispose();
568568
updateCertificate.CertificateWithPrivateKey = certOnly;
569+
//update certificate identifier with new certificate
570+
existingCertIdentifier.Find(m_configuration.ApplicationUri).GetAwaiter().GetResult();
569571
}
570572

571573
ICertificateStore issuerStore = certificateGroup.IssuerStore.OpenStore();
@@ -800,7 +802,7 @@ private ServiceResult GetCertificates(
800802
}
801803

802804
certificateTypeIds = certificateGroup.CertificateTypes;
803-
certificates = certificateGroup.ApplicationCertificates.Select(s => s.Certificate.RawData).ToArray();
805+
certificates = certificateGroup.ApplicationCertificates.Select(s => s.Certificate?.RawData).ToArray();
804806

805807
return ServiceResult.Good;
806808
}

Stack/Opc.Ua.Core/Security/Certificates/CertificateIdentifier.cs

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,10 @@ public static NodeId GetCertificateType(X509Certificate2 certificate)
577577
/// <param name="certificateType">The NodeId of the certificate type.</param>
578578
public static bool ValidateCertificateType(X509Certificate2 certificate, NodeId certificateType)
579579
{
580+
if (certificateType == null)
581+
{
582+
return true;
583+
}
580584
switch (certificate.SignatureAlgorithm.Value)
581585
{
582586
case Oids.ECDsaWithSha1:
@@ -594,18 +598,21 @@ public static bool ValidateCertificateType(X509Certificate2 certificate, NodeId
594598
}
595599

596600

597-
// special cases
598-
if (certType == ObjectTypeIds.EccNistP384ApplicationCertificateType &&
599-
certificateType == ObjectTypeIds.EccNistP256ApplicationCertificateType)
600-
{
601-
return true;
602-
}
603-
604-
if (certType == ObjectTypeIds.EccBrainpoolP384r1ApplicationCertificateType &&
605-
certificateType == ObjectTypeIds.EccBrainpoolP256r1ApplicationCertificateType)
606-
{
607-
return true;
608-
}
601+
// not needed: An end entity Certificate shall use P-256.
602+
// http://opcfoundation.org/UA/SecurityPolicy#ECC_nistP256
603+
//if (certType == ObjectTypeIds.EccNistP384ApplicationCertificateType &&
604+
// certificateType == ObjectTypeIds.EccNistP256ApplicationCertificateType)
605+
//{
606+
// return true;
607+
//}
608+
609+
// not needed: An end entity Certificate shall use P256r1.
610+
// http://opcfoundation.org/UA/SecurityPolicy#ECC_brainpoolP256r1
611+
//if (certType == ObjectTypeIds.EccBrainpoolP384r1ApplicationCertificateType &&
612+
// certificateType == ObjectTypeIds.EccBrainpoolP256r1ApplicationCertificateType)
613+
//{
614+
// return true;
615+
//}
609616

610617
break;
611618

Stack/Opc.Ua.Core/Security/Certificates/CertificateValidator.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,10 +257,9 @@ public virtual async Task UpdateCertificateAsync(SecurityConfiguration securityC
257257

258258
try
259259
{
260-
260+
m_applicationCertificates.Clear();
261261
foreach (var applicationCertificate in securityConfiguration.ApplicationCertificates)
262262
{
263-
m_applicationCertificates.RemoveAll(cert => Utils.IsEqual(cert.RawData, applicationCertificate.RawData));
264263
applicationCertificate.DisposeCertificate();
265264
}
266265

Tests/Opc.Ua.Gds.Tests/ClientTest.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
using System.Threading;
3737
using System.Threading.Tasks;
3838
using NUnit.Framework;
39+
using Opc.Ua.Gds.Server;
3940
using Assert = NUnit.Framework.Legacy.ClassicAssert;
4041

4142

@@ -108,6 +109,14 @@ protected async Task OneTimeSetUp()
108109
m_invalidRegistrationOk = false;
109110
m_goodNewKeyPairRequestOk = false;
110111
m_gdsRegisteredTestClient = false;
112+
113+
//get supported CertificateTypes from GDS
114+
m_supportedCertificateTypes = m_server.Config.ParseExtension<GlobalDiscoveryServerConfiguration>().CertificateGroups
115+
.Where(cg => cg.Id == "Default")
116+
.SelectMany(cg => cg.CertificateTypes)
117+
.Select(s => typeof(Ua.ObjectTypeIds).GetField(s).GetValue(null) as NodeId)
118+
.Where(n => n != null && Utils.IsSupportedCertificateType(n))
119+
.ToList();
111120
}
112121

113122
/// <summary>
@@ -652,8 +661,12 @@ public void StartGoodNewKeyPairRequests()
652661
{
653662
AssertIgnoreTestWithoutGoodRegistration();
654663
ConnectGDS(true);
664+
int certificateTypeIndex = 0;
655665
foreach (var application in m_goodApplicationTestSet)
656666
{
667+
application.CertificateTypeId = m_supportedCertificateTypes[certificateTypeIndex];
668+
certificateTypeIndex = (certificateTypeIndex + 1) % m_supportedCertificateTypes.Count;
669+
657670
Assert.Null(application.CertificateRequestId);
658671
NodeId requestId = m_gdsClient.GDSClient.StartNewKeyPairRequest(
659672
application.ApplicationRecord.ApplicationId,
@@ -875,7 +888,7 @@ out byte[][] issuerCertificates
875888

876889
}
877890

878-
891+
879892
[Test, Order(540)]
880893
public void GetGoodCertificates()
881894
{
@@ -1531,6 +1544,7 @@ private int GoodServersOnNetworkCount()
15311544
private bool m_goodRegistrationOk;
15321545
private bool m_invalidRegistrationOk;
15331546
private bool m_gdsRegisteredTestClient;
1547+
private List<NodeId> m_supportedCertificateTypes;
15341548
private bool m_goodNewKeyPairRequestOk;
15351549
private string m_storeType;
15361550
#endregion

Tests/Opc.Ua.Gds.Tests/GlobalDiscoveryTestServer.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,13 @@ private static async Task<ApplicationConfiguration> Load(ApplicationInstance app
216216
{
217217
new CertificateGroupConfiguration() {
218218
Id = "Default",
219-
CertificateType = "RsaSha256ApplicationCertificateType",
219+
CertificateTypes = new StringCollection() {
220+
"RsaSha256ApplicationCertificateType",
221+
"EccNistP256ApplicationCertificateType",
222+
"EccNistP384ApplicationCertificateType",
223+
"EccBrainpoolP256r1ApplicationCertificateType",
224+
"EccBrainpoolP384r1ApplicationCertificateType"
225+
},
220226
SubjectName = "CN=GDS Test CA, O=OPC Foundation",
221227
BaseStorePath = Path.Combine(gdsRoot, "CA", "default"),
222228
DefaultCertificateHashSize = 256,

Tests/Opc.Ua.Gds.Tests/Opc.Ua.GlobalDiscoveryTestServer.Config.xml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,30 @@
1717
<SubjectName>CN=Global Discovery Test Server, O=OPC Foundation, DC=localhost</SubjectName>
1818
<CertificateTypeString>RsaSha256</CertificateTypeString>
1919
</CertificateIdentifier>
20+
<CertificateIdentifier>
21+
<StoreType>Directory</StoreType>
22+
<StorePath>%LocalApplicationData%/OPC/GDS/own</StorePath>
23+
<SubjectName>CN=Global Discovery Test Server, O=OPC Foundation, DC=localhost</SubjectName>
24+
<CertificateTypeString>NistP256</CertificateTypeString>
25+
</CertificateIdentifier>
26+
<CertificateIdentifier>
27+
<StoreType>Directory</StoreType>
28+
<StorePath>%LocalApplicationData%/OPC/GDS/own</StorePath>
29+
<SubjectName>CN=Global Discovery Test Server, O=OPC Foundation, DC=localhost</SubjectName>
30+
<CertificateTypeString>NistP384</CertificateTypeString>
31+
</CertificateIdentifier>
32+
<CertificateIdentifier>
33+
<StoreType>Directory</StoreType>
34+
<StorePath>%LocalApplicationData%/OPC/GDS/own</StorePath>
35+
<SubjectName>CN=Global Discovery Test Server, O=OPC Foundation, DC=localhost</SubjectName>
36+
<CertificateTypeString>BrainpoolP256r1</CertificateTypeString>
37+
</CertificateIdentifier>
38+
<CertificateIdentifier>
39+
<StoreType>Directory</StoreType>
40+
<StorePath>%LocalApplicationData%/OPC/GDS/own</StorePath>
41+
<SubjectName>CN=Global Discovery Test Server, O=OPC Foundation, DC=localhost</SubjectName>
42+
<CertificateTypeString>BrainpoolP384r1</CertificateTypeString>
43+
</CertificateIdentifier>
2044
</ApplicationCertificates>
2145

2246
<TrustedIssuerCertificates>
@@ -143,6 +167,8 @@
143167
<ua:String>RsaSha256ApplicationCertificateType</ua:String>
144168
<ua:String>EccNistP256ApplicationCertificateType</ua:String>
145169
<ua:String>EccNistP384ApplicationCertificateType</ua:String>
170+
<ua:String>EccBrainpoolP256r1ApplicationCertificateType</ua:String>
171+
<ua:String>EccBrainpoolP384r1ApplicationCertificateType</ua:String>
146172
</CertificateTypes>
147173
<SubjectName>CN=GDS Test CA, O=OPC Foundation</SubjectName>
148174
<BaseStorePath>%LocalApplicationData%/OPC/GDS/CA/default</BaseStorePath>

Tests/Opc.Ua.Gds.Tests/Opc.Ua.GlobalDiscoveryTestServerX509Stores.Config.xml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,30 @@
1717
<SubjectName>CN=Global Discovery Test Server, O=OPC Foundation, DC=localhost</SubjectName>
1818
<CertificateTypeString>RsaSha256</CertificateTypeString>
1919
</CertificateIdentifier>
20+
<CertificateIdentifier>
21+
<StoreType>X509Store</StoreType>
22+
<StorePath>CurrentUser\UA_Test_GDS_Server_own</StorePath>
23+
<SubjectName>CN=Global Discovery Test Server, O=OPC Foundation, DC=localhost</SubjectName>
24+
<CertificateTypeString>NistP256</CertificateTypeString>
25+
</CertificateIdentifier>
26+
<CertificateIdentifier>
27+
<StoreType>X509Store</StoreType>
28+
<StorePath>CurrentUser\UA_Test_GDS_Server_own</StorePath>
29+
<SubjectName>CN=Global Discovery Test Server, O=OPC Foundation, DC=localhost</SubjectName>
30+
<CertificateTypeString>NistP384</CertificateTypeString>
31+
</CertificateIdentifier>
32+
<CertificateIdentifier>
33+
<StoreType>X509Store</StoreType>
34+
<StorePath>CurrentUser\UA_Test_GDS_Server_own</StorePath>
35+
<SubjectName>CN=Global Discovery Test Server, O=OPC Foundation, DC=localhost</SubjectName>
36+
<CertificateTypeString>BrainpoolP256r1</CertificateTypeString>
37+
</CertificateIdentifier>
38+
<CertificateIdentifier>
39+
<StoreType>X509Store</StoreType>
40+
<StorePath>CurrentUser\UA_Test_GDS_Server_own</StorePath>
41+
<SubjectName>CN=Global Discovery Test Server, O=OPC Foundation, DC=localhost</SubjectName>
42+
<CertificateTypeString>BrainpoolP384r1</CertificateTypeString>
43+
</CertificateIdentifier>
2044
</ApplicationCertificates>
2145

2246
<TrustedIssuerCertificates>
@@ -143,6 +167,8 @@
143167
<ua:String>RsaSha256ApplicationCertificateType</ua:String>
144168
<ua:String>EccNistP256ApplicationCertificateType</ua:String>
145169
<ua:String>EccNistP384ApplicationCertificateType</ua:String>
170+
<ua:String>EccBrainpoolP256r1ApplicationCertificateType</ua:String>
171+
<ua:String>EccBrainpoolP384r1ApplicationCertificateType</ua:String>
146172
</CertificateTypes>
147173
<SubjectName>CN=GDS Test CA, O=OPC Foundation</SubjectName>
148174
<BaseStorePath>%LocalApplicationData%/OPC/GDS/CA/default</BaseStorePath>

0 commit comments

Comments
 (0)