Skip to content

Commit 3f65a75

Browse files
Merge pull request #1 from OPCFoundation/v1.03
Merge remote-tracking branch 'origin/v1.03' into v1.03
2 parents 8af886f + c2f943f commit 3f65a75

File tree

5 files changed

+131
-34
lines changed

5 files changed

+131
-34
lines changed

SampleApplications/Samples/GDS/ClientTest/ClientTest.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
using Opc.Ua.Gds.Client;
3939
using Opc.Ua.Gds.Test;
4040
using Opc.Ua.Test;
41+
using System.IO;
4142

4243
namespace NUnit.Opc.Ua.Gds.Test
4344
{
@@ -523,7 +524,7 @@ public void StartGoodSigningRequests()
523524
}
524525
}
525526

526-
[Test, Order(521)]
527+
[Test, Order(530)]
527528
public void FinishGoodSigningRequests()
528529
{
529530
AssertIgnoreTestWithoutGoodRegistration();
@@ -568,6 +569,26 @@ out byte[][] issuerCertificates
568569

569570
}
570571

572+
[Test, Order(550)]
573+
public void StartGoodSigningRequestWithInvalidAppURI()
574+
{
575+
AssertIgnoreTestWithoutGoodRegistration();
576+
ConnectGDS(true);
577+
var application = _goodApplicationTestSet[0];
578+
Assert.Null(application.CertificateRequestId);
579+
// load csr with invalid app URI
580+
byte[] certificateRequest = File.ReadAllBytes("test.csr");
581+
Assert.That(() =>
582+
{
583+
NodeId requestId = _gdsClient.GDSClient.StartSigningRequest(
584+
application.ApplicationRecord.ApplicationId,
585+
application.CertificateGroupId,
586+
application.CertificateTypeId,
587+
certificateRequest);
588+
}, Throws.Exception);
589+
}
590+
591+
571592
[Test, Order(600)]
572593
public void GetGoodCertificateGroupsNullTests()
573594
{

SampleApplications/Samples/GDS/ClientTest/GlobalDiscoveryClientTest.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@
3131
<None Update="Opc.Ua.ServerConfigurationPushTestClient.Config.xml">
3232
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
3333
</None>
34+
<None Update="test.csr">
35+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
36+
</None>
3437
</ItemGroup>
3538

3639
</Project>
1.2 KB
Binary file not shown.

SampleApplications/Samples/GDS/ServerCommon/CertificateGroup.cs

Lines changed: 85 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,8 @@
2727
* http://opcfoundation.org/License/MIT/1.00/
2828
* ======================================================================*/
2929

30-
using Org.BouncyCastle.Asn1.Pkcs;
31-
using Org.BouncyCastle.Pkcs;
3230
using System;
31+
using System.Collections.Generic;
3332
using System.Security.Cryptography.X509Certificates;
3433
using System.Threading.Tasks;
3534

@@ -145,24 +144,63 @@ public virtual async Task<X509Certificate2> SigningRequestAsync(
145144
string[] domainNames,
146145
byte[] certificateRequest)
147146
{
148-
Pkcs10CertificationRequest pkcs10CertificationRequest = new Pkcs10CertificationRequest(certificateRequest);
149-
CertificationRequestInfo info = pkcs10CertificationRequest.GetCertificationRequestInfo();
150-
DateTime yesterday = DateTime.UtcNow.AddDays(-1);
151-
return CertificateFactory.CreateCertificate(
152-
null,
153-
null,
154-
null,
155-
application.ApplicationUri ?? "urn:ApplicationURI",
156-
application.ApplicationNames.Count > 0 ? application.ApplicationNames[0].Text : "ApplicationName",
157-
info.Subject.ToString(),
158-
domainNames,
159-
Configuration.DefaultCertificateKeySize,
160-
yesterday,
161-
Configuration.DefaultCertificateLifetime,
162-
Configuration.DefaultCertificateHashSize,
163-
false,
164-
await LoadSigningKeyAsync(Certificate, string.Empty),
165-
info.SubjectPublicKeyInfo.GetEncoded());
147+
try
148+
{
149+
var pkcs10CertificationRequest = new Org.BouncyCastle.Pkcs.Pkcs10CertificationRequest(certificateRequest);
150+
151+
if (!pkcs10CertificationRequest.Verify())
152+
{
153+
throw new ServiceResultException(StatusCodes.BadInvalidArgument, "CSR signature invalid.");
154+
}
155+
156+
var info = pkcs10CertificationRequest.GetCertificationRequestInfo();
157+
var altNameExtension = GetAltNameExtensionFromCSRInfo(info);
158+
if (altNameExtension != null)
159+
{
160+
if (altNameExtension.Uris.Count > 0)
161+
{
162+
if (!altNameExtension.Uris.Contains(application.ApplicationUri))
163+
{
164+
throw new ServiceResultException(StatusCodes.BadCertificateUriInvalid,
165+
"CSR AltNameExtension does not match "+ application.ApplicationUri);
166+
}
167+
}
168+
169+
if (altNameExtension.IPAddresses.Count > 0 || altNameExtension.DomainNames.Count > 0)
170+
{
171+
var domainNameList = new List<string>();
172+
domainNameList.AddRange(altNameExtension.DomainNames);
173+
domainNameList.AddRange(altNameExtension.IPAddresses);
174+
domainNames = domainNameList.ToArray();
175+
}
176+
}
177+
178+
DateTime yesterday = DateTime.UtcNow.AddDays(-1);
179+
return CertificateFactory.CreateCertificate(
180+
null,
181+
null,
182+
null,
183+
application.ApplicationUri ?? "urn:ApplicationURI",
184+
application.ApplicationNames.Count > 0 ? application.ApplicationNames[0].Text : "ApplicationName",
185+
info.Subject.ToString(),
186+
domainNames,
187+
Configuration.DefaultCertificateKeySize,
188+
yesterday,
189+
Configuration.DefaultCertificateLifetime,
190+
Configuration.DefaultCertificateHashSize,
191+
false,
192+
await LoadSigningKeyAsync(Certificate, string.Empty),
193+
info.SubjectPublicKeyInfo.GetEncoded());
194+
}
195+
catch (Exception ex)
196+
{
197+
if (ex is ServiceResultException)
198+
{
199+
throw ex as ServiceResultException;
200+
}
201+
throw new ServiceResultException(StatusCodes.BadInvalidArgument, ex.Message);
202+
}
203+
166204
}
167205

168206
public virtual async Task<X509Certificate2> CreateCACertificateAsync(
@@ -248,6 +286,33 @@ private async Task UpdateAuthorityCertInTrustedList()
248286
}
249287
}
250288
}
289+
290+
private X509SubjectAltNameExtension GetAltNameExtensionFromCSRInfo(Org.BouncyCastle.Asn1.Pkcs.CertificationRequestInfo info)
291+
{
292+
try
293+
{
294+
for (int i = 0; i < info.Attributes.Count; i++)
295+
{
296+
var sequence = Org.BouncyCastle.Asn1.Asn1Sequence.GetInstance(info.Attributes[i].ToAsn1Object());
297+
var oid = Org.BouncyCastle.Asn1.DerObjectIdentifier.GetInstance(sequence[0].ToAsn1Object());
298+
if (oid.Equals(Org.BouncyCastle.Asn1.Pkcs.PkcsObjectIdentifiers.Pkcs9AtExtensionRequest))
299+
{
300+
var extensionInstance = Org.BouncyCastle.Asn1.DerSet.GetInstance(sequence[1]);
301+
var extensionSequence = Org.BouncyCastle.Asn1.Asn1Sequence.GetInstance(extensionInstance[0]);
302+
var extensions = Org.BouncyCastle.Asn1.X509.X509Extensions.GetInstance(extensionSequence);
303+
Org.BouncyCastle.Asn1.X509.X509Extension extension = extensions.GetExtension(Org.BouncyCastle.Asn1.X509.X509Extensions.SubjectAlternativeName);
304+
var asnEncodedAltNameExtension = new System.Security.Cryptography.AsnEncodedData(Org.BouncyCastle.Asn1.X509.X509Extensions.SubjectAlternativeName.ToString(), extension.Value.GetOctets());
305+
var altNameExtension = new X509SubjectAltNameExtension(asnEncodedAltNameExtension, extension.IsCritical);
306+
return altNameExtension;
307+
}
308+
}
309+
}
310+
catch
311+
{
312+
throw new ServiceResultException(StatusCodes.BadInvalidArgument, "CSR altNameExtension invalid.");
313+
}
314+
return null;
315+
}
251316
#endregion
252317

253318
#region Protected Fields

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

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -642,22 +642,30 @@ public static byte[] CreateSigningRequest(
642642
}
643643
}
644644

645-
if (domainNames.Count > 0)
645+
// build CSR extensions
646+
List<GeneralName> generalNames = new List<GeneralName>();
647+
648+
string applicationUri = Utils.GetApplicationUriFromCertificate(certificate);
649+
if (applicationUri != null)
646650
{
647-
List<GeneralName> generalNames = CreateSubjectAlternateNameDomains(domainNames);
648-
if (generalNames.Count > 0)
649-
{
650-
IList oids = new ArrayList();
651-
IList values = new ArrayList();
652-
oids.Add(X509Extensions.SubjectAlternativeName);
653-
values.Add(new Org.BouncyCastle.Asn1.X509.X509Extension(false,
654-
new DerOctetString(new GeneralNames(generalNames.ToArray()).GetDerEncoded())));
651+
generalNames.Add(new GeneralName(GeneralName.UniformResourceIdentifier, applicationUri));
652+
}
655653

656-
AttributePkcs attribute = new AttributePkcs(PkcsObjectIdentifiers.Pkcs9AtExtensionRequest,
657-
new DerSet(new X509Extensions(oids, values)));
654+
if (domainNames.Count > 0)
655+
{
656+
generalNames.AddRange(CreateSubjectAlternateNameDomains(domainNames));
657+
}
658658

659-
attributes = new DerSet(attribute);
660-
}
659+
if (generalNames.Count > 0)
660+
{
661+
IList oids = new ArrayList();
662+
IList values = new ArrayList();
663+
oids.Add(X509Extensions.SubjectAlternativeName);
664+
values.Add(new Org.BouncyCastle.Asn1.X509.X509Extension(false,
665+
new DerOctetString(new GeneralNames(generalNames.ToArray()).GetDerEncoded())));
666+
AttributePkcs attribute = new AttributePkcs(PkcsObjectIdentifiers.Pkcs9AtExtensionRequest,
667+
new DerSet(new X509Extensions(oids, values)));
668+
attributes = new DerSet(attribute);
661669
}
662670

663671
Pkcs10CertificationRequest pkcs10CertificationRequest = new Pkcs10CertificationRequest(

0 commit comments

Comments
 (0)