diff --git a/.gitignore b/.gitignore
index ff104459c0..3667e71d57 100644
--- a/.gitignore
+++ b/.gitignore
@@ -266,4 +266,8 @@ OPC\ Foundation/
# UA Fuzzing findings folders
/Fuzzing/**/findings/
/Fuzzing/**/Testcases/
-!/Fuzzing/**/Testcases/*.bin
\ No newline at end of file
+!/Fuzzing/**/Testcases/*.bin
+/Fuzzing/Encoders/Fuzz.Tests/Assets/*
+/Fuzzing/**/crash-*
+/Fuzzing/**/slow-*
+/Fuzzing/**/timeout-*
diff --git a/Fuzzing/Encoders/Fuzz.Tests/Opc.Ua.Encoders.Fuzz.Tests.csproj b/Fuzzing/Encoders/Fuzz.Tests/Opc.Ua.Encoders.Fuzz.Tests.csproj
index 26130413da..8843d1d6f3 100644
--- a/Fuzzing/Encoders/Fuzz.Tests/Opc.Ua.Encoders.Fuzz.Tests.csproj
+++ b/Fuzzing/Encoders/Fuzz.Tests/Opc.Ua.Encoders.Fuzz.Tests.csproj
@@ -13,6 +13,8 @@
+
+
@@ -53,6 +55,12 @@
Testcases\%(RecursiveDir)%(FileName)%(Extension)
+
+ Testcases\%(RecursiveDir)%(FileName)%(Extension)
+
+
+ Testcases\%(RecursiveDir)%(FileName)%(Extension)
+
@@ -68,6 +76,14 @@
Testcases\%(RecursiveDir)%(FileName)%(Extension)
PreserveNewest
+
+ Testcases\%(RecursiveDir)%(FileName)%(Extension)
+ PreserveNewest
+
+
+ Testcases\%(RecursiveDir)%(FileName)%(Extension)
+ PreserveNewest
+
PreserveNewest
diff --git a/Fuzzing/Encoders/Fuzz.Tools/Encoders.Fuzz.Tools.csproj b/Fuzzing/Encoders/Fuzz.Tools/Encoders.Fuzz.Tools.csproj
index 1c16b233a4..1c4af62da8 100644
--- a/Fuzzing/Encoders/Fuzz.Tools/Encoders.Fuzz.Tools.csproj
+++ b/Fuzzing/Encoders/Fuzz.Tools/Encoders.Fuzz.Tools.csproj
@@ -12,6 +12,8 @@
+
+
@@ -20,7 +22,7 @@
-
+
diff --git a/Fuzzing/Encoders/Fuzz.Tools/Encoders.Testcases.cs b/Fuzzing/Encoders/Fuzz.Tools/Encoders.Testcases.cs
index f12fcd4f48..dad461ca6e 100644
--- a/Fuzzing/Encoders/Fuzz.Tools/Encoders.Testcases.cs
+++ b/Fuzzing/Encoders/Fuzz.Tools/Encoders.Testcases.cs
@@ -27,9 +27,13 @@
* http://opcfoundation.org/License/MIT/1.00/
* ======================================================================*/
+using System;
using System.IO;
+using System.Linq;
+using System.Security.Cryptography.X509Certificates;
using System.Text;
using Opc.Ua;
+using Opc.Ua.Security.Certificates;
public static partial class Testcases
{
@@ -38,10 +42,12 @@ public enum TestCaseEncoders : int
{
Binary = 0,
Json = 1,
- Xml = 2
+ Xml = 2,
+ Certificates = 3,
+ CRLs = 4
};
- public static string[] TestcaseEncoderSuffixes = new string[] { ".Binary", ".Json", ".Xml" };
+ public static string[] TestcaseEncoderSuffixes = new string[] { ".Binary", ".Json", ".Xml", ".Certificates", ".CRLs" };
public static void Run(string workPath)
{
@@ -57,17 +63,10 @@ public static void Run(string workPath)
message = encoder.CloseAndReturnBuffer();
}
- // Test the fuzz targets with the message.
- FuzzableCode.LibfuzzBinaryDecoder(message);
- FuzzableCode.LibfuzzBinaryEncoder(message);
- using (var stream = new MemoryStream(message))
- {
- FuzzableCode.AflfuzzBinaryDecoder(stream);
- }
- using (var stream = new MemoryStream(message))
- {
- FuzzableCode.AflfuzzBinaryEncoder(stream);
- }
+ // ensure the test case does not throw an exception
+ TestNewRawDataMessage(message);
+
+ // ensure it does not throw an exception
using (var stream = new MemoryStream(message))
{
FuzzableCode.FuzzBinaryDecoderCore(stream, true);
@@ -91,13 +90,11 @@ public static void Run(string workPath)
message = memoryStream.ToArray();
}
-
// Test the fuzz targets with the message.
- FuzzableCode.LibfuzzJsonDecoder(message);
- FuzzableCode.LibfuzzJsonEncoder(message);
+ TestNewUtf8Message(message);
+
+ // ensure the test case does not throw an exception
string json = Encoding.UTF8.GetString(message);
- FuzzableCode.AflfuzzJsonDecoder(json);
- FuzzableCode.AflfuzzJsonEncoder(json);
FuzzableCode.FuzzJsonDecoderCore(json, true);
string fileName = Path.Combine(pathTarget, $"{messageEncoder.Method.Name}.json".ToLowerInvariant());
@@ -120,22 +117,167 @@ public static void Run(string workPath)
// Test the fuzz targets with the message.
byte[] message = Encoding.UTF8.GetBytes(xml);
using (var stream = new MemoryStream(message))
- {
- FuzzableCode.AflfuzzXmlDecoder(stream);
- }
- using (var stream = new MemoryStream(message))
- {
- FuzzableCode.AflfuzzXmlEncoder(stream);
- }
- using (var stream = new MemoryStream(message))
{
FuzzableCode.FuzzXmlDecoderCore(stream, true);
}
- FuzzableCode.LibfuzzXmlDecoder(message);
- FuzzableCode.LibfuzzXmlEncoder(message);
+
+ TestNewUtf8Message(message);
string fileName = Path.Combine(pathTarget, $"{messageEncoder.Method.Name}.xml".ToLowerInvariant());
File.WriteAllBytes(fileName, Encoding.UTF8.GetBytes(xml));
}
+
+ // Create the Testcases for the certificate decoder.
+ pathSuffix = TestcaseEncoderSuffixes[(int)TestCaseEncoders.Certificates];
+ pathTarget = workPath + pathSuffix + Path.DirectorySeparatorChar;
+ X509Certificate2 rootCert = null;
+ X509Certificate2 certificate = null;
+ {
+ var crlName = "root.crl";
+ var crlServerUrl = "http://127.0.0.1:1234/";
+ var crlExtension = X509Extensions.BuildX509CRLDistributionPoints(crlServerUrl + crlName);
+
+ // create the root cert
+ rootCert = CertificateFactory.CreateCertificate("CN=Root")
+ .AddExtension(crlExtension)
+ .SetLifeTime(25 * 12)
+ .SetCAConstraint()
+ .SetRSAKeySize(4096)
+ .CreateForRSA();
+
+ certificate = CertificateFactory.CreateCertificate(
+ "urn:op:ua:application:test",
+ "TestApp",
+ "CN=TestApp",
+ new string[] { "test.com", "192.168.1.111", "c034:777f:9abc::1234:5678" })
+ .SetLifeTime(12)
+ .SetIssuer(rootCert)
+ .SetRSAKeySize(2048)
+ .CreateForRSA();
+
+ // Test the fuzz targets with the message.
+ byte[] rawData = certificate.RawData;
+ TestNewRawDataMessage(rawData);
+
+ // should not throw an exception
+ _ = X509CertificateLoader.LoadCertificate(rawData);
+ FuzzableCode.FuzzCertificateChainDecoderCore(rawData,false);
+ FuzzableCode.FuzzCertificateChainDecoderCore(rawData, true);
+
+ string fileName = Path.Combine(pathTarget, "certificate.bin");
+ File.WriteAllBytes(fileName, rawData);
+
+ // Test the fuzz targets with the message.
+ rawData = rootCert.RawData;
+ TestNewRawDataMessage(rawData);
+
+ // should not throw an exception
+ _ = X509CertificateLoader.LoadCertificate(rawData);
+ FuzzableCode.FuzzCertificateChainDecoderCore(rawData, false);
+ FuzzableCode.FuzzCertificateChainDecoderCore(rawData, true);
+
+ fileName = Path.Combine(pathTarget, "rootcertificate.bin");
+ File.WriteAllBytes(fileName, rawData);
+
+ // Create a binary blob chain.
+ rawData = new byte[certificate.RawData.Length + rootCert.RawData.Length];
+ certificate.RawData.CopyTo(rawData, 0);
+ rootCert.RawData.CopyTo(rawData, certificate.RawData.Length);
+ TestNewRawDataMessage(rawData);
+ FuzzableCode.FuzzCertificateChainDecoderCore(rawData, false);
+ FuzzableCode.FuzzCertificateChainDecoderCore(rawData, true);
+
+ // should not throw an exception
+ _ = X509CertificateLoader.LoadCertificate(rawData);
+ _ = Utils.ParseCertificateBlob(rawData, false);
+ _ = Utils.ParseCertificateBlob(rawData, true);
+ _ = Utils.ParseCertificateChainBlob(rawData, false);
+ _ = Utils.ParseCertificateChainBlob(rawData, true);
+
+ fileName = Path.Combine(pathTarget, "certificatechain.bin");
+ File.WriteAllBytes(fileName, rawData);
+ }
+
+ // Create the Testcases for the CRL decoder.
+ pathSuffix = TestcaseEncoderSuffixes[(int)TestCaseEncoders.CRLs];
+ pathTarget = workPath + pathSuffix + Path.DirectorySeparatorChar;
+ {
+ // create an empty CRL
+ X509CRL rootCrl = CertificateFactory.RevokeCertificate(rootCert, null, null);
+
+ // Test the fuzz targets with the message.
+ byte[] rawData = rootCrl.RawData;
+ TestNewRawDataMessage(rawData);
+
+ string fileName = Path.Combine(pathTarget, "emptyroot.crl");
+ File.WriteAllBytes(fileName, rawData);
+
+ // create a CRL with a revoked certificate
+ X509CRL revokedRootCrl = CertificateFactory.RevokeCertificate(rootCert, null, new X509Certificate2Collection(certificate));
+
+ // Test the fuzz targets with the message.
+ rawData = revokedRootCrl.RawData;
+ TestNewRawDataMessage(rawData);
+
+ fileName = Path.Combine(pathTarget, "root.crl");
+ File.WriteAllBytes(fileName, rawData);
+
+ // create a CRL which revokes the leaf certificate
+ CrlBuilder crlBuilder = CrlBuilder.Create(certificate.IssuerName);
+ IX509CRL x509CRL = crlBuilder
+ .AddRevokedCertificate(certificate, CRLReason.PrivilegeWithdrawn)
+ .CreateForRSA(certificate);
+
+ // Test the fuzz targets with the message.
+ rawData = x509CRL.RawData;
+ TestNewRawDataMessage(rawData);
+
+ fileName = Path.Combine(pathTarget, "leaf.crl");
+ File.WriteAllBytes(fileName, rawData);
+ }
+ }
+
+ private static void TestNewRawDataMessage(byte[] message)
+ {
+ FuzzableCode.LibfuzzBinaryDecoder(message);
+ FuzzableCode.LibfuzzBinaryEncoder(message);
+ using (var stream = new MemoryStream(message))
+ {
+ FuzzableCode.AflfuzzBinaryDecoder(stream);
+ }
+ using (var stream = new MemoryStream(message))
+ {
+ FuzzableCode.AflfuzzBinaryEncoder(stream);
+ }
+ using (var stream = new MemoryStream(message))
+ {
+ FuzzableCode.FuzzBinaryDecoderCore(stream);
+ }
+ FuzzableCode.LibfuzzXmlDecoder(message);
+ FuzzableCode.LibfuzzXmlEncoder(message);
+ FuzzableCode.LibfuzzCertificateDecoder(message);
+ FuzzableCode.LibfuzzCertificateChainDecoder(message);
+ FuzzableCode.LibfuzzCertificateChainDecoderCustom(message);
+ FuzzableCode.LibfuzzCRLDecoder(message);
+ FuzzableCode.LibfuzzCRLEncoder(message);
+ }
+
+ private static void TestNewUtf8Message(byte[] message)
+ {
+ FuzzableCode.LibfuzzJsonDecoder(message);
+ FuzzableCode.LibfuzzJsonEncoder(message);
+ FuzzableCode.LibfuzzXmlDecoder(message);
+ FuzzableCode.LibfuzzXmlEncoder(message);
+ FuzzableCode.LibfuzzCertificateDecoder(message);
+ FuzzableCode.LibfuzzCertificateChainDecoder(message);
+ FuzzableCode.LibfuzzCertificateChainDecoderCustom(message);
+ FuzzableCode.LibfuzzCRLDecoder(message);
+ FuzzableCode.LibfuzzCRLEncoder(message);
+
+ // string targets
+ string json = Encoding.UTF8.GetString(message);
+ FuzzableCode.AflfuzzJsonDecoder(json);
+ FuzzableCode.AflfuzzJsonEncoder(json);
+ FuzzableCode.FuzzJsonDecoderCore(json);
}
}
diff --git a/Fuzzing/Encoders/Fuzz/Encoders.Fuzz.csproj b/Fuzzing/Encoders/Fuzz/Encoders.Fuzz.csproj
index cfd8744a7b..bade0c4d7b 100644
--- a/Fuzzing/Encoders/Fuzz/Encoders.Fuzz.csproj
+++ b/Fuzzing/Encoders/Fuzz/Encoders.Fuzz.csproj
@@ -17,7 +17,7 @@
-
+
@@ -25,4 +25,9 @@
+
+
+
+
+
diff --git a/Fuzzing/Encoders/Fuzz/FuzzableCode.CRLs.cs b/Fuzzing/Encoders/Fuzz/FuzzableCode.CRLs.cs
new file mode 100644
index 0000000000..2ca7344ae7
--- /dev/null
+++ b/Fuzzing/Encoders/Fuzz/FuzzableCode.CRLs.cs
@@ -0,0 +1,208 @@
+/* ========================================================================
+ * Copyright (c) 2005-2024 The OPC Foundation, Inc. All rights reserved.
+ *
+ * OPC Foundation MIT License 1.00
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The complete license agreement can be found here:
+ * http://opcfoundation.org/License/MIT/1.00/
+ * ======================================================================*/
+
+using System;
+using System.IO;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Security.Cryptography.X509Certificates;
+using Opc.Ua.Security.Certificates;
+using Opc.Ua;
+
+///
+/// Fuzzing code for the CRL decoder and encoder.
+///
+public static partial class FuzzableCode
+{
+ ///
+ /// The CRL decoder fuzz target for afl-fuzz.
+ ///
+ /// The stdin stream from the afl-fuzz process.
+ public static void AflfuzzCRLDecoder(Stream stream)
+ {
+ using (var memoryStream = PrepareArraySegmentStream(stream))
+ {
+ FuzzCRLDecoderCore(memoryStream.ToArray());
+ }
+ }
+
+ ///
+ /// The CRL encoder fuzz target for afl-fuzz.
+ ///
+ /// The stdin stream from the afl-fuzz process.
+ public static void AflfuzzCRLEncoder(Stream stream)
+ {
+ X509CRL crl = null;
+ using (var memoryStream = PrepareArraySegmentStream(stream))
+ {
+ try
+ {
+ crl = FuzzCRLDecoderCore(memoryStream.ToArray());
+ }
+ catch
+ {
+ return;
+ }
+ }
+
+ // encode the fuzzed object and see if it crashes
+ if (crl != null)
+ {
+ _ = CrlBuilder.Create(crl).Encode();
+ }
+ }
+
+ ///
+ /// The CRL encoder indempotent fuzz target for afl-fuzz.
+ ///
+ /// The stdin stream from the afl-fuzz process.
+ public static void AflfuzzCRLEncoderIndempotent(Stream stream)
+ {
+ X509CRL crl = null;
+ byte[] serialized = null;
+ using (var memoryStream = PrepareArraySegmentStream(stream))
+ {
+ try
+ {
+ crl = FuzzCRLDecoderCore(memoryStream.ToArray(), true);
+ serialized = CrlBuilder.Create(crl).Encode();
+ }
+ catch
+ {
+ return;
+ }
+ }
+
+ // reencode the fuzzed input and see if they are indempotent
+ FuzzCRLEncoderIndempotentCore(serialized, crl);
+ }
+
+ ///
+ /// The CRL decoder fuzz target for libfuzzer.
+ ///
+ public static void LibfuzzCRLDecoder(ReadOnlySpan input)
+ {
+ _ = FuzzCRLDecoderCore(input);
+ }
+
+ ///
+ /// The CRL encoder fuzz target for libfuzzer.
+ ///
+ public static void LibfuzzCRLEncoder(ReadOnlySpan input)
+ {
+ X509CRL crl = null;
+ try
+ {
+ crl = FuzzCRLDecoderCore(input, true);
+ }
+ catch
+ {
+ return;
+ }
+
+ // encode the fuzzed object and see if it crashes
+ if (crl != null)
+ {
+ _ = CrlBuilder.Create(crl).Encode();
+ }
+ }
+
+ ///
+ /// The CRL encoder indempotent fuzz target for libfuzzer.
+ ///
+ public static void LibfuzzCRLEncoderIndempotent(ReadOnlySpan input)
+ {
+ X509CRL crl = null;
+ byte[] serialized = null;
+ try
+ {
+ crl = FuzzCRLDecoderCore(input, true);
+ serialized = CrlBuilder.Create(crl).Encode();
+ }
+ catch
+ {
+ return;
+ }
+
+ // reencode the fuzzed input and see if they are indempotent
+ FuzzCRLEncoderIndempotentCore(serialized, crl);
+ }
+
+ ///
+ /// The fuzz target for the CRL decoder.
+ ///
+ /// A byte array with fuzz content.
+ internal static X509CRL FuzzCRLDecoderCore(ReadOnlySpan serialized, bool throwAll = false)
+ {
+ try
+ {
+ var result = new X509CRL(serialized.ToArray());
+ _ = result.Issuer;
+ return result;
+ }
+ catch (CryptographicException)
+ {
+ if (!throwAll)
+ {
+ return null;
+ }
+ throw;
+ }
+ }
+
+ ///
+ /// The indempotent fuzz target core for the CRL encoder.
+ ///
+ /// The indempotent ASN.1 encoded data.
+ ///
+ internal static void FuzzCRLEncoderIndempotentCore(byte[] serialized, X509CRL encodeable)
+ {
+ if (serialized == null || encodeable == null) return;
+
+ X509CRL crl2 = FuzzCRLDecoderCore(serialized, true);
+ byte[] serialized2 = crl2.RawData;
+
+ using (var memoryStream2 = new MemoryStream(serialized2))
+ {
+ X509CRL crl3 = FuzzCRLDecoderCore(serialized2, true);
+
+ string encodeableTypeName = crl3?.GetType().Name ?? "unknown type";
+ if (serialized2 == null || !serialized.SequenceEqual(serialized2))
+ {
+ throw new Exception(Utils.Format("Indempotent encoding failed. Type={0}.", encodeableTypeName));
+ }
+
+ if (!Utils.IsEqual(crl2, crl3))
+ {
+ throw new Exception(Utils.Format("Indempotent 3rd gen decoding failed. Type={0}.", encodeableTypeName));
+ }
+ }
+ }
+}
+
diff --git a/Fuzzing/Encoders/Fuzz/FuzzableCode.Certificates.cs b/Fuzzing/Encoders/Fuzz/FuzzableCode.Certificates.cs
new file mode 100644
index 0000000000..2f56bf90d3
--- /dev/null
+++ b/Fuzzing/Encoders/Fuzz/FuzzableCode.Certificates.cs
@@ -0,0 +1,150 @@
+/* ========================================================================
+ * Copyright (c) 2005-2024 The OPC Foundation, Inc. All rights reserved.
+ *
+ * OPC Foundation MIT License 1.00
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The complete license agreement can be found here:
+ * http://opcfoundation.org/License/MIT/1.00/
+ * ======================================================================*/
+
+using System;
+using System.IO;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Security.Cryptography.X509Certificates;
+using Opc.Ua;
+
+///
+/// Fuzzing code for the certificate decoder.
+///
+public static partial class FuzzableCode
+{
+ ///
+ /// The certificate decoder fuzz target for afl-fuzz.
+ ///
+ /// The stdin stream from the afl-fuzz process.
+ public static void AflfuzzCertificateDecoder(Stream stream)
+ {
+ using (var memoryStream = PrepareArraySegmentStream(stream))
+ {
+ FuzzCertificateDecoderCore(memoryStream.ToArray());
+ }
+ }
+
+ ///
+ /// The certificate chain decoder fuzz target for afl-fuzz.
+ ///
+ /// The stdin stream from the afl-fuzz process.
+ public static void AflfuzzCertificateChainDecoder(Stream stream)
+ {
+ using (var memoryStream = PrepareArraySegmentStream(stream))
+ {
+ FuzzCertificateChainDecoderCore(memoryStream.ToArray());
+ }
+ }
+
+ ///
+ /// The certificate chain decoder with custom blob fuzz target for afl-fuzz.
+ ///
+ /// The stdin stream from the afl-fuzz process.
+ public static void AflfuzzCertificateChainDecoderCustom(Stream stream)
+ {
+ using (var memoryStream = PrepareArraySegmentStream(stream))
+ {
+ FuzzCertificateChainDecoderCore(memoryStream.ToArray(), true);
+ }
+ }
+
+ ///
+ /// The certificate decoder fuzz target for libfuzzer.
+ ///
+ public static void LibfuzzCertificateDecoder(ReadOnlySpan input)
+ {
+ _ = FuzzCertificateDecoderCore(input);
+ }
+
+ ///
+ /// The certificate encoder fuzz target for libfuzzer.
+ ///
+ public static void LibfuzzCertificateChainDecoder(ReadOnlySpan input)
+ {
+ _ = FuzzCertificateChainDecoderCore(input);
+ }
+
+ ///
+ /// The certificate encoder fuzz target for libfuzzer.
+ ///
+ public static void LibfuzzCertificateChainDecoderCustom(ReadOnlySpan input)
+ {
+ _ = FuzzCertificateChainDecoderCore(input, true);
+ }
+
+ ///
+ /// The fuzz target for the Certificate decoder.
+ ///
+ /// A byte array with fuzz content.
+ internal static X509Certificate2 FuzzCertificateDecoderCore(ReadOnlySpan serialized, bool throwAll = false)
+ {
+ try
+ {
+ return X509CertificateLoader.LoadCertificate(serialized.ToArray());
+ }
+ catch (CryptographicException)
+ {
+ if (!throwAll)
+ {
+ return null;
+ }
+ throw;
+ }
+ }
+
+ ///
+ /// The fuzz target for the Certificate chain decoder.
+ ///
+ /// A byte array with fuzz content.
+ internal static X509Certificate2Collection FuzzCertificateChainDecoderCore(ReadOnlySpan serialized, bool useAsn1Parser = false, bool throwAll = false)
+ {
+ try
+ {
+ return Utils.ParseCertificateChainBlob(serialized.ToArray(), useAsn1Parser);
+ }
+ catch (ServiceResultException sre)
+ {
+ switch (sre.StatusCode)
+ {
+ case StatusCodes.BadCertificateInvalid:
+ if (!throwAll)
+ {
+ return null;
+ }
+ break;
+
+ default:
+ break;
+ }
+ throw;
+ }
+ }
+}
+
diff --git a/Fuzzing/Encoders/Fuzz/FuzzableCode.cs b/Fuzzing/Encoders/Fuzz/FuzzableCode.cs
index 01d9536519..43528b1788 100644
--- a/Fuzzing/Encoders/Fuzz/FuzzableCode.cs
+++ b/Fuzzing/Encoders/Fuzz/FuzzableCode.cs
@@ -35,6 +35,8 @@
public static partial class FuzzableCode
{
private static ServiceMessageContext messageContext = ServiceMessageContext.GlobalContext;
+ private static BufferManager bufferManager = new BufferManager(nameof(FuzzableCode), 65535);
+ private static ChannelQuotas channelQuotas = new ChannelQuotas();
///
/// Print information about the fuzzer target.
@@ -42,7 +44,7 @@ public static partial class FuzzableCode
public static void FuzzInfo()
{
Console.WriteLine("OPC UA Core Encoder Fuzzer for afl-fuzz and libfuzzer.");
- Console.WriteLine("Fuzzing targets for various aspects of the Binary, Json and Xml encoders.");
+ Console.WriteLine("Fuzzing targets for various aspects of the OPC UA Binary, Json and Xml encoders.");
}
///
diff --git a/Fuzzing/Encoders/Fuzz/Testcases.Binary/readrequest.bin b/Fuzzing/Encoders/Fuzz/Testcases.Binary/readrequest.bin
index 15f160ef31..ac36487658 100644
Binary files a/Fuzzing/Encoders/Fuzz/Testcases.Binary/readrequest.bin and b/Fuzzing/Encoders/Fuzz/Testcases.Binary/readrequest.bin differ
diff --git a/Fuzzing/Encoders/Fuzz/Testcases.Binary/readresponse.bin b/Fuzzing/Encoders/Fuzz/Testcases.Binary/readresponse.bin
index 25561bc108..05aff1743d 100644
Binary files a/Fuzzing/Encoders/Fuzz/Testcases.Binary/readresponse.bin and b/Fuzzing/Encoders/Fuzz/Testcases.Binary/readresponse.bin differ
diff --git a/Fuzzing/Encoders/Fuzz/Testcases.CRLs/emptyroot.crl b/Fuzzing/Encoders/Fuzz/Testcases.CRLs/emptyroot.crl
new file mode 100644
index 0000000000..d562150772
Binary files /dev/null and b/Fuzzing/Encoders/Fuzz/Testcases.CRLs/emptyroot.crl differ
diff --git a/Fuzzing/Encoders/Fuzz/Testcases.CRLs/leaf.crl b/Fuzzing/Encoders/Fuzz/Testcases.CRLs/leaf.crl
new file mode 100644
index 0000000000..318d16eeeb
Binary files /dev/null and b/Fuzzing/Encoders/Fuzz/Testcases.CRLs/leaf.crl differ
diff --git a/Fuzzing/Encoders/Fuzz/Testcases.CRLs/root.crl b/Fuzzing/Encoders/Fuzz/Testcases.CRLs/root.crl
new file mode 100644
index 0000000000..352a32b1f1
Binary files /dev/null and b/Fuzzing/Encoders/Fuzz/Testcases.CRLs/root.crl differ
diff --git a/Fuzzing/Encoders/Fuzz/Testcases.Certificates/certificate.bin b/Fuzzing/Encoders/Fuzz/Testcases.Certificates/certificate.bin
new file mode 100644
index 0000000000..923dc3899f
Binary files /dev/null and b/Fuzzing/Encoders/Fuzz/Testcases.Certificates/certificate.bin differ
diff --git a/Fuzzing/Encoders/Fuzz/Testcases.Certificates/certificatechain.bin b/Fuzzing/Encoders/Fuzz/Testcases.Certificates/certificatechain.bin
new file mode 100644
index 0000000000..7f296b6e72
Binary files /dev/null and b/Fuzzing/Encoders/Fuzz/Testcases.Certificates/certificatechain.bin differ
diff --git a/Fuzzing/Encoders/Fuzz/Testcases.Certificates/rootcertificate.bin b/Fuzzing/Encoders/Fuzz/Testcases.Certificates/rootcertificate.bin
new file mode 100644
index 0000000000..c484c05a6b
Binary files /dev/null and b/Fuzzing/Encoders/Fuzz/Testcases.Certificates/rootcertificate.bin differ
diff --git a/Fuzzing/Encoders/Fuzz/Testcases.Json/readrequest.json b/Fuzzing/Encoders/Fuzz/Testcases.Json/readrequest.json
index ba55d02acc..e0161ef433 100644
--- a/Fuzzing/Encoders/Fuzz/Testcases.Json/readrequest.json
+++ b/Fuzzing/Encoders/Fuzz/Testcases.Json/readrequest.json
@@ -1 +1 @@
-{"TypeId":{"Id":629},"Body":{"RequestHeader":{"Timestamp":"2024-04-21T04:30:30.6104202Z","RequestHandle":42,"ReturnDiagnostics":0,"TimeoutHint":0},"MaxAge":0,"TimestampsToReturn":0,"NodesToRead":[{"NodeId":{"Id":1000},"AttributeId":5},{"NodeId":{"Id":1000},"AttributeId":13},{"NodeId":{"Id":1000},"AttributeId":4},{"NodeId":{"Id":1000},"AttributeId":17},{"NodeId":{"Id":1000},"AttributeId":24}]}}
\ No newline at end of file
+{"TypeId":{"Id":629},"Body":{"RequestHeader":{"Timestamp":"2025-02-06T05:50:41.6658997Z","RequestHandle":422,"ReturnDiagnostics":1023,"TimeoutHint":10000},"MaxAge":1000,"TimestampsToReturn":0,"NodesToRead":[{"NodeId":{"Id":123},"AttributeId":25},{"NodeId":{"Id":4444,"Namespace":2},"AttributeId":5},{"NodeId":{"IdType":1,"Id":"RevisionCounter","Namespace":3},"AttributeId":13,"IndexRange":"1:2"},{"NodeId":{"IdType":2,"Id":"6fe986d2-d4e4-4d9e-89e2-12cf71047951"},"AttributeId":4},{"NodeId":{"Id":4444,"Namespace":2},"AttributeId":17},{"NodeId":{"IdType":3,"Id":"QhY3LAs="},"AttributeId":24}]}}
\ No newline at end of file
diff --git a/Fuzzing/Encoders/Fuzz/Testcases.Json/readresponse.json b/Fuzzing/Encoders/Fuzz/Testcases.Json/readresponse.json
index 80262fb5ba..4588ab0aaa 100644
--- a/Fuzzing/Encoders/Fuzz/Testcases.Json/readresponse.json
+++ b/Fuzzing/Encoders/Fuzz/Testcases.Json/readresponse.json
@@ -1 +1 @@
-{"TypeId":{"Id":632},"Body":{"ResponseHeader":{"Timestamp":"2024-04-21T04:30:30.6969268Z","RequestHandle":42,"ServiceDiagnostics":{"AdditionalInfo":"NodeId not found","InnerStatusCode":2153644032,"InnerDiagnosticInfo":{"AdditionalInfo":"Hello World","InnerStatusCode":2150891520,"InnerDiagnosticInfo":{"AdditionalInfo":"Hello World","InnerStatusCode":2150891520,"InnerDiagnosticInfo":{"AdditionalInfo":"Hello World","InnerStatusCode":2150891520}}}}},"Results":[{"Value":{"Type":12,"Body":"Hello World"},"SourceTimestamp":"2024-04-21T04:31:30.6908516Z","SourcePicoseconds":10,"ServerTimestamp":"2024-04-21T04:30:30.6908516Z","ServerPicoseconds":100},{"Value":{"Type":7,"Body":12345678},"StatusCode":2157772800,"SourceTimestamp":"2024-04-21T04:31:30.6908516Z","ServerTimestamp":"2024-04-21T04:30:30.6908516Z"},{"Value":{"Type":15,"Body":"AAECAwQFBg=="},"SourceTimestamp":"2024-04-21T04:31:30.6908516Z","ServerTimestamp":"2024-04-21T04:30:30.6908516Z"},{"Value":{"Type":3,"Body":42}}],"DiagnosticInfos":[{"AdditionalInfo":"Hello World","InnerStatusCode":2148925440,"InnerDiagnosticInfo":{"AdditionalInfo":"Hello World","InnerStatusCode":2150891520}}]}}
\ No newline at end of file
+{"TypeId":{"Id":632},"Body":{"ResponseHeader":{"Timestamp":"2025-02-06T05:50:42.1388195Z","RequestHandle":42,"ServiceDiagnostics":{"AdditionalInfo":"NodeId not found","InnerStatusCode":2161770496,"InnerDiagnosticInfo":{"AdditionalInfo":"Hello World","InnerStatusCode":2151022592,"InnerDiagnosticInfo":{"AdditionalInfo":"Hello World","InnerStatusCode":2149711872,"InnerDiagnosticInfo":{"AdditionalInfo":"Hello World","InnerStatusCode":2165637120}}}}},"Results":[{"Value":{"Type":12,"Body":"Hello World"},"SourceTimestamp":"2025-02-06T05:51:42.1387675Z","SourcePicoseconds":10,"ServerTimestamp":"2025-02-06T05:50:42.1387675Z","ServerPicoseconds":100},{"Value":{"Type":7,"Body":12345678},"StatusCode":2157772800,"SourceTimestamp":"2025-02-06T05:51:42.1387675Z","ServerTimestamp":"2025-02-06T05:50:42.1387675Z"},{"Value":{"Type":15,"Body":"AAECAwQFBg=="},"SourceTimestamp":"2025-02-06T05:51:42.1387675Z","ServerTimestamp":"2025-02-06T05:50:42.1387675Z"},{"Value":{"Type":3,"Body":42},"SourceTimestamp":"2025-02-06T05:50:42.1387675Z"},{"Value":{"Type":3,"Body":[1,2,3,4,11,22,33,44],"Dimensions":[2,2,2]},"ServerTimestamp":"2025-02-06T05:50:42.1387675Z"}],"DiagnosticInfos":[{"AdditionalInfo":"Hello World","InnerStatusCode":2148925440,"InnerDiagnosticInfo":{"AdditionalInfo":"Hello World","InnerStatusCode":2150891520}}]}}
\ No newline at end of file
diff --git a/Fuzzing/Encoders/Fuzz/Testcases.Xml/readrequest.xml b/Fuzzing/Encoders/Fuzz/Testcases.Xml/readrequest.xml
index 34b7bc8cca..915568f009 100644
--- a/Fuzzing/Encoders/Fuzz/Testcases.Xml/readrequest.xml
+++ b/Fuzzing/Encoders/Fuzz/Testcases.Xml/readrequest.xml
@@ -1,41 +1,48 @@
- 2024-05-03T12:59:58.4456622Z
- 42
- 0
- 0
+ 2025-02-06T05:50:42.9259436Z
+ 422
+ 1023
+ 10000
- 0
+ 1000
Source_0
- i=1000
+ i=123
+
+ 25
+
+
+
+ ns=2;i=4444
5
- i=1000
+ ns=3;s=RevisionCounter
13
+ 1:2
- i=1000
+ g=ef982ce2-00b2-4306-8338-beb422db6f3c
4
- i=1000
+ ns=2;i=4444
17
- i=1000
+ b=QhY3LAs=
24
diff --git a/Fuzzing/Encoders/Fuzz/Testcases.Xml/readresponse.xml b/Fuzzing/Encoders/Fuzz/Testcases.Xml/readresponse.xml
index 5d550a5183..8bbf0f8244 100644
--- a/Fuzzing/Encoders/Fuzz/Testcases.Xml/readresponse.xml
+++ b/Fuzzing/Encoders/Fuzz/Testcases.Xml/readresponse.xml
@@ -1,6 +1,6 @@
- 2024-05-03T13:00:39.3472074Z
+ 2025-02-06T05:50:43.7080229Z
42
0
@@ -12,7 +12,7 @@
-1
NodeId not found
- 2153644032
+ 2161770496
-1
@@ -21,7 +21,7 @@
-1
Hello World
- 2150891520
+ 2151022592
-1
@@ -30,7 +30,7 @@
-1
Hello World
- 2150891520
+ 2149711872
-1
@@ -39,7 +39,7 @@
-1
Hello World
- 2150891520
+ 2165637120
@@ -57,9 +57,9 @@
0
- 2024-05-03T13:01:39.3471774Z
+ 2025-02-06T05:51:43.7079679Z
10
- 2024-05-03T13:00:39.3471774Z
+ 2025-02-06T05:50:43.7079679Z
100
@@ -71,9 +71,9 @@
2157772800
- 2024-05-03T13:01:39.3471774Z
+ 2025-02-06T05:51:43.7079679Z
0
- 2024-05-03T13:00:39.3471774Z
+ 2025-02-06T05:50:43.7079679Z
0
@@ -85,9 +85,9 @@
0
- 2024-05-03T13:01:39.3471774Z
+ 2025-02-06T05:51:43.7079679Z
0
- 2024-05-03T13:00:39.3471774Z
+ 2025-02-06T05:50:43.7079679Z
0
@@ -99,11 +99,43 @@
0
- 2024-05-03T13:00:39.3471774Z
+ 2025-02-06T05:50:43.7079679Z
0
0001-01-01T00:00:00
0
+
+
+
+
+
+
+ 1
+ 2
+ 3
+ 4
+ 11
+ 22
+ 33
+ 44
+
+
+
+ 2
+ 2
+ 2
+
+
+
+
+
+ 0
+
+ 0001-01-01T00:00:00
+ 0
+ 2025-02-06T05:50:43.7079679Z
+ 0
+
diff --git a/Fuzzing/Encoders/aflfuzz.sh b/Fuzzing/Encoders/aflfuzz.sh
index ebf40ee227..621a2ba773 100644
--- a/Fuzzing/Encoders/aflfuzz.sh
+++ b/Fuzzing/Encoders/aflfuzz.sh
@@ -10,7 +10,12 @@ display_menu() {
echo "5. Opc.Ua.JsonEncoder"
echo "6. Opc.Ua.XmlDecoder"
echo "7. Opc.Ua.XmlEncoder"
- echo "8. Exit"
+ echo "8. ASN.1 Certificate decoder"
+ echo "9. ASN.1 Certificate chain decoder"
+ echo "10. ASN.1 Certificate chain decoder with custom blob parser (macOS)"
+ echo "11. ASN.1 CRL decoder"
+ echo "12. ASN.1 CRL encoder"
+ echo "13. Exit"
}
# Function to execute fuzz-afl PowerShell script based on user choice
@@ -44,6 +49,26 @@ execute_powershell_script() {
echo "Running afl-fuzz with Opc.Ua.XmlEncoder"
pwsh ../scripts/fuzz-afl.ps1 ./Fuzz/Encoders.Fuzz.csproj -i ./Fuzz/Testcases.Xml -x ../dictionaries/xml.dict -fuzztarget AflfuzzXmlEncoder
;;
+ 8)
+ echo "Running afl-fuzz with Certificate decoder"
+ pwsh ../scripts/fuzz-afl.ps1 ./Fuzz/Encoders.Fuzz.csproj -i ./Fuzz/Testcases.Certificates -fuzztarget AflfuzzCertificateDecoder
+ ;;
+ 9)
+ echo "Running afl-fuzz with Certificate chain decoder"
+ pwsh ../scripts/fuzz-afl.ps1 ./Fuzz/Encoders.Fuzz.csproj -i ./Fuzz/Testcases.Certificates -fuzztarget AflfuzzCertificateChainDecoder
+ ;;
+ 10)
+ echo "Running afl-fuzz with Certificate chain decoder and custom blob parser"
+ pwsh ../scripts/fuzz-afl.ps1 ./Fuzz/Encoders.Fuzz.csproj -i ./Fuzz/Testcases.Certificates -fuzztarget AflfuzzCertificateChainDecoderCustom
+ ;;
+ 11)
+ echo "Running afl-fuzz with CRL Decoder"
+ pwsh ../scripts/fuzz-afl.ps1 ./Fuzz/Encoders.Fuzz.csproj -i ./Fuzz/Testcases.CRLs -fuzztarget AflfuzzCRLDecoder
+ ;;
+ 12)
+ echo "Running afl-fuzz with CRL Encoder"
+ pwsh ../scripts/fuzz-afl.ps1 ./Fuzz/Encoders.Fuzz.csproj -i ./Fuzz/Testcases.CRLs -fuzztarget AflfuzzCRLEncoder
+ ;;
*)
echo "Invalid option. Exiting."
;;
@@ -53,18 +78,18 @@ execute_powershell_script() {
# Main
display_menu
-read -p "Enter your choice (1-8): " choice
+read -p "Enter your choice (1-12): " choice
case $choice in
- 1|2|3|4|5|6|7)
+ 1|2|3|4|5|6|7|8|9|10|11|12)
execute_powershell_script $choice
;;
- 8)
+ 13)
echo "Exiting."
break
;;
*)
- echo "Invalid input. Please enter a number between 1 and 8."
+ echo "Invalid input. Please enter a number between 1 and 12."
;;
esac
diff --git a/Fuzzing/Encoders/libfuzz.bat b/Fuzzing/Encoders/libfuzz.bat
index 52407f2095..dd82b3d76f 100644
--- a/Fuzzing/Encoders/libfuzz.bat
+++ b/Fuzzing/Encoders/libfuzz.bat
@@ -4,13 +4,21 @@ cls
echo "Select a OPA UA Encoder fuzzing function:"
echo "1. Opc.Ua.BinaryDecoder"
echo "2. Opc.Ua.BinaryEncoder"
-echo "3. Opc.Ua.JsonDecoder"
-echo "4. Opc.Ua.JsonEncoder"
-echo "5. Opc.Ua.XmlDecoder"
-echo "6. Opc.Ua.XmlEncoder"
-echo "7. Exit"
+echo "3. Opc.Ua.BinaryDecoder Indempotent"
+echo "4. Opc.Ua.JsonDecoder"
+echo "5. Opc.Ua.JsonEncoder"
+echo "6. Opc.Ua.XmlDecoder"
+echo "7. Opc.Ua.XmlEncoder"
+echo "8. ASN.1 Certificate decoder"
+echo "9. ASN.1 Certificate chain decoder"
+echo "10. ASN.1 Certificate chain decoder with custom blob parser (macOS)"
+echo "11. ASN.1 CRL decoder"
+echo "12. ASN.1 CRL encoder"
+echo "13. Exit"
-set /p choice="Enter your choice (1-7): "
+set /p choice="Enter your choice (1-13): "
+
+echo Choice %choice%
if "%choice%"=="1" (
echo "Running libfuzzer with Opc.Ua.BinaryDecoder"
@@ -19,22 +27,40 @@ if "%choice%"=="1" (
echo "Running libfuzzer with Opc.Ua.BinaryEncoder"
powershell.exe -File ../scripts/fuzz-libfuzzer.ps1 -libFuzzer "./libfuzzer-dotnet-windows.exe" -project ./Fuzz/Encoders.Fuzz.csproj -fuzztarget LibfuzzBinaryEncoder -corpus ./Fuzz/Testcases.Binary/
) else if "%choice%"=="3" (
+ echo "Running libfuzzer with Opc.Ua.BinaryEncoder Indempotent"
+ powershell.exe -File ../scripts/fuzz-libfuzzer.ps1 -libFuzzer "./libfuzzer-dotnet-windows.exe" -project ./Fuzz/Encoders.Fuzz.csproj -fuzztarget LibfuzzBinaryEncoderIndempotent -corpus ./Fuzz/Testcases.Binary/
+) else if "%choice%"=="4" (
echo "Running libfuzzer with Opc.Ua.JsonDecoder"
powershell.exe -File ../scripts/fuzz-libfuzzer.ps1 -libFuzzer "./libfuzzer-dotnet-windows.exe" -project ./Fuzz/Encoders.Fuzz.csproj -fuzztarget LibfuzzJsonDecoder -dict ../dictionaries/json.dict -corpus ./Fuzz/Testcases.Json/
-) else if "%choice%"=="4" (
+) else if "%choice%"=="5" (
echo "Running libfuzzer with Opc.Ua.JsonEncoder"
powershell.exe -File ../scripts/fuzz-libfuzzer.ps1 -libFuzzer "./libfuzzer-dotnet-windows.exe" -project ./Fuzz/Encoders.Fuzz.csproj -fuzztarget LibfuzzJsonEncoder -dict ../dictionaries/json.dict -corpus ./Fuzz/Testcases.Json/
-) else if "%choice%"=="5" (
+) else if "%choice%"=="6" (
echo "Running libfuzzer with Opc.Ua.XmlDecoder"
powershell.exe -File ../scripts/fuzz-libfuzzer.ps1 -libFuzzer "./libfuzzer-dotnet-windows.exe" -project ./Fuzz/Encoders.Fuzz.csproj -fuzztarget LibfuzzXmlDecoder -dict ../dictionaries/xml.dict -corpus ./Fuzz/Testcases.Xml/
-) else if "%choice%"=="6" (
+) else if "%choice%"=="7" (
echo "Running libfuzzer with Opc.Ua.XmlEncoder"
powershell.exe -File ../scripts/fuzz-libfuzzer.ps1 -libFuzzer "./libfuzzer-dotnet-windows.exe" -project ./Fuzz/Encoders.Fuzz.csproj -fuzztarget LibfuzzXmlEncoder -dict ../dictionaries/xml.dict -corpus ./Fuzz/Testcases.Xml/
-) else if "%choice%"=="7" (
+) else if "%choice%"=="8" (
+ echo "Running libfuzzer with ASN.1 Certificate decoder"
+ powershell.exe -File ../scripts/fuzz-libfuzzer.ps1 -libFuzzer "./libfuzzer-dotnet-windows.exe" -project ./Fuzz/Encoders.Fuzz.csproj -fuzztarget LibfuzzCertificateDecoder -corpus ./Fuzz/Testcases.Certificates/
+) else if "%choice%"=="9" (
+ echo "Running libfuzzer with ASN.1 Certificate chain decoder"
+ powershell.exe -File ../scripts/fuzz-libfuzzer.ps1 -libFuzzer "./libfuzzer-dotnet-windows.exe" -project ./Fuzz/Encoders.Fuzz.csproj -fuzztarget LibfuzzCertificateChainDecoder -corpus ./Fuzz/Testcases.Certificates/
+) else if "%choice%"=="10" (
+ echo "Running libfuzzer with ASN.1 Certificate chain decoder with custom blob parser"
+ powershell.exe -File ../scripts/fuzz-libfuzzer.ps1 -libFuzzer "./libfuzzer-dotnet-windows.exe" -project ./Fuzz/Encoders.Fuzz.csproj -fuzztarget LibfuzzCertificateChainDecoderCustom -corpus ./Fuzz/Testcases.Certificates/
+) else if "%choice%"=="11" (
+ echo "Running libfuzzer with ASN.1 CRL decoder"
+ powershell.exe -File ../scripts/fuzz-libfuzzer.ps1 -libFuzzer "./libfuzzer-dotnet-windows.exe" -project ./Fuzz/Encoders.Fuzz.csproj -fuzztarget LibfuzzCRLDecoder -corpus ./Fuzz/Testcases.CRLs/
+) else if "%choice%"=="12" (
+ echo "Running libfuzzer with ASN.1 CRL encoder"
+ powershell.exe -File ../scripts/fuzz-libfuzzer.ps1 -libFuzzer "./libfuzzer-dotnet-windows.exe" -project ./Fuzz/Encoders.Fuzz.csproj -fuzztarget LibfuzzCRLEncoder -corpus ./Fuzz/Testcases.CRLs/
+) else if "%choice%"=="13" (
echo Exiting.
exit /b
) else (
- echo Invalid input. Please enter a number between 1 and 7.
+ echo Invalid input. Please enter a number between 1 and 13.
)
echo Done
\ No newline at end of file
diff --git a/Fuzzing/Encoders/libfuzz.sh b/Fuzzing/Encoders/libfuzz.sh
index f4e2a9f47e..1f89a4b3b9 100644
--- a/Fuzzing/Encoders/libfuzz.sh
+++ b/Fuzzing/Encoders/libfuzz.sh
@@ -5,11 +5,17 @@ display_menu() {
echo "Select a OPA UA Encoder fuzzing function:"
echo "1. Opc.Ua.BinaryDecoder"
echo "2. Opc.Ua.BinaryEncoder"
+ echo "3. Opc.Ua.BinaryEncoder Indempotent"
echo "3. Opc.Ua.JsonDecoder"
echo "4. Opc.Ua.JsonEncoder"
echo "5. Opc.Ua.XmlDecoder"
echo "6. Opc.Ua.XmlEncoder"
- echo "7. Exit"
+ echo "8. ASN.1 Certificate decoder"
+ echo "9. ASN.1 Certificate chain decoder"
+ echo "10. ASN.1 Certificate chain decoder with custom blob parser (macOS)"
+ echo "11. ASN.1 CRL decoder"
+ echo "12. ASN.1 CRL encoder"
+ echo "13. Exit"
}
# Function to execute fuzz-afl PowerShell script based on user choice
@@ -24,21 +30,45 @@ execute_powershell_script() {
pwsh ../scripts/fuzz-libfuzzer.ps1 -libFuzzer "./libfuzzer-dotnet-ubuntu" -project ./Fuzz/Encoders.Fuzz.csproj -fuzztarget LibfuzzBinaryEncoder -corpus ./Fuzz/Testcases.Binary/
;;
3)
+ echo "Running libfuzzer with Opc.Ua.BinaryEncoder"
+ pwsh ../scripts/fuzz-libfuzzer.ps1 -libFuzzer "./libfuzzer-dotnet-ubuntu" -project ./Fuzz/Encoders.Fuzz.csproj -fuzztarget LibfuzzBinaryEncoderIndempotent -corpus ./Fuzz/Testcases.Binary/
+ ;;
+ 4)
echo "Running libfuzzer with Opc.Ua.JsonDecoder"
pwsh ../scripts/fuzz-libfuzzer.ps1 -libFuzzer "./libfuzzer-dotnet-ubuntu" -project ./Fuzz/Encoders.Fuzz.csproj -fuzztarget LibfuzzJsonDecoder -dict ../dictionaries/json.dict -corpus ./Fuzz/Testcases.Json/
;;
- 4)
+ 5)
echo "Running libfuzzer with Opc.Ua.JsonEncoder"
pwsh ../scripts/fuzz-libfuzzer.ps1 -libFuzzer "./libfuzzer-dotnet-ubuntu" -project ./Fuzz/Encoders.Fuzz.csproj -fuzztarget LibfuzzJsonEncoder -dict ../dictionaries/json.dict -corpus ./Fuzz/Testcases.Json/
;;
- 5)
+ 6)
echo "Running libfuzzer with Opc.Ua.XmlDecoder"
pwsh ../scripts/fuzz-libfuzzer.ps1 -libFuzzer "./libfuzzer-dotnet-ubuntu" -project ./Fuzz/Encoders.Fuzz.csproj -fuzztarget LibfuzzXmlDecoder -dict ../dictionaries/xml.dict -corpus ./Fuzz/Testcases.Xml/
;;
- 6)
+ 7)
echo "Running libfuzzer with Opc.Ua.XmlEncoder"
pwsh ../scripts/fuzz-libfuzzer.ps1 -libFuzzer "./libfuzzer-dotnet-ubuntu" -project ./Fuzz/Encoders.Fuzz.csproj -fuzztarget LibfuzzXmlEncoder -dict ../dictionaries/xml.dict -corpus ./Fuzz/Testcases.Xml/
;;
+ 8)
+ echo "Running libfuzzer with ASN.1 Certificate decoder"
+ pwsh ../scripts/fuzz-libfuzzer.ps1 -libFuzzer "./libfuzzer-dotnet-ubuntu" -project ./Fuzz/Encoders.Fuzz.csproj -fuzztarget LibfuzzCertificateDecoder -corpus ./Fuzz/Testcases.Certificates/
+ ;;
+ 9)
+ echo "Running libfuzzer with ASN.1 Certificate chain decoder"
+ pwsh ../scripts/fuzz-libfuzzer.ps1 -libFuzzer "./libfuzzer-dotnet-ubuntu" -project ./Fuzz/Encoders.Fuzz.csproj -fuzztarget LibfuzzCertificateChainDecoder -corpus ./Fuzz/Testcases.Certificates/
+ ;;
+ 10)
+ echo "Running libfuzzer with ASN.1 Certificate chain decoder with custom blob parser (macOS)"
+ pwsh ../scripts/fuzz-libfuzzer.ps1 -libFuzzer "./libfuzzer-dotnet-ubuntu" -project ./Fuzz/Encoders.Fuzz.csproj -fuzztarget LibfuzzCertificateChainDecoderCustom -corpus ./Fuzz/Testcases.Certificates/
+ ;;
+ 11)
+ echo "Running libfuzzer with ASN.1 CRL decoder"
+ pwsh ../scripts/fuzz-libfuzzer.ps1 -libFuzzer "./libfuzzer-dotnet-ubuntu" -project ./Fuzz/Encoders.Fuzz.csproj -fuzztarget LibfuzzCRLDecoder -corpus ./Fuzz/Testcases.CRLs/
+ ;;
+ 12)
+ echo "Running libfuzzer with ASN.1 CRL encoder"
+ pwsh ../scripts/fuzz-libfuzzer.ps1 -libFuzzer "./libfuzzer-dotnet-ubuntu" -project ./Fuzz/Encoders.Fuzz.csproj -fuzztarget LibfuzzCRLEncoder -corpus ./Fuzz/Testcases.CRLs/
+ ;;
*)
echo "Invalid option. Exiting."
;;
@@ -48,18 +78,18 @@ execute_powershell_script() {
# Main
display_menu
-read -p "Enter your choice (1-5): " choice
+read -p "Enter your choice (1-12): " choice
case $choice in
- 1|2|3|4|5|6)
+ 1|2|3|4|5|6|7|8|9|10|11|12)
execute_powershell_script $choice
;;
- 7)
+ 13)
echo "Exiting."
break
;;
*)
- echo "Invalid input. Please enter a number between 1 and 5."
+ echo "Invalid input. Please enter a number between 1 and 13."
;;
esac
diff --git a/Fuzzing/common/Fuzz.Tools/Testcases.cs b/Fuzzing/common/Fuzz.Tools/Testcases.cs
index 137b2ec2a9..4065eb7f7c 100644
--- a/Fuzzing/common/Fuzz.Tools/Testcases.cs
+++ b/Fuzzing/common/Fuzz.Tools/Testcases.cs
@@ -43,35 +43,48 @@ public partial class Testcases
public static void ReadRequest(IEncoder encoder)
{
- var nodeId = new NodeId(1000);
+ var twoByteNodeIdNumeric = new NodeId(123);
+ var nodeIdNumeric = new NodeId(4444, 2);
+ var nodeIdString = new NodeId("ns=3;s=RevisionCounter");
+ var nodeIdGuid = new NodeId(Guid.NewGuid());
+ var nodeIdOpaque = new NodeId(new byte[] { 66, 22, 55, 44, 11 });
var readRequest = new ReadRequest {
RequestHeader = new RequestHeader {
Timestamp = DateTime.UtcNow,
- RequestHandle = 42,
+ TimeoutHint = 10000,
+ RequestHandle = 422,
AdditionalHeader = new ExtensionObject(),
+ ReturnDiagnostics = (uint)DiagnosticsMasks.All,
},
NodesToRead = new ReadValueIdCollection {
new ReadValueId {
- NodeId = nodeId,
+ NodeId = twoByteNodeIdNumeric,
+ AttributeId = Attributes.UserRolePermissions,
+ },
+ new ReadValueId {
+ NodeId = nodeIdNumeric,
AttributeId = Attributes.Description,
},
new ReadValueId {
- NodeId = nodeId,
+ NodeId = nodeIdString,
AttributeId = Attributes.Value,
+ IndexRange = "1:2",
},
new ReadValueId {
- NodeId = nodeId,
+ NodeId = nodeIdGuid,
AttributeId = Attributes.DisplayName,
},
new ReadValueId {
- NodeId = nodeId,
+ NodeId = nodeIdNumeric,
AttributeId = Attributes.AccessLevel,
},
new ReadValueId {
- NodeId = nodeId,
+ NodeId = nodeIdOpaque,
AttributeId = Attributes.RolePermissions,
},
},
+ MaxAge = 1000,
+ TimestampsToReturn = TimestampsToReturn.Source,
};
encoder.EncodeMessage(readRequest);
}
@@ -80,6 +93,7 @@ public static void ReadResponse(IEncoder encoder)
{
var now = DateTime.UtcNow;
var nodeId = new NodeId(1000);
+ var matrix = new byte[2, 2, 2] { { { 1, 2 }, { 3, 4 } }, { { 11, 22 }, { 33, 44 } } };
var readRequest = new ReadResponse {
Results = new DataValueCollection {
new DataValue {
@@ -106,6 +120,11 @@ public static void ReadResponse(IEncoder encoder)
Value = new Variant((byte)42),
SourceTimestamp = now,
},
+ new DataValue {
+ Value = new Variant(new Matrix(matrix, BuiltInType.Byte)),
+ ServerTimestamp = now,
+ },
+
},
DiagnosticInfos = new DiagnosticInfoCollection {
new DiagnosticInfo {
@@ -123,16 +142,16 @@ public static void ReadResponse(IEncoder encoder)
ServiceResult = StatusCodes.Good,
ServiceDiagnostics = new DiagnosticInfo {
AdditionalInfo = "NodeId not found",
- InnerStatusCode = StatusCodes.BadNodeIdExists,
+ InnerStatusCode = StatusCodes.BadAggregateConfigurationRejected,
InnerDiagnosticInfo = new DiagnosticInfo {
AdditionalInfo = "Hello World",
- InnerStatusCode = StatusCodes.BadNodeIdUnknown,
+ InnerStatusCode = StatusCodes.BadIndexRangeInvalid,
InnerDiagnosticInfo = new DiagnosticInfo {
AdditionalInfo = "Hello World",
- InnerStatusCode = StatusCodes.BadNodeIdUnknown,
+ InnerStatusCode = StatusCodes.BadSecureChannelIdInvalid,
InnerDiagnosticInfo = new DiagnosticInfo {
AdditionalInfo = "Hello World",
- InnerStatusCode = StatusCodes.BadNodeIdUnknown,
+ InnerStatusCode = StatusCodes.BadAlreadyExists,
},
},
},
diff --git a/Libraries/Opc.Ua.Security.Certificates/Properties/AssemblyInfo.cs b/Libraries/Opc.Ua.Security.Certificates/Properties/AssemblyInfo.cs
index 30b5ad22b5..fc2c918461 100644
--- a/Libraries/Opc.Ua.Security.Certificates/Properties/AssemblyInfo.cs
+++ b/Libraries/Opc.Ua.Security.Certificates/Properties/AssemblyInfo.cs
@@ -46,7 +46,31 @@
"f78357b8745cb6e1334655afce1a9527ac92fc829ff585ea79f007e52ba0f83ead627e3edda40b" +
"ec5ae574128fc9342cb57cb8285aa4e5b589c0ebef3be571b5c8f2ab1067f7c880e8f8882a73c8" +
"0a12a1ef")]
+[assembly: InternalsVisibleTo("Encoders.Fuzz, PublicKey = " +
+ // OPC Foundation Strong Name Public Key
+ "0024000004800000940000000602000000240000525341310004000001000100d987b12f068b35" +
+ "80429f3dde01397508880fc7e62621397618456ca1549aeacfbdb90c62adfe918f05ce3677b390" +
+ "f78357b8745cb6e1334655afce1a9527ac92fc829ff585ea79f007e52ba0f83ead627e3edda40b" +
+ "ec5ae574128fc9342cb57cb8285aa4e5b589c0ebef3be571b5c8f2ab1067f7c880e8f8882a73c8" +
+ "0a12a1ef")]
+[assembly: InternalsVisibleTo("Encoders.Fuzz.Tools, PublicKey = " +
+ // OPC Foundation Strong Name Public Key
+ "0024000004800000940000000602000000240000525341310004000001000100d987b12f068b35" +
+ "80429f3dde01397508880fc7e62621397618456ca1549aeacfbdb90c62adfe918f05ce3677b390" +
+ "f78357b8745cb6e1334655afce1a9527ac92fc829ff585ea79f007e52ba0f83ead627e3edda40b" +
+ "ec5ae574128fc9342cb57cb8285aa4e5b589c0ebef3be571b5c8f2ab1067f7c880e8f8882a73c8" +
+ "0a12a1ef")]
+[assembly: InternalsVisibleTo("Opc.Ua.Encoders.Fuzz.Tests, PublicKey = " +
+ // OPC Foundation Strong Name Public Key
+ "0024000004800000940000000602000000240000525341310004000001000100d987b12f068b35" +
+ "80429f3dde01397508880fc7e62621397618456ca1549aeacfbdb90c62adfe918f05ce3677b390" +
+ "f78357b8745cb6e1334655afce1a9527ac92fc829ff585ea79f007e52ba0f83ead627e3edda40b" +
+ "ec5ae574128fc9342cb57cb8285aa4e5b589c0ebef3be571b5c8f2ab1067f7c880e8f8882a73c8" +
+ "0a12a1ef")]
#else
[assembly: InternalsVisibleTo("Opc.Ua.Security.Certificates.Tests")]
[assembly: InternalsVisibleTo("Opc.Ua.Core.Tests")]
+[assembly: InternalsVisibleTo("Encoders.Fuzz")]
+[assembly: InternalsVisibleTo("Encoders.Fuzz.Tools")]
+[assembly: InternalsVisibleTo("Opc.Ua.Encoders.Fuzz.Tests")]
#endif
diff --git a/Libraries/Opc.Ua.Server/Configuration/ConfigurationNodeManager.cs b/Libraries/Opc.Ua.Server/Configuration/ConfigurationNodeManager.cs
index a41431b66f..7283148d48 100644
--- a/Libraries/Opc.Ua.Server/Configuration/ConfigurationNodeManager.cs
+++ b/Libraries/Opc.Ua.Server/Configuration/ConfigurationNodeManager.cs
@@ -695,7 +695,7 @@ private ServiceResult GetCertificates(
{
certificateTypeIds = new NodeId[1] { certificateTypeId };
certificates = new byte[1][];
- certificates[0] = certificateGroup.ApplicationCertificate.Certificate.GetRawCertData();
+ certificates[0] = certificateGroup.ApplicationCertificate.Certificate.RawData;
}
else
{
diff --git a/Stack/Opc.Ua.Core/Stack/Buffers/ArrayPoolBufferWriter{T}.cs b/Stack/Opc.Ua.Core/Stack/Buffers/ArrayPoolBufferWriter{T}.cs
index 7394f4f7bc..59cae11dc8 100644
--- a/Stack/Opc.Ua.Core/Stack/Buffers/ArrayPoolBufferWriter{T}.cs
+++ b/Stack/Opc.Ua.Core/Stack/Buffers/ArrayPoolBufferWriter{T}.cs
@@ -139,6 +139,7 @@ public Span GetSpan(int sizeHint = 0)
throw new ArgumentOutOfRangeException(nameof(sizeHint), $"{nameof(sizeHint)} must be non-negative.");
}
+
int remainingSpace = CheckAndAllocateBuffer(sizeHint);
return _currentBuffer.AsSpan(_offset, remainingSpace);
}
diff --git a/Stack/Opc.Ua.Core/Types/Utils/Utils.cs b/Stack/Opc.Ua.Core/Types/Utils/Utils.cs
index 1b49fd94be..0c8ed69ead 100644
--- a/Stack/Opc.Ua.Core/Types/Utils/Utils.cs
+++ b/Stack/Opc.Ua.Core/Types/Utils/Utils.cs
@@ -2824,12 +2824,12 @@ public static byte[] Append(params byte[][] arrays)
///
/// Creates a X509 certificate object from the DER encoded bytes.
///
- public static X509Certificate2 ParseCertificateBlob(ReadOnlyMemory certificateData)
+ public static X509Certificate2 ParseCertificateBlob(ReadOnlyMemory certificateData, bool useAsnParser = false)
{
// macOS X509Certificate2 constructor throws exception if a certchain is encoded
// use AsnParser on macOS to parse for byteblobs,
#if !NETFRAMEWORK
- bool useAsnParser = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
+ useAsnParser = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
#endif
try
{
@@ -2858,15 +2858,16 @@ public static X509Certificate2 ParseCertificateBlob(ReadOnlyMemory certifi
/// Creates a X509 certificate collection object from the DER encoded bytes.
///
/// The certificate data.
+ /// Whether the ASN.1 library should be used to decode certificate blobs.
///
- public static X509Certificate2Collection ParseCertificateChainBlob(ReadOnlyMemory certificateData)
+ public static X509Certificate2Collection ParseCertificateChainBlob(ReadOnlyMemory certificateData, bool useAsnParser = false)
{
X509Certificate2Collection certificateChain = new X509Certificate2Collection();
// macOS X509Certificate2 constructor throws exception if a certchain is encoded
// use AsnParser on macOS to parse for byteblobs,
#if !NETFRAMEWORK
- bool useAsnParser = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
+ useAsnParser = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
#endif
int offset = 0;
int length = certificateData.Length;