This commit is contained in:
Tamer Wahba 2026-05-05 18:20:17 +01:00 committed by GitHub
commit 046c6096fe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 51 additions and 10 deletions

View file

@ -0,0 +1,34 @@
using System;
using System.Linq;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
namespace NzbDrone.Common.Http
{
public class SslCertificateLoadException : Exception
{
public SslCertificateLoadException(string message)
: base(message)
{
}
}
public static class SslCertificateLoader
{
public static SslStreamCertificateContext LoadCertificateContext(string certPath, string certPassword)
{
var certificateCollection = new X509Certificate2Collection();
certificateCollection.Import(certPath, certPassword, X509KeyStorageFlags.DefaultKeySet);
var leafCert = certificateCollection.FirstOrDefault(c => c.HasPrivateKey);
if (leafCert == null)
{
throw new SslCertificateLoadException(
$"The SSL certificate file {certPath} does not contain a certificate with an associated private key");
}
return SslStreamCertificateContext.Create(leafCert, certificateCollection, offline: true);
}
}
}

View file

@ -2,9 +2,9 @@
using System.Collections.Generic;
using System.Data.SQLite;
using System.IO;
using System.Net.Security;
using System.Reflection;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using DryIoc;
using DryIoc.Microsoft.DependencyInjection;
@ -19,6 +19,7 @@
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Exceptions;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Common.Instrumentation;
using NzbDrone.Common.Instrumentation.Extensions;
using NzbDrone.Common.Options;
@ -192,7 +193,13 @@ public static IHostBuilder CreateConsoleHostBuilder(string[] args, StartupContex
{
options.ConfigureHttpsDefaults(configureOptions =>
{
configureOptions.ServerCertificate = ValidateSslCertificate(sslCertPath, sslCertPassword);
var sslContext = ValidateSslCertificate(sslCertPath, sslCertPassword);
configureOptions.ServerCertificate = sslContext.TargetCertificate;
configureOptions.OnAuthenticate = (context, authOptions) =>
{
authOptions.ServerCertificateContext = sslContext;
};
});
}
});
@ -272,13 +279,13 @@ private static string BuildUrl(string scheme, string bindAddress, int port)
return $"{scheme}://{bindAddress}:{port}";
}
private static X509Certificate2 ValidateSslCertificate(string cert, string password)
private static SslStreamCertificateContext ValidateSslCertificate(string cert, string password)
{
X509Certificate2 certificate;
SslStreamCertificateContext certificateContext;
try
{
certificate = new X509Certificate2(cert, password, X509KeyStorageFlags.DefaultKeySet);
certificateContext = SslCertificateLoader.LoadCertificateContext(cert, password);
}
catch (CryptographicException ex)
{
@ -291,7 +298,7 @@ private static X509Certificate2 ValidateSslCertificate(string cert, string passw
throw new RadarrStartupException(ex);
}
return certificate;
return certificateContext;
}
}
}

View file

@ -1,8 +1,8 @@
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System;
using FluentValidation;
using FluentValidation.Validators;
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Common.Instrumentation;
namespace Radarr.Api.V3.Config
@ -35,11 +35,11 @@ protected override bool IsValid(PropertyValidatorContext context)
try
{
new X509Certificate2(resource.SslCertPath, resource.SslCertPassword, X509KeyStorageFlags.DefaultKeySet);
SslCertificateLoader.LoadCertificateContext(resource.SslCertPath, resource.SslCertPassword);
return true;
}
catch (CryptographicException ex)
catch (Exception ex)
{
Logger.Debug(ex, "Invalid SSL certificate file or password. {0}", ex.Message);