Skip to content

test: add fuzz testing setup for BOLT8 and BOLT11 #42

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

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
55 changes: 54 additions & 1 deletion NLightning.sln
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,22 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BlazorTests", "BlazorTests"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NLightning.Blazor.Tests", "test\BlazorTests\NLightning.Blazor.Tests\NLightning.Blazor.Tests.csproj", "{C0F21413-47D0-4584-84A5-B730909E7349}"
EndProject
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{29E3DE2A-9C25-4F48-8FCB-0BBAA9699662}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bolt11.Decoder.Blazor", "samples\Bolt11.Decoder.Blazor\Bolt11.Decoder.Blazor.csproj", "{D80680EA-8B09-44BA-A9EE-435C93D298B1}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Fuzztests", "Fuzztests", "{965A5904-F5EC-40EE-822C-3E6912640F80}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NLightning.Bolts.BOLT11", "NLightning.Bolts.BOLT11", "{79B6F41F-3E5A-4ABF-83A4-5860F9ADAC35}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InvoiceRoundTripFuzzer", "test\FuzzTests\NLightning.Bolts.BOLT11\InvoiceRoundTripFuzzer\InvoiceRoundTripFuzzer.csproj", "{201CF0D3-AA8A-40D3-843E-4382F9EDEABA}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NLightning.Bolts.BOLT8", "NLightning.Bolts.BOLT8", "{6BECD5C6-9978-41E1-BAC0-854E16F0D142}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ActOneFuzzer", "test\FuzzTests\NLightning.Bolts.BOLT8\ActOneFuzzer\ActOneFuzzer.csproj", "{A7C2075F-1C1E-4EE6-A2FE-D65EFBB2D662}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ActTwoFuzzer", "test\FuzzTests\NLightning.Bolts.BOLT8\ActTwoFuzzer\ActTwoFuzzer.csproj", "{8A99EB76-83DA-4E88-A7F8-265224F901D5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Release|Any CPU = Release|Any CPU
Expand Down Expand Up @@ -176,6 +187,42 @@ Global
{D80680EA-8B09-44BA-A9EE-435C93D298B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D80680EA-8B09-44BA-A9EE-435C93D298B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D80680EA-8B09-44BA-A9EE-435C93D298B1}.Release|Any CPU.Build.0 = Release|Any CPU
{201CF0D3-AA8A-40D3-843E-4382F9EDEABA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{201CF0D3-AA8A-40D3-843E-4382F9EDEABA}.Release|Any CPU.Build.0 = Release|Any CPU
{201CF0D3-AA8A-40D3-843E-4382F9EDEABA}.Release.Native|Any CPU.ActiveCfg = Debug|Any CPU
{201CF0D3-AA8A-40D3-843E-4382F9EDEABA}.Release.Native|Any CPU.Build.0 = Debug|Any CPU
{201CF0D3-AA8A-40D3-843E-4382F9EDEABA}.Release.Wasm|Any CPU.ActiveCfg = Debug|Any CPU
{201CF0D3-AA8A-40D3-843E-4382F9EDEABA}.Release.Wasm|Any CPU.Build.0 = Debug|Any CPU
{201CF0D3-AA8A-40D3-843E-4382F9EDEABA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{201CF0D3-AA8A-40D3-843E-4382F9EDEABA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{201CF0D3-AA8A-40D3-843E-4382F9EDEABA}.Debug.Native|Any CPU.ActiveCfg = Debug|Any CPU
{201CF0D3-AA8A-40D3-843E-4382F9EDEABA}.Debug.Native|Any CPU.Build.0 = Debug|Any CPU
{201CF0D3-AA8A-40D3-843E-4382F9EDEABA}.Debug.Wasm|Any CPU.ActiveCfg = Debug|Any CPU
{201CF0D3-AA8A-40D3-843E-4382F9EDEABA}.Debug.Wasm|Any CPU.Build.0 = Debug|Any CPU
{A7C2075F-1C1E-4EE6-A2FE-D65EFBB2D662}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A7C2075F-1C1E-4EE6-A2FE-D65EFBB2D662}.Release|Any CPU.Build.0 = Release|Any CPU
{A7C2075F-1C1E-4EE6-A2FE-D65EFBB2D662}.Release.Native|Any CPU.ActiveCfg = Debug|Any CPU
{A7C2075F-1C1E-4EE6-A2FE-D65EFBB2D662}.Release.Native|Any CPU.Build.0 = Debug|Any CPU
{A7C2075F-1C1E-4EE6-A2FE-D65EFBB2D662}.Release.Wasm|Any CPU.ActiveCfg = Debug|Any CPU
{A7C2075F-1C1E-4EE6-A2FE-D65EFBB2D662}.Release.Wasm|Any CPU.Build.0 = Debug|Any CPU
{A7C2075F-1C1E-4EE6-A2FE-D65EFBB2D662}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A7C2075F-1C1E-4EE6-A2FE-D65EFBB2D662}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A7C2075F-1C1E-4EE6-A2FE-D65EFBB2D662}.Debug.Native|Any CPU.ActiveCfg = Debug|Any CPU
{A7C2075F-1C1E-4EE6-A2FE-D65EFBB2D662}.Debug.Native|Any CPU.Build.0 = Debug|Any CPU
{A7C2075F-1C1E-4EE6-A2FE-D65EFBB2D662}.Debug.Wasm|Any CPU.ActiveCfg = Debug|Any CPU
{A7C2075F-1C1E-4EE6-A2FE-D65EFBB2D662}.Debug.Wasm|Any CPU.Build.0 = Debug|Any CPU
{8A99EB76-83DA-4E88-A7F8-265224F901D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8A99EB76-83DA-4E88-A7F8-265224F901D5}.Release|Any CPU.Build.0 = Release|Any CPU
{8A99EB76-83DA-4E88-A7F8-265224F901D5}.Release.Native|Any CPU.ActiveCfg = Debug|Any CPU
{8A99EB76-83DA-4E88-A7F8-265224F901D5}.Release.Native|Any CPU.Build.0 = Debug|Any CPU
{8A99EB76-83DA-4E88-A7F8-265224F901D5}.Release.Wasm|Any CPU.ActiveCfg = Debug|Any CPU
{8A99EB76-83DA-4E88-A7F8-265224F901D5}.Release.Wasm|Any CPU.Build.0 = Debug|Any CPU
{8A99EB76-83DA-4E88-A7F8-265224F901D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8A99EB76-83DA-4E88-A7F8-265224F901D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8A99EB76-83DA-4E88-A7F8-265224F901D5}.Debug.Native|Any CPU.ActiveCfg = Debug|Any CPU
{8A99EB76-83DA-4E88-A7F8-265224F901D5}.Debug.Native|Any CPU.Build.0 = Debug|Any CPU
{8A99EB76-83DA-4E88-A7F8-265224F901D5}.Debug.Wasm|Any CPU.ActiveCfg = Debug|Any CPU
{8A99EB76-83DA-4E88-A7F8-265224F901D5}.Debug.Wasm|Any CPU.Build.0 = Debug|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -198,5 +245,11 @@ Global
{99E240CC-6381-40DF-B784-528D2EDBBDFC} = {6F76E9AF-7E6D-42D8-918A-4C5B26BE07C1}
{C0F21413-47D0-4584-84A5-B730909E7349} = {6F76E9AF-7E6D-42D8-918A-4C5B26BE07C1}
{D80680EA-8B09-44BA-A9EE-435C93D298B1} = {29E3DE2A-9C25-4F48-8FCB-0BBAA9699662}
{965A5904-F5EC-40EE-822C-3E6912640F80} = {AF4411D4-8EE9-423E-8213-1C9D35E47882}
{79B6F41F-3E5A-4ABF-83A4-5860F9ADAC35} = {965A5904-F5EC-40EE-822C-3E6912640F80}
{201CF0D3-AA8A-40D3-843E-4382F9EDEABA} = {79B6F41F-3E5A-4ABF-83A4-5860F9ADAC35}
{6BECD5C6-9978-41E1-BAC0-854E16F0D142} = {965A5904-F5EC-40EE-822C-3E6912640F80}
{A7C2075F-1C1E-4EE6-A2FE-D65EFBB2D662} = {6BECD5C6-9978-41E1-BAC0-854E16F0D142}
{8A99EB76-83DA-4E88-A7F8-265224F901D5} = {6BECD5C6-9978-41E1-BAC0-854E16F0D142}
EndGlobalSection
EndGlobal
4 changes: 3 additions & 1 deletion src/NLightning.Bolts/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("NLightning.Bolts.Tests")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
[assembly: InternalsVisibleTo("ActOneFuzzer")]
[assembly: InternalsVisibleTo("ActTwoFuzzer")]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="SharpFuzz" Version="2.2.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\..\src\NLightning.Bolts\NLightning.Bolts.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using NLightning.Bolts.BOLT11;
using NLightning.Bolts.Exceptions;
using SharpFuzz;

namespace InvoiceRoundTripFuzzer;

internal abstract class InvoiceRoundTripFuzzer
{
private static void Main()
{
Fuzzer.OutOfProcess.Run(stream =>
{
//pwsh ../../fuzz.ps1 InvoiceRoundTripFuzzer.csproj -i Testcases
try
{
using var reader = new StreamReader(stream);

var invoiceData = reader.ReadToEnd();

var invoice = Invoice.Decode(invoiceData);

var encodedInvoice = invoice.Encode();

if (!invoiceData.Equals(encodedInvoice, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("Invoice mismatch");
}

}
catch (InvoiceSerializationException) { }
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
lnbc2500n1p0j5lkpp5ujnc3jk8zzxy8ycqzrfpp5f8n5x2c7csthrunm8lzw29tuk3l8qprn5h63qsp5u3u7t
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="SharpFuzz" Version="2.2.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\..\src\NLightning.Bolts\NLightning.Bolts.csproj" />
<ProjectReference Include="..\..\..\NLightning.Bolts.Tests\NLightning.Bolts.Tests.csproj" />
</ItemGroup>

</Project>
40 changes: 40 additions & 0 deletions test/FuzzTests/NLightning.Bolts.BOLT8/ActOneFuzzer/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System.Security.Cryptography;
using NLightning.Bolts.BOLT8.Constants;
using NLightning.Bolts.BOLT8.States;
using NLightning.Bolts.Tests.BOLT8.Mock;
using NLightning.Bolts.Tests.BOLT8.Utils;
using SharpFuzz;

namespace ActOneFuzzer;

internal abstract class ActOneFuzzer
{
private static void Main()
{
Fuzzer.OutOfProcess.Run(stream =>
{
//pwsh ../../fuzz.ps1 ActOneFuzzer.csproj -i Testcases
try
{
using var memory = new MemoryStream();
stream.CopyTo(memory);
var data = memory.ToArray().AsSpan();

var responder = new HandshakeState(
false,
ResponderValidKeysUtil.LocalStaticPrivateKey,
ResponderValidKeysUtil.LocalStaticPublicKey,
new FakeFixedKeyDh(ResponderValidKeysUtil.EphemeralPrivateKey)
);

var buffer = new byte[ProtocolConstants.MAX_MESSAGE_LENGTH];
responder.ReadMessage(data, buffer);
}
catch (ObjectDisposedException) { }
catch (InvalidOperationException) { }
catch (ArgumentException) { }
catch (CryptographicException) { }
catch (FormatException) { } //Crash found: System.FormatException: Invalid public key at NBitcoin.PubKey..ctor(ReadOnlySpan`1 bytes)
});
}
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="SharpFuzz" Version="2.2.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\..\src\NLightning.Bolts\NLightning.Bolts.csproj" />
<ProjectReference Include="..\..\..\NLightning.Bolts.Tests\NLightning.Bolts.Tests.csproj" />
</ItemGroup>

</Project>
45 changes: 45 additions & 0 deletions test/FuzzTests/NLightning.Bolts.BOLT8/ActTwoFuzzer/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System.Security.Cryptography;
using System.Text;
using NLightning.Bolts.BOLT8.Constants;
using NLightning.Bolts.BOLT8.States;
using NLightning.Bolts.Tests.BOLT8.Mock;
using NLightning.Bolts.Tests.BOLT8.Utils;
using SharpFuzz;

namespace ActTwoFuzzer;

internal abstract class ActTwoFuzzer
{
private static void Main()
{
Fuzzer.OutOfProcess.Run(stream =>
{
//pwsh ../../fuzz.ps1 ActTwoFuzzer.csproj -i Testcases
try
{
using var memory = new MemoryStream();
stream.CopyTo(memory);
var data = memory.ToArray().AsSpan();

var initiator = new HandshakeState(
true,
InitiatorValidKeysUtil.LocalStaticPrivateKey,
InitiatorValidKeysUtil.RemoteStaticPublicKey,
new FakeFixedKeyDh(InitiatorValidKeysUtil.EphemeralPrivateKey)
);

var buffer = new byte[ProtocolConstants.MAX_MESSAGE_LENGTH];

initiator.WriteMessage(Encoding.ASCII.GetBytes(string.Empty), buffer);

initiator.ReadMessage(data, buffer);
}
catch (ObjectDisposedException) { }
catch (InvalidOperationException) { }
catch (ArgumentException) { }
catch (CryptographicException) { }
catch (FormatException) { } //Crash found: System.FormatException: Invalid public key at NBitcoin.PubKey..ctor(ReadOnlySpan`1 bytes)

});
}
}
Binary file not shown.
63 changes: 63 additions & 0 deletions test/FuzzTests/fuzz.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
param (
[Parameter(Mandatory = $true)]
[string]$project,
[Parameter(Mandatory = $true)]
[string]$i,
[string]$x = $null,
[int]$t = 10000,
[string]$command = "sharpfuzz"
)

Set-StrictMode -Version Latest

$outputDir = "bin"
$findingsDir = "findings"

if (Test-Path $outputDir) {
Remove-Item -Recurse -Force $outputDir
}

if (Test-Path $findingsDir) {
Remove-Item -Recurse -Force $findingsDir
}

dotnet publish $project -c release -o $outputDir

$projectName = (Get-Item $project).BaseName
$projectDll = "$projectName.dll"
$project = Join-Path $outputDir $projectDll

$exclusions = @(
"dnlib.dll",
"SharpFuzz.dll",
"SharpFuzz.Common.dll",
$projectDll
)

$fuzzingTargets = Get-ChildItem $outputDir -Filter *.dll `
| Where-Object { $_.Name -notin $exclusions } `
| Where-Object { $_.Name -notlike "System.*.dll" }

if (($fuzzingTargets | Measure-Object).Count -eq 0) {
Write-Error "No fuzzing targets found"
exit 1
}

foreach ($fuzzingTarget in $fuzzingTargets) {
Write-Output "Instrumenting $fuzzingTarget"
& $command $fuzzingTarget

if ($LastExitCode -ne 0) {
Write-Error "An error occurred while instrumenting $fuzzingTarget"
exit 1
}
}

$env:AFL_SKIP_BIN_CHECK = 1

if ($x) {
afl-fuzz -i $i -o $findingsDir -t $t -m none -x $x dotnet $project
}
else {
afl-fuzz -i $i -o $findingsDir -t $t -m none dotnet $project
}
17 changes: 17 additions & 0 deletions test/FuzzTests/install-fuzz-tools.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/sh
set -eux

# Download and extract the latest afl-fuzz source package
wget http://lcamtuf.coredump.cx/afl/releases/afl-latest.tgz
tar -xvf afl-latest.tgz

rm afl-latest.tgz
cd afl-2.52b/

# Install afl-fuzz
sudo make install
cd ..
rm -rf afl-2.52b/

# Install SharpFuzz.CommandLine global .NET tool
dotnet tool install --global SharpFuzz.CommandLine
4 changes: 3 additions & 1 deletion test/NLightning.Bolts.Tests/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
[assembly: InternalsVisibleTo("ActOneFuzzer")]
[assembly: InternalsVisibleTo("ActTwoFuzzer")]
Loading