Implementing HTTPS for Internal Web Services with Dynamic IPs and Automated Certificate Generation


4 views

When building presentation software that requires secure internal communication, we face three unique constraints:

  • Dynamic internal IPv4 addressing (typically in 192.168.0.x range)
  • Potential IPv6-only environments
  • No external certificate authority access (like Let's Encrypt)
  • Zero manual configuration requirements

The most reliable solution is programmatic certificate generation during installation. Here's how to implement it in C#:

using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

public X509Certificate2 CreateSelfSignedCertificate(string subjectName)
{
    using (RSA rsa = RSA.Create(2048))
    {
        CertificateRequest req = new CertificateRequest(
            $"CN={subjectName}",
            rsa,
            HashAlgorithmName.SHA256,
            RSASignaturePadding.Pkcs1);

        req.CertificateExtensions.Add(
            new X509KeyUsageExtension(
                X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.KeyEncipherment,
                false));

        req.CertificateExtensions.Add(
            new X509EnhancedKeyUsageExtension(
                new OidCollection { new Oid("1.3.6.1.5.5.7.3.1") },
                false));

        req.CertificateExtensions.Add(
            new X509BasicConstraintsExtension(false, false, 0, false));

        return req.CreateSelfSigned(
            DateTimeOffset.UtcNow.AddDays(-1),
            DateTimeOffset.UtcNow.AddYears(1));
    }
}

For HttpListener with PowerShell integration:

# PowerShell script to configure HTTPS binding
$cert = New-SelfSignedCertificate 
    -DnsName "internal-presentation.local" 
    -CertStoreLocation "cert:\LocalMachine\My" 
    -KeySpec KeyExchange 
    -KeyExportPolicy Exportable

$thumbprint = $cert.Thumbprint
$guid = [guid]::NewGuid().ToString("B")

netsh http add sslcert ipport=0.0.0.0:443 
    certhash=$thumbprint 
    appid=$guid

For IPv4/IPv6 agnostic operation:

// C# code to handle both IP versions
HttpListener listener = new HttpListener();
listener.Prefixes.Add("https://*:443/");
listener.Prefixes.Add("https://[::]:443/");

To avoid browser warnings without manual steps:

  1. Package the root CA with your installer
  2. Automate trust store installation
  3. Implement certificate pinning in your client code
// Certificate validation callback example
ServicePointManager.ServerCertificateValidationCallback += 
    (sender, cert, chain, errors) =>
    {
        // Implement your custom validation logic here
        return cert.Thumbprint == EXPECTED_THUMBPRINT;
    };
  • Set appropriate certificate expiration (1-2 years recommended)
  • Implement automatic certificate renewal logic
  • Include revocation checking for enterprise environments
  • Consider using CNG instead of RSA for better performance

When developing presentation software that handles sensitive data like authentication tokens, enabling HTTPS is non-negotiable. However, internal networks present unique challenges:

  • Dynamic IPv4 addresses (e.g., 192.168.0.x) and IPv6 configurations
  • No public DNS resolution for Let's Encrypt validation
  • Requirement for zero-touch deployment

For internal applications using HttpListener, self-signed certificates offer the most flexible approach. Here's how to implement this in C#:


using System;
using System.Net;
using System.Security.Cryptography.X509Certificates;

class HttpsServer
{
    static void Main()
    {
        var listener = new HttpListener();
        listener.Prefixes.Add("https://localhost:8443/");
        
        // Generate and install self-signed cert
        var cert = CreateSelfSignedCertificate();
        listener.Start();
        
        Console.WriteLine("HTTPS server running...");
        // Server logic here
    }

    static X509Certificate2 CreateSelfSignedCertificate()
    {
        var powershellScript = @"
            $cert = New-SelfSignedCertificate -DnsName 'localhost' -CertStoreLocation 'cert:\LocalMachine\My'
            Export-Certificate -Cert $cert -FilePath 'C:\temp\servercert.cer'
            Import-Certificate -FilePath 'C:\temp\servercert.cer' -CertStoreLocation 'Cert:\LocalMachine\Root'
            return $cert.Thumbprint
        ";
        
        // Execute PowerShell and retrieve thumbprint
        // Implementation omitted for brevity
        return new X509Certificate2(/* cert data */);
    }
}

For production environments, we need a fully automated solution. This PowerShell script handles certificate generation and binding:


# Generate self-signed certificate
$certParams = @{
    Subject = "CN=YourInternalServer"
    KeyAlgorithm = 'RSA'
    KeyLength = 2048
    NotBefore = Get-Date
    NotAfter = (Get-Date).AddYears(5)
    CertStoreLocation = 'Cert:\LocalMachine\My'
}
$cert = New-SelfSignedCertificate @certParams

# Export and import to Trusted Root
Export-Certificate -Cert $cert -FilePath "C:\Temp\InternalCert.cer"
Import-Certificate -FilePath "C:\Temp\InternalCert.cer" -CertStoreLocation 'Cert:\LocalMachine\Root'

# Configure HTTP.sys to use the certificate
netsh http add sslcert ipport=0.0.0.0:443 certhash=$($cert.Thumbprint) appid="{00112233-4455-6677-8899-AABBCCDDEEFF}"

For environments with dynamic internal IPs, consider these approaches:

  1. Use localhost binding with reverse proxy
  2. Implement internal DNS with static hostnames
  3. Leverage IPv6 link-local addresses which are more stable

Here's how to configure HttpListener for flexible addressing:


var listener = new HttpListener();
// Bind to all available addresses
listener.Prefixes.Add("https://+:443/");
listener.Prefixes.Add("https://[::]:443/"); // IPv6

While self-signed certificates solve the technical challenge, remember:

  • Distribute the root CA certificate to all client machines
  • Implement certificate pinning in your client software
  • Rotate certificates periodically (automate this process)

For enterprise environments, consider setting up an internal PKI rather than individual self-signed certs.