mirror of
https://github.com/jakeswenson/BitBetter.git
synced 2026-06-04 02:23:39 +00:00
Update to .NET 10.0 and fix certificate validation for Bitwarden server 2026.5.0 (#282)
* Update to .NET 10.0 for Bitwarden server 2026.5.0 compatibility Bitwarden server 2026.5.0 ships with .NET 10.0 runtime only, breaking the fast-patch build. This commit updates all .NET projects and build pipelines to target net10.0 and the dotnet/sdk:10.0 image. Additionally: - Replace obsolete X509Certificate2(byte[]) constructors with X509CertificateLoader.LoadCertificate() / LoadPkcs12FromFile() to resolve SYSLIB0057 warnings introduced in .NET 9/10 - Add -certpbe AES-256-CBC -keypbe AES-256-CBC -macalg SHA256 to generate-keys.sh PKCS#12 export, fixing OpenSSL 3.x errors caused by the deprecated RC2-40-CBC legacy algorithm - Update FixRuntimeConfig fallback framework version to 10.0.0 Fixes #281 Signed-off-by: Pascal Pothmann <19438422+p0thi@users.noreply.github.com> * Fix certificate validation by replacing all thumbprint occurrences Bitwarden's LicensingService performs two validation checks: 1. Validates _creationCertificate thumbprint 2. Validates all certificates in _verificationCertificates The thumbprint constants are inlined at compile time, creating multiple Ldstr instructions in the IL code. The patcher was only replacing the first occurrence, causing the second validation to fail with: 'Invalid license verifying certificate.' This fix replaces ALL occurrences of the old thumbprint to ensure both validation checks pass. Fixes runtime error: 'Invalid license verifying certificate' --------- Signed-off-by: Pascal Pothmann <19438422+p0thi@users.noreply.github.com> Co-authored-by: Pascal Pothmann <19438422+p0thi@users.noreply.github.com>
This commit is contained in:
@@ -15,6 +15,6 @@ DIR=`exec 2>/dev/null;(cd -- "$DIR") && cd -- "$DIR"|| cd "$DIR"; unset PWD; /us
|
||||
# Generate new keys
|
||||
openssl req -x509 -newkey rsa:4096 -keyout "$DIR/key.pem" -out "$DIR/cert.cert" -days 36500 -subj '/CN=www.mydom.com/O=My Company Name LTD./C=US' -outform DER -passout pass:test
|
||||
openssl x509 -inform DER -in "$DIR/cert.cert" -out "$DIR/cert.pem"
|
||||
openssl pkcs12 -export -out "$DIR/cert.pfx" -inkey "$DIR/key.pem" -in "$DIR/cert.pem" -passin pass:test -passout pass:test
|
||||
openssl pkcs12 -export -out "$DIR/cert.pfx" -inkey "$DIR/key.pem" -in "$DIR/cert.pem" -passin pass:test -passout pass:test -certpbe AES-256-CBC -keypbe AES-256-CBC -macalg SHA256
|
||||
|
||||
ls
|
||||
|
||||
2
build.sh
2
build.sh
@@ -70,7 +70,7 @@ else
|
||||
docker run --rm \
|
||||
-v "$DIR/src/bitBetter:/bitBetter" \
|
||||
-w /bitBetter \
|
||||
mcr.microsoft.com/dotnet/sdk:8.0 sh build.sh
|
||||
mcr.microsoft.com/dotnet/sdk:10.0 sh build.sh
|
||||
|
||||
docker build \
|
||||
--no-cache \
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
ARG BITWARDEN_TAG
|
||||
FROM ${BITWARDEN_TAG}
|
||||
|
||||
COPY bin/Release/net8.0/publish/* /bitBetter/
|
||||
COPY bin/Release/net10.0/publish/* /bitBetter/
|
||||
COPY ./.keys/cert.cert /newLicensing.cer
|
||||
|
||||
RUN set -e; set -x; \
|
||||
|
||||
@@ -66,8 +66,8 @@ namespace BitwardenSelfLicensor
|
||||
module.Resources.Add(new EmbeddedResource("Bit.Core.licensing.cer", existingRes.Attributes, certBytes));
|
||||
module.Resources.Remove(existingRes);
|
||||
|
||||
var existingCert = new X509Certificate2(existingRes.GetResourceData());
|
||||
var newCert = new X509Certificate2(certBytes);
|
||||
var existingCert = X509CertificateLoader.LoadCertificate(existingRes.GetResourceData());
|
||||
var newCert = X509CertificateLoader.LoadCertificate(certBytes);
|
||||
Console.WriteLine($"Old thumbprint: {existingCert.Thumbprint}");
|
||||
Console.WriteLine($"New thumbprint: {newCert.Thumbprint}");
|
||||
|
||||
@@ -85,15 +85,22 @@ namespace BitwardenSelfLicensor
|
||||
|
||||
// Use Contains() to handle the hidden Unicode LRM character (\u200E) that Bitwarden
|
||||
// prepends to the production thumbprint string literal in LicensingService.cs
|
||||
var instToReplace = ctor.Body.Instructions
|
||||
// Replace ALL occurrences since const fields are inlined at compile time and used in
|
||||
// multiple validation checks (both _creationCertificate and _verificationCertificates)
|
||||
var instructionsToReplace = ctor.Body.Instructions
|
||||
.Where(i => i.OpCode == OpCodes.Ldstr)
|
||||
.FirstOrDefault(i => ((string)i.Operand)
|
||||
.Contains(existingCert.Thumbprint, StringComparison.OrdinalIgnoreCase));
|
||||
.Where(i => ((string)i.Operand)
|
||||
.Contains(existingCert.Thumbprint, StringComparison.OrdinalIgnoreCase))
|
||||
.ToList();
|
||||
|
||||
if (instToReplace != null)
|
||||
if (instructionsToReplace.Count > 0)
|
||||
{
|
||||
Console.WriteLine($"Replacing thumbprint Ldstr: '{instToReplace.Operand}'");
|
||||
rewriter.Replace(instToReplace, Instruction.Create(OpCodes.Ldstr, newCert.Thumbprint));
|
||||
Console.WriteLine($"Found {instructionsToReplace.Count} thumbprint Ldstr instruction(s) to replace");
|
||||
foreach (var inst in instructionsToReplace)
|
||||
{
|
||||
Console.WriteLine($" Replacing: '{inst.Operand}'");
|
||||
rewriter.Replace(inst, Instruction.Create(OpCodes.Ldstr, newCert.Thumbprint));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -121,7 +128,7 @@ namespace BitwardenSelfLicensor
|
||||
|
||||
// Derive framework name/version from the self-contained includedFrameworks before removing it
|
||||
string fwName = "Microsoft.AspNetCore.App";
|
||||
string fwVersion = "8.0.0";
|
||||
string fwVersion = "10.0.0";
|
||||
if (opts["includedFrameworks"] is JsonArray included && included.Count > 0)
|
||||
{
|
||||
var first = included[0]!.AsObject();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -4,4 +4,4 @@ set -e
|
||||
set -x
|
||||
|
||||
dotnet restore
|
||||
dotnet publish -c Release -o bin/Release/net8.0/publish
|
||||
dotnet publish -c Release -o bin/Release/net10.0/publish
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
|
||||
|
||||
WORKDIR /licenseGen
|
||||
|
||||
@@ -12,6 +12,6 @@ RUN set -e; set -x; \
|
||||
|
||||
FROM bitbetter/api
|
||||
|
||||
COPY --from=build /licenseGen/bin/Release/net8.0/publish/* /app/
|
||||
COPY --from=build /licenseGen/bin/Release/net10.0/publish/* /app/
|
||||
|
||||
ENTRYPOINT [ "dotnet", "/app/licenseGen.dll", "--core", "/app/Core.dll", "--executable", "/app/Api", "--cert", "/cert.pfx" ]
|
||||
|
||||
@@ -141,7 +141,7 @@ namespace BitwardenSelfLicensor
|
||||
buff = Console.ReadLine();
|
||||
if ( buff == "" || buff == "y" || buff == "Y" )
|
||||
{
|
||||
GenerateUserLicense(new X509Certificate2(cert.Value(), "test"), GetCoreDllPath(), name, email, storage, guid, null);
|
||||
GenerateUserLicense(X509CertificateLoader.LoadPkcs12FromFile(cert.Value(), "test"), GetCoreDllPath(), name, email, storage, guid, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -155,7 +155,7 @@ namespace BitwardenSelfLicensor
|
||||
buff = Console.ReadLine();
|
||||
if ( buff == "" || buff == "y" || buff == "Y" )
|
||||
{
|
||||
GenerateOrgLicense(new X509Certificate2(cert.Value(), "test"), GetCoreDllPath(), name, email, storage, installid, businessname, null);
|
||||
GenerateOrgLicense(X509CertificateLoader.LoadPkcs12FromFile(cert.Value(), "test"), GetCoreDllPath(), name, email, storage, installid, businessname, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -214,7 +214,7 @@ namespace BitwardenSelfLicensor
|
||||
storageShort = (short) parsedStorage;
|
||||
}
|
||||
|
||||
GenerateUserLicense(new X509Certificate2(cert.Value(), "test"), GetCoreDllPath(), name.Value, email.Value, storageShort, userId, key.Value);
|
||||
GenerateUserLicense(X509CertificateLoader.LoadPkcs12FromFile(cert.Value(), "test"), GetCoreDllPath(), name.Value, email.Value, storageShort, userId, key.Value);
|
||||
|
||||
return 0;
|
||||
});
|
||||
@@ -269,7 +269,7 @@ namespace BitwardenSelfLicensor
|
||||
storageShort = (short) parsedStorage;
|
||||
}
|
||||
|
||||
GenerateOrgLicense(new X509Certificate2(cert.Value(), "test"), GetCoreDllPath(), name.Value, email.Value, storageShort, installationId, businessName.Value, key.Value);
|
||||
GenerateOrgLicense(X509CertificateLoader.LoadPkcs12FromFile(cert.Value(), "test"), GetCoreDllPath(), name.Value, email.Value, storageShort, installationId, businessName.Value, key.Value);
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user