Skip to content

Conversation

DeagleGross
Copy link
Member

@DeagleGross DeagleGross commented Sep 15, 2025

Http.Sys

During obsoletion of ITlsHandshake members (see #59389), property TlsCipherSuite? NegotiatedCipherSuite was never set for HTTP.SYS and IIS scenario.

I've tried to calculate TlsCipherSuite value out from already available HTTP_SSL_PROTOCOL_INFO, but it does not have enough fragments to restore that data correctly. (see #59426 (comment))

In current PR I am setting value using HttpAPI to query tls cipher suite info via http.sys HttpRequestPropertyTlsCipherInfo request property. If this request property is not supported or query failed, I am setting null (which fulfills the ITlsHandshake contract).

In case OS does not support querying this info, the workaround is to get values from the obsoleted members.

IIS

IIS has basically the same implementation (see IISHttpContext).

Relates #59426

@Copilot Copilot AI review requested due to automatic review settings September 15, 2025 15:49
@github-actions github-actions bot added the area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions label Sep 15, 2025
@DeagleGross DeagleGross self-assigned this Sep 15, 2025
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements support for querying TlsCipherSuite on HTTP.SYS requests to address the obsoletion of ITlsHandshake members. The implementation uses the HTTP.SYS API to query TLS cipher suite information when supported by the OS.

  • Adds native interop support for querying TLS cipher suite via HttpRequestPropertyTlsCipherInfo
  • Implements ITlsHandshakeFeature.NegotiatedCipherSuite property for HTTP.SYS scenarios
  • Provides fallback behavior returning null when the feature is not supported by the OS

Reviewed Changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
RequestContext.cs Adds GetTlsCipherSuite() method to query TLS cipher suite from HTTP.SYS API
RequestContext.Log.cs Adds logging for TLS cipher suite query errors
RequestContext.FeatureCollection.cs Implements ITlsHandshakeFeature.NegotiatedCipherSuite property
Request.cs Adds NegotiatedCipherSuite property and populates it during TLS handshake processing
SecPkgContext_CipherInfo.cs New native struct definition for TLS cipher suite information
HttpApi.cs Adds feature detection for TLS cipher suite querying capability
LoggerEventIds.cs Adds new event ID for TLS cipher suite query errors
Program.cs Updates sample to demonstrate the new cipher suite functionality
Comments suppressed due to low confidence (1)

src/Servers/HttpSys/src/NativeInterop/HttpApi.cs:1

  • The feature ID cast appears incorrect. Line 90 uses (HTTP_FEATURE_ID)11 with a comment indicating HttpFeatureCacheTlsClientHello, but this should be (HTTP_FEATURE_ID)15 for HttpFeatureQueryCipherInfo to match the comment in the method call on line 247.
// Licensed to the .NET Foundation under one or more agreements. 
@DeagleGross DeagleGross changed the title Support querying TlsCipherSuite on Http.Sys Request Support querying TlsCipherSuite on Http.Sys / IIS Sep 17, 2025
if (statusCode == NativeMethods.HR_OK)
{
var cipherInfo = Marshal.PtrToStructure<SecPkgContext_CipherInfo>((IntPtr)pBuffer);
return (TlsCipherSuite)cipherInfo.dwCipherSuite;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty sure you have tested it and it returned the expected result. But just to be sure, the .h file uses a DWORD for this property, so I would assume an uint in c#. It's mapped to an int right now and it's fine as it's the same size. However I am not sure about the cast from int to the TlsCipherSuite enum. Do you know if a memory representation of a "positive value" DWORD will be fine when represented as an int?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I asked Copilot and it told me both will be represented the same way below 2,147,483,647, so this is fine. (actual used max value is 53253 for TlsCipherSuite)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you are right, but I simply found this type definition in the dotnet/runtime: SecPkgContext_CipherInfo

where field is defined with int:
https://github.com/dotnet/runtime/blob/eeb1eae5038a82243d4675c37b6449cac4030207/src/libraries/Common/src/Interop/Windows/SChannel/SecPkgContext_CipherInfo.cs#L17

Now I think it should be uint, but probably does not matter below 2,147,483,647 value as you have already explained.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SChannel transfers it as a DWORD, but it's actually a ushort (it's only 2 bytes on the wire).

The .NET TlsCipherSuite enum is : ushort. So the cast is just as sketchy with uint as it is with int, though in reality they'll both always work.

If you wanted to be paranoid you could do it as a checked cast return checked((TlsCipherSuite)cipherInfo.dwCipherSuite);. That won't check if the enum value is defined (which is fine), but it will fail if it exceeds ushort.MaxValue (or if the interpreted dwCipherSuite value is negative).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added paranoid check :)

@DeagleGross
Copy link
Member Author

Was able to validate it for IIS - I've published NativeIISSample app to local IIS, bind the certificate and attached debugger to w3wp.exe. It correctly retrieved value via call to aspnetcorev2_inprocess.dll and shows a valid TlsCipherSuite value!

image

For http.sys I just ran a sample, which accesses ITlsHandshakeFeature and I got the value from calling http.api:
image

I think PR is ready to merge.

Copy link
Member

@bartonjs bartonjs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • I've never actually worked with either of these systems, so I don't have special knowledge.
  • I was actually surprised that the IIS copy was calling the same HttpQueryRequestProperty as the Http.Sys property, but I see prior art with client SNI.
  • The SecPkgContext_CipherInfo matches dotnet/runtime's copy, and matches the copy I see from the Win32 headers. (Allowing for the common "I don't need the high bit, so just say int instead of uint for DWORD" pattern)
  • Property 15 matches HttpFeatureQueryCipherInfo from the Win32 header.
  • I don't know why cswin32 doesn't define HttpFeatureQueryCipherInfo.
    • Which, to me, reinforces my usual "magic is bad"
  • I already commented on the unease I get from seeing two almost identical copies of the same thing. That just sets it up for one getting a fix that the other doesn't.

Seems legit to me, especially if you're seeing sensible answers from the tests (including manual testing).

@DeagleGross
Copy link
Member Author

DeagleGross commented Sep 18, 2025

why cswin32 doesn't define HttpFeatureQueryCipherInfo

i created an issue to see why cswin32 is outdated and does not define new types #63686. its a bug basically

@DeagleGross DeagleGross enabled auto-merge (squash) September 19, 2025 10:50
@DeagleGross DeagleGross merged commit 8ec4585 into main Sep 19, 2025
30 checks passed
@DeagleGross DeagleGross deleted the dmkorolev/cipherinfo branch September 19, 2025 11:23
@dotnet-policy-service dotnet-policy-service bot added this to the 11.0-preview1 milestone Sep 19, 2025
@DeagleGross
Copy link
Member Author

/backport to release/10.0

Copy link
Contributor

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions feature-httpsys

5 participants