aspnetcore icon indicating copy to clipboard operation
aspnetcore copied to clipboard

TLS 1.3 negotiation fails with FIPS-enabled Ubuntu 22.04 server and Chromium based browsers

Open michaelwildvarian opened this issue 1 year ago • 0 comments

Is there an existing issue for this?

  • [X] I have searched the existing issues

Describe the bug

When Kestrel is running on a FIPS-enabled Ubuntu 22.04, TLS 1.3 negotiation fails for Chromium browsers and ERR_SSL_PROTOCOL_ERROR is displayed.

Scenarios tested:

  • Different clients against Kestrel server: Firefox, curl and OpenSSL s_client all work. Chrome and Chromium Edge fail.
  • Different servers against Chrome: OpenSSL s_server, nginx and Python https.server+ssl work. Kestrel fails.

Expected Behavior

Chromium based browsers should be able to establish a TLS 1.3 session with Kestrel servers running on FIPS-enabled Ubuntu 22.04.

Steps To Reproduce

  • Provision VM running Ubuntu 22.04
  • Obtain a free Ubuntu Pro token by registering a private account at https://ubuntu.com/pro
  • Enable FIPS on the VM:
    • sudo pro attach --no-auto-enable <token>
    • sudo pro enable fips-preview --assume-yes
    • sudo reboot
    • cat /proc/sys/crypto/fips_enabled <-- Ensure the output is 1
  • Install ssl-cert package:
    • sudo apt install ssl-cert
  • Install Chrome on the VM:
    • wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
    • sudo dpkg -i google-chrome-stable_current_amd64.deb
  • Install .NET 8 SDK on the VM:
    • wget https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb
    • sudo dpkg -i packages-microsoft-prod.deb
    • sudo apt update
    • sudo apt install dotnet-sdk-8.0
  • Configure a hostname and create a snakeoil certificate:
    • sudo bash -c 'echo some.host.internal > /etc/hostname
    • sudo bash -c 'echo "127.0.0.1 some.host.internal" >> /etc/hosts
    • sudo make-ssl-cert generate-default-snakeoil --force-overwrite
  • Create a ASP.NET Core webapi boilerplate application
    • mkdir app
    • cd app
    • dotnet new webapi -au None
  • Add the following configurations to appsetting.Development.json
    • Urls = https://127.0.0.1:4445
    • Kestrel:Certificates:Default:Path = /etc/ssl/certs/ssl-cert-snakeoil.pem
    • Kestrel:Certificates:Default:KeyPath = /etc/ssl/private/ssl-cert-snakeoil.key
    • Logging:LogLevel:Microsoft.AspeNetCore.HttpLogging.HttpLoggingMiddleware = Trace
    • Logging:LogLevel:Microsoft.AspeNetCore.Server.Kestrel = Trace
  • Start the application (with sudo for access to the certificates)
    • dotnet build
    • sudo dotnet run --no-build
  • Start the Chrome browser and navigate to https://some.host.internal:4445/weatherforecast. It should display the following: image
  • By forcing TLS 1.2 Chrome is able to connect:
    • Add Kestrel:EndpointDefaults:SslProtocols = [ "Tls12" ] to appsettings.Developmen.json
    • Restart the app
    • Reload the page in Chrome, accept the security risk of the self-signed certificate and Chrome should display the following: image
  • Observe that openssl s_server is able to successfully negotiate TLS 1.3 with Chrome:
    • sudo openssl s_server -key /etc/ssl/private/ssl-cert-snakeoil.key -cert /etc/ssl/certs/ssl-cert-snakeoil.pem -accept 4446 -www
    • Open https://some.host.internal:4446 in Chrome. It should display a successful TLS 1.3 connection (after accepting the self-signed certificate): image

Exceptions (if any)

dbug: Microsoft.Extensions.Hosting.Internal.Host[1]
      Hosting starting
dbug: Microsoft.AspNetCore.Server.Kestrel.Core.Internal.CertificatePathWatcher[4]
      Created directory watcher for '/etc/ssl/certs'.
dbug: Microsoft.AspNetCore.Server.Kestrel.Core.Internal.CertificatePathWatcher[5]
      Created file watcher for '/etc/ssl/certs/ssl-cert-snakeoil.pem'.
trce: Microsoft.AspNetCore.Server.Kestrel.Core.Internal.CertificatePathWatcher[11]
      Added observer to file watcher for '/etc/ssl/certs/ssl-cert-snakeoil.pem'.
trce: Microsoft.AspNetCore.Server.Kestrel.Core.Internal.CertificatePathWatcher[13]
      File '/etc/ssl/certs/ssl-cert-snakeoil.pem' now has 1 observers.
trce: Microsoft.AspNetCore.Server.Kestrel.Core.Internal.CertificatePathWatcher[14]
      Directory '/etc/ssl/certs' now has watchers on 1 files.
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: https://127.0.0.1:4445
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /home/vendor/dotnettest
dbug: Microsoft.Extensions.Hosting.Internal.Host[2]
      Hosting started

dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[39]
      Connection id "0HN1JEM94TIM8" accepted.
dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[1]
      Connection id "0HN1JEM94TIM8" started.
dbug: Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets[6]
      Connection id "0HN1JEM94TIM8" received FIN.
dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[39]
      Connection id "0HN1JEM94TIM9" accepted.
dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[1]
      Connection id "0HN1JEM94TIM9" started.
dbug: Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets[6]
      Connection id "0HN1JEM94TIM9" received FIN.
dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[39]
      Connection id "0HN1JEM94TIMA" accepted.
dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[1]
      Connection id "0HN1JEM94TIMA" started.
dbug: Microsoft.AspNetCore.Server.Kestrel.Https.Internal.HttpsConnectionMiddleware[1]
      Failed to authenticate HTTPS connection.
      System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception.
       ---> Interop+OpenSsl+SslException: SSL Handshake failed with OpenSSL error - SSL_ERROR_SSL.
       ---> Interop+Crypto+OpenSslCryptographicException: error:0A0000EB:SSL routines::no application protocol
         --- End of inner exception stack trace ---
         at Interop.OpenSsl.DoSslHandshake(SafeSslHandle context, ReadOnlySpan`1 input, Byte[]& sendBuf, Int32& sendCount)
         at System.Net.Security.SslStreamPal.HandshakeInternal(SafeDeleteSslContext& context, ReadOnlySpan`1 inputBuffer, Byte[]& outputBuffer, SslAuthenticationOptions sslAuthenticationOptions)
         --- End of inner exception stack trace ---
         at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](Boolean receiveFirst, Byte[] reAuthenticationData, CancellationToken cancellationToken)
         at Microsoft.AspNetCore.Server.Kestrel.Https.Internal.HttpsConnectionMiddleware.OnConnectionAsync(ConnectionContext context)
dbug: Microsoft.AspNetCore.Server.Kestrel.Https.Internal.HttpsConnectionMiddleware[1]
      Failed to authenticate HTTPS connection.
      System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception.
       ---> Interop+OpenSsl+SslException: SSL Handshake failed with OpenSSL error - SSL_ERROR_SSL.
       ---> Interop+Crypto+OpenSslCryptographicException: error:0A0000EB:SSL routines::no application protocol
         --- End of inner exception stack trace ---
         at Interop.OpenSsl.DoSslHandshake(SafeSslHandle context, ReadOnlySpan`1 input, Byte[]& sendBuf, Int32& sendCount)
         at System.Net.Security.SslStreamPal.HandshakeInternal(SafeDeleteSslContext& context, ReadOnlySpan`1 inputBuffer, Byte[]& outputBuffer, SslAuthenticationOptions sslAuthenticationOptions)
         --- End of inner exception stack trace ---
         at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](Boolean receiveFirst, Byte[] reAuthenticationData, CancellationToken cancellationToken)
         at Microsoft.AspNetCore.Server.Kestrel.Https.Internal.HttpsConnectionMiddleware.OnConnectionAsync(ConnectionContext context)
dbug: Microsoft.AspNetCore.Server.Kestrel.Https.Internal.HttpsConnectionMiddleware[1]
      Failed to authenticate HTTPS connection.
      System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception.
       ---> Interop+OpenSsl+SslException: SSL Handshake failed with OpenSSL error - SSL_ERROR_SSL.
       ---> Interop+Crypto+OpenSslCryptographicException: error:0A0000EB:SSL routines::no application protocol
         --- End of inner exception stack trace ---
         at Interop.OpenSsl.DoSslHandshake(SafeSslHandle context, ReadOnlySpan`1 input, Byte[]& sendBuf, Int32& sendCount)
         at System.Net.Security.SslStreamPal.HandshakeInternal(SafeDeleteSslContext& context, ReadOnlySpan`1 inputBuffer, Byte[]& outputBuffer, SslAuthenticationOptions sslAuthenticationOptions)
         --- End of inner exception stack trace ---
         at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](Boolean receiveFirst, Byte[] reAuthenticationData, CancellationToken cancellationToken)
         at Microsoft.AspNetCore.Server.Kestrel.Https.Internal.HttpsConnectionMiddleware.OnConnectionAsync(ConnectionContext context)
dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[2]
      Connection id "0HN1JEM94TIM8" stopped.
dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[2]
      Connection id "0HN1JEM94TIMA" stopped.
dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[2]
      Connection id "0HN1JEM94TIM9" stopped.
dbug: Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets[7]
      Connection id "0HN1JEM94TIMA" sending FIN because: "The Socket transport's send loop completed gracefully."
dbug: Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets[7]
      Connection id "0HN1JEM94TIM9" sending FIN because: "The Socket transport's send loop completed gracefully."
dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[39]
      Connection id "0HN1JEM94TIMB" accepted.
dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[1]
      Connection id "0HN1JEM94TIMB" started.
dbug: Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets[7]
      Connection id "0HN1JEM94TIM8" sending FIN because: "The Socket transport's send loop completed gracefully."
dbug: Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets[6]
      Connection id "0HN1JEM94TIMB" received FIN.
dbug: Microsoft.AspNetCore.Server.Kestrel.Https.Internal.HttpsConnectionMiddleware[1]
      Failed to authenticate HTTPS connection.
      System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception.
       ---> Interop+OpenSsl+SslException: SSL Handshake failed with OpenSSL error - SSL_ERROR_SSL.
       ---> Interop+Crypto+OpenSslCryptographicException: error:0A0000EB:SSL routines::no application protocol
         --- End of inner exception stack trace ---
         at Interop.OpenSsl.DoSslHandshake(SafeSslHandle context, ReadOnlySpan`1 input, Byte[]& sendBuf, Int32& sendCount)
         at System.Net.Security.SslStreamPal.HandshakeInternal(SafeDeleteSslContext& context, ReadOnlySpan`1 inputBuffer, Byte[]& outputBuffer, SslAuthenticationOptions sslAuthenticationOptions)
         --- End of inner exception stack trace ---
         at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](Boolean receiveFirst, Byte[] reAuthenticationData, CancellationToken cancellationToken)
         at Microsoft.AspNetCore.Server.Kestrel.Https.Internal.HttpsConnectionMiddleware.OnConnectionAsync(ConnectionContext context)
dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[2]
      Connection id "0HN1JEM94TIMB" stopped.
dbug: Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets[7]
      Connection id "0HN1JEM94TIMB" sending FIN because: "The Socket transport's send loop completed gracefully."

.NET Version

8.0.200

Anything else?

Output of dotnet --info:

.NET SDK:
 Version:           8.0.200
 Commit:            438cab6a9d
 Workload version:  8.0.200-manifests.cdf2cc8e

Runtime Environment:
 OS Name:     ubuntu
 OS Version:  22.04
 OS Platform: Linux
 RID:         linux-x64
 Base Path:   /usr/share/dotnet/sdk/8.0.200/

.NET workloads installed:
There are no installed workloads to display.

Host:
  Version:      8.0.2
  Architecture: x64
  Commit:       1381d5ebd2

.NET SDKs installed:
  8.0.200 [/usr/share/dotnet/sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 8.0.2 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 8.0.2 [/usr/share/dotnet/shared/Microsoft.NETCore.App]

Other architectures found:
  None

Environment variables:
  Not set

global.json file:
  Not found

Learn more:
  https://aka.ms/dotnet/info

Download .NET:
  https://aka.ms/dotnet/download

On request I can provide Wireshark captures via email.

michaelwildvarian avatar Feb 22 '24 07:02 michaelwildvarian