- Notifications
You must be signed in to change notification settings - Fork 10.5k
Support querying TlsCipherSuite
on Http.Sys / IIS #63685
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this 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 indicatingHttpFeatureCacheTlsClientHello
, but this should be(HTTP_FEATURE_ID)15
forHttpFeatureQueryCipherInfo
to match the comment in the method call on line 247.
// Licensed to the .NET Foundation under one or more agreements.
TlsCipherSuite
on Http.Sys RequestTlsCipherSuite
on Http.Sys / IIS if (statusCode == NativeMethods.HR_OK) | ||
{ | ||
var cipherInfo = Marshal.PtrToStructure<SecPkgContext_CipherInfo>((IntPtr)pBuffer); | ||
return (TlsCipherSuite)cipherInfo.dwCipherSuite; |
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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
)
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added paranoid check :)
There was a problem hiding this 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).
i created an issue to see why cswin32 is outdated and does not define new types #63686. its a bug basically |
/backport to release/10.0 |
Started backporting to release/10.0: https://github.com/dotnet/aspnetcore/actions/runs/17923800853 |
Http.Sys
During obsoletion of
ITlsHandshake
members (see #59389), propertyTlsCipherSuite? 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 settingnull
(which fulfills theITlsHandshake
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