Basic implementation of SSL selfsigned certificates creation and renewal

Allows selfsigned certificates creation and renewal for local and external use. When enabled, will create a folder SSL\ and 2 sub folders SSL\ssl\ and SSL\src\. Next creates and store an RSA private key in SSL\src\ and the derived selfsigned certificates in SSL\ssl\ folder. Is also possible to renew the certificate on every server restart if CertRenewOnStartup is set to true.

Note: The SSL related params in the network section was adapted to be user friendly and allow the usage just by uncommenting the SSL params in both sections and a password change.
This commit is contained in:
Adil El Farissi
2024-03-20 01:12:49 +00:00
committed by UbitUmarov
parent e2b655a939
commit c2c3ca418a
5 changed files with 142 additions and 11 deletions

View File

@@ -308,7 +308,7 @@ namespace OpenSim.Framework.Servers.HttpServer
if(htype == UriHostNameType.Unknown || htype == UriHostNameType.Basic)
return false;
if(htype == UriHostNameType.Dns)
if(htype == UriHostNameType.Dns || htype == UriHostNameType.IPv4)
{
foreach(string name in m_certNames)
{

View File

@@ -56,6 +56,7 @@ using OpenMetaverse.StructuredData;
using Amib.Threading;
using System.Collections.Concurrent;
using System.Net.Http;
using System.Security.Cryptography.X509Certificates;
namespace OpenSim.Framework
{
@@ -1480,6 +1481,71 @@ namespace OpenSim.Framework
return streamReader.ReadToEnd();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CreateOrUpdateSelfsignedCert(string certFileName, string certHostName, string certHostIp, string certPassword)
{
CreateOrUpdateSelfsignedCertificate(certFileName, certHostName, certHostIp, certPassword);
}
/// <summary>
/// Create or renew an SSL selfsigned certificate using the parameters set in the startup section of OpenSim.ini
/// </summary>
/// <param name="certFileName">The certificate file name.</param>
/// <param name="certHostName">The certificate host DNS name (CN).</param>
/// <param name="certHostIp">The certificate host IP address.</param>
/// <param name="certPassword">The certificate password.</param>
private static void CreateOrUpdateSelfsignedCertificate(string certFileName, string certHostName, string certHostIp, string certPassword)
{
SubjectAlternativeNameBuilder san = new();
san.AddDnsName(certHostName);
san.AddIpAddress(IPAddress.Parse(certHostIp));
// What OpenSim check (CN).
X500DistinguishedName dn = new($"CN={certHostName}");
using (RSA rsa = RSA.Create(2048))
{
CertificateRequest request = new(dn, rsa, HashAlgorithmName.SHA256,RSASignaturePadding.Pkcs1);
// (Optional)...
request.CertificateExtensions.Add(
new X509KeyUsageExtension(X509KeyUsageFlags.DataEncipherment | X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature , false));
// (Optional) SSL Server Authentication...
request.CertificateExtensions.Add(
new X509EnhancedKeyUsageExtension(
new OidCollection { new Oid("1.3.6.1.5.5.7.3.1") }, false));
request.CertificateExtensions.Add(san.Build());
X509Certificate2 certificate = request.CreateSelfSigned(new DateTimeOffset(DateTime.UtcNow), new DateTimeOffset(DateTime.UtcNow.AddDays(3650)));
string privateKey = Convert.ToBase64String(rsa.ExportRSAPrivateKey(), Base64FormattingOptions.InsertLineBreaks);
// Create the SSL folder and sub folders if not exists.
if (!Directory.Exists("SSL\\src\\"))
Directory.CreateDirectory("SSL\\src\\");
if (!Directory.Exists("SSL\\ssl\\"))
Directory.CreateDirectory("SSL\\ssl\\");
// Store the RSA key in SSL\src\
File.WriteAllText($"SSL\\src\\{certFileName}.txt", privateKey);
// Export and store the .pfx and .p12 certificates in SSL\ssl\.
// Note: Pfx is a Pkcs12 certificate and both files work for OpenSim.
byte[] pfxCertBytes = string.IsNullOrEmpty(certPassword)
? certificate.Export(X509ContentType.Pfx)
: certificate.Export(X509ContentType.Pfx, certPassword);
File.WriteAllBytes($"SSL\\ssl\\{certFileName}.pfx", pfxCertBytes);
byte[] p12CertBytes = string.IsNullOrEmpty(certPassword)
? certificate.Export(X509ContentType.Pkcs12)
: certificate.Export(X509ContentType.Pkcs12, certPassword);
File.WriteAllBytes($"SSL\\ssl\\{certFileName}.p12", p12CertBytes);
}
}
public static int fast_distance2d(int x, int y)
{
x = Math.Abs(x);

View File

@@ -352,7 +352,22 @@ namespace OpenSim
IConfig startupConfig = Config.Configs["Startup"];
if (startupConfig == null || startupConfig.GetBoolean("JobEngineEnabled", true))
WorkManager.JobEngine.Start();
// Sure is not the right place for this but do the job...
// Must always be called before (all) / the HTTP servers starting for the Certs creation or renewals.
if(startupConfig.GetBoolean("EnbleSelfsignedCertSupport"))
{
if(!File.Exists("SSL\\ssl\\"+ startupConfig.GetString("CertFileName") +".p12") || startupConfig.GetBoolean("CertRenewOnStartup"))
{
Util.CreateOrUpdateSelfsignedCert(
string.IsNullOrEmpty(startupConfig.GetString("CertFileName")) ? "OpenSim" : startupConfig.GetString("CertFileName"),
string.IsNullOrEmpty(startupConfig.GetString("CertHostName")) ? "localhost" : startupConfig.GetString("CertHostName"),
string.IsNullOrEmpty(startupConfig.GetString("CertHostIp")) ? "127.0.0.1" : startupConfig.GetString("CertHostIp"),
string.IsNullOrEmpty(startupConfig.GetString("CertPassword")) ? string.Empty : startupConfig.GetString("CertPassword")
);
}
}
if(m_networkServersInfo.HttpUsesSSL)
{
m_httpServerSSL = true;