Skip to content

Fix xml signature verification and update to .net 9.0 #84

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

Merged
merged 10 commits into from
Feb 8, 2025
Merged
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
7 changes: 5 additions & 2 deletions .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,16 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: 8.x
dotnet-version: 9.x
- name: Restore dependencies
run: dotnet restore
working-directory: src
- name: Build
run: dotnet build --no-restore
working-directory: src
- name: Test
run: dotnet test --no-build **/*Tests.csproj
working-directory: src
- name: Restore dependencies
run: dotnet restore
working-directory: samples/1_SimpleSPWebApp
Expand All @@ -41,7 +44,7 @@ jobs:
- name: Update apt repo
run: sudo apt update
- name: Install dependencies
run: sudo apt install -y libxml2-dev libxmlsec1-dev libxmlsec1-openssl xmlsec1 python3-pip && pip install cryptography==38.0.4
run: sudo apt install -y libxml2-dev libxmlsec1-dev libxmlsec1-openssl xmlsec1 python3-pip
- name: Pip list
run: pip list
- name: Install spid-sp-test
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<CopyRefAssembliesToPublishDirectory>false</CopyRefAssembliesToPublishDirectory>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="8.0.5" />
<PackageReference Include="SPID.AspNetCore.Authentication" Version="3.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="9.0.1" />
<!--<PackageReference Include="SPID.AspNetCore.Authentication" Version="3.3.0" />-->
</ItemGroup>

<!--<ItemGroup>
<ItemGroup>
<Reference Include="SPID.AspNetCore.Authentication">
<HintPath>..\..\..\src\SPID.AspNetCore.Authentication\bin\Debug\net8.0\SPID.AspNetCore.Authentication.dll</HintPath>
<HintPath>..\..\..\src\SPID.AspNetCore.Authentication\bin\Debug\net9.0\SPID.AspNetCore.Authentication.dll</HintPath>
</Reference>
</ItemGroup>-->
</ItemGroup>

</Project>
Binary file not shown.
58 changes: 23 additions & 35 deletions src/SPID.AspNetCore.Authentication/Helpers/XmlHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using SPID.AspNetCore.Authentication.Resources;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography.Xml;
Expand Down Expand Up @@ -37,7 +38,7 @@

try
{
privateKey = certificate.PrivateKey;
privateKey = certificate.GetRSAPrivateKey();
}
catch (Exception ex)
{
Expand Down Expand Up @@ -75,37 +76,28 @@
/// <param name="signedDocument">The signed document.</param>
/// <param name="xmlMetadata">The XML metadata.</param>
/// <returns></returns>
internal static bool VerifySignature(XmlDocument signedDocument, IdentityProvider? identityProvider = null)

Check warning on line 79 in src/SPID.AspNetCore.Authentication/Helpers/XmlHelpers.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 79 in src/SPID.AspNetCore.Authentication/Helpers/XmlHelpers.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 79 in src/SPID.AspNetCore.Authentication/Helpers/XmlHelpers.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 79 in src/SPID.AspNetCore.Authentication/Helpers/XmlHelpers.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 79 in src/SPID.AspNetCore.Authentication/Helpers/XmlHelpers.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 79 in src/SPID.AspNetCore.Authentication/Helpers/XmlHelpers.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
{
BusinessValidation.Argument(signedDocument, string.Format(ErrorLocalization.ParameterCantNullOrEmpty, nameof(signedDocument)));

try
{
SignedXml signedXml = new SignedXml(signedDocument);
XmlNodeList signatureNodes = signedDocument.GetElementsByTagName("Signature", SignedXml.XmlDsigNamespaceUrl);

if (signatureNodes.Count == 0)
{
return false;
}

if (identityProvider is not null)
{
bool validated = false;
foreach (var certificate in identityProvider.X509SigningCertificates)
{
var publicMetadataCert = new X509Certificate2(Convert.FromBase64String(certificate));
XmlNodeList nodeList = (signedDocument.GetElementsByTagName("ds:Signature")?.Count > 1) ?
signedDocument.GetElementsByTagName("ds:Signature") :
(signedDocument.GetElementsByTagName("ns2:Signature")?.Count > 1) ?
signedDocument.GetElementsByTagName("ns2:Signature") :
signedDocument.GetElementsByTagName("Signature");
signedXml.LoadXml((XmlElement)nodeList[0]);
validated |= signedXml.CheckSignature(publicMetadataCert, true);
}
return validated;
return identityProvider.X509SigningCertificates
.Any(certificate => VerifyAllSignatures(signedDocument, signatureNodes, new X509Certificate2(Convert.FromBase64String(certificate))));
}
else
{
XmlNodeList nodeList = (signedDocument.GetElementsByTagName("ds:Signature")?.Count > 0) ?
signedDocument.GetElementsByTagName("ds:Signature") :
signedDocument.GetElementsByTagName("Signature");
signedXml.LoadXml((XmlElement)nodeList[0]);
return signedXml.CheckSignature();

return VerifyAllSignatures(signedDocument, signatureNodes);
}
}
catch (Exception)
Expand All @@ -114,27 +106,23 @@
}
}

private static readonly ConcurrentDictionary<Type, XmlSerializer> serializers = new ConcurrentDictionary<Type, XmlSerializer>();
/// <summary>
/// Serializes to XML document.
/// </summary>
/// <param name="o">The o.</param>
/// <returns></returns>
public static XmlDocument SerializeToXmlDoc(this object o)
private static bool VerifyAllSignatures(XmlDocument signedDocument, XmlNodeList signatureNodes, X509Certificate2? publicMetadataCert = null)

Check warning on line 109 in src/SPID.AspNetCore.Authentication/Helpers/XmlHelpers.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 109 in src/SPID.AspNetCore.Authentication/Helpers/XmlHelpers.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 109 in src/SPID.AspNetCore.Authentication/Helpers/XmlHelpers.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 109 in src/SPID.AspNetCore.Authentication/Helpers/XmlHelpers.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 109 in src/SPID.AspNetCore.Authentication/Helpers/XmlHelpers.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 109 in src/SPID.AspNetCore.Authentication/Helpers/XmlHelpers.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
{
XmlDocument doc = new XmlDocument() { PreserveWhitespace = true };

using XmlWriter writer = doc.CreateNavigator().AppendChild();
if (!serializers.ContainsKey(o.GetType()))
bool internalResult = true;
foreach (var signatureNode in signatureNodes)
{
var serializer = new XmlSerializer(o.GetType());
serializers.AddOrUpdate(o.GetType(), serializer, (key, value) => serializer);
SignedXml signedXml = new(signedDocument);
signedXml.LoadXml((XmlElement)signatureNode);
internalResult &= publicMetadataCert is null
? signedXml.CheckSignature()
: signedXml.CheckSignature(publicMetadataCert, true);
}
serializers[o.GetType()].Serialize(writer, o);

return doc;
return internalResult;
}

private static readonly ConcurrentDictionary<Type, XmlSerializer> serializers = new();

public static XmlElement SerializeInternalExtensionToXmlElement(object o, string namespacePrefix, string xmlNamespace)
{
XmlDocument doc = SerializeExtensionToXmlElementInternal(o, namespacePrefix, xmlNamespace);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0;net7.0;net6.0</TargetFrameworks>
<TargetFrameworks>net9.0;net8.0;net7.0;net6.0</TargetFrameworks>
<LangVersion>latest</LangVersion>
<Description>AspNetCore Remote Authenticator for SPID</Description>
<Authors>Daniele Giallonardo, Stefano Mostarda</Authors>
Expand All @@ -12,37 +12,49 @@
<PackageProjectUrl>https://github.com/italia/spid-aspnetcore</PackageProjectUrl>
<PackageIcon>spid-nuget.png</PackageIcon>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageVersion>3.3.0</PackageVersion>
<Version>3.3.0</Version>
<AssemblyVersion>3.3.0</AssemblyVersion>
<FileVersion>3.3.0</FileVersion>
<InformationalVersion>3.3.0</InformationalVersion>
<PackageVersion>3.4.0</PackageVersion>
<Version>3.4.0</Version>
<AssemblyVersion>3.4.0</AssemblyVersion>
<FileVersion>3.4.0</FileVersion>
<InformationalVersion>3.4.0</InformationalVersion>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryUrl>https://github.com/italia/spid-aspnetcore</RepositoryUrl>
</PropertyGroup>

<ItemGroup>
<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
<_Parameter1>SPID.AspNetCore.Authentication.Tests</_Parameter1>
</AssemblyAttribute>
</ItemGroup>

<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' or '$(TargetFramework)' == 'net7.0' or '$(TargetFramework)' == 'net6.0'">
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageReference Include="System.Security.Cryptography.Xml" Version="8.0.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net9.0' ">
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.1" />
<PackageReference Include="System.Security.Cryptography.Xml" Version="9.0.1" />
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.1" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' ">
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="8.0.4" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' ">
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="8.0.12" />
<PackageReference Include="System.Security.Cryptography.Xml" Version="8.0.2" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'net7.0' ">
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="7.0.12" />
</ItemGroup>
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="7.0.12" />
<PackageReference Include="System.Security.Cryptography.Xml" Version="8.0.2" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'net6.0' ">
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="6.0.21" />
</ItemGroup>
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="6.0.21" />
<PackageReference Include="System.Security.Cryptography.Xml" Version="8.0.2" />
</ItemGroup>

<ItemGroup>
<None Include="..\..\README.md" Pack="true" PackagePath="\" />
Expand Down
Loading