dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.

Home Page:https://docs.microsoft.com/dotnet/core/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

C# .NET Framework issue WinHttpException: Error 12175 calling WINHTTP_CALLBACK_STATUS_REQUEST_ERROR

p1x31 opened this issue · comments

Description

Hi! I was asked to copy the original issue from grpc repo in here.

I have implemented a simple gRPC client in C# .NET Framework (WinHttpHandler) and a gRPC server in Python3 (grpcio) for testing.

I'm getting this error with .net framework client and python server

Grpc.Core.RpcException
  HResult=0x80131500
  Message=Status(StatusCode="Internal", Detail="Error starting gRPC call. HttpRequestException: An error occurred while sending the request. WinHttpException: Error 12175 calling WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, 'A security error occurred'.", DebugException="System.Net.Http.HttpRequestException: An error occurred while sending the request.")
  Source=mscorlib
  StackTrace:
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Grpc.Net.Client.Internal.GrpcCall`2.<GetResponseHeadersCoreAsync>d__72.MoveNext()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Program.<<Main>$>d__0.MoveNext() in C:\Users\*\GrpcClientTest\GrpcClientTest\Program.cs:line 53

  This exception was originally thrown at this call stack:
    [External Code]

Inner Exception 1:
HttpRequestException: An error occurred while sending the request.

Inner Exception 2:
WinHttpException: Error 12175 calling WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, 'A security error occurred.

.net framework client to .net framework server works fine
.net 8 client to python server works fine

What did you do?

If possible, provide a recipe for reproducing the error. Try being specific and include code snippets if helpful.

following WinHttpHandler official example.

Make sure you include information that can help us debug (full error message, exception listing, stack trace, logs).

See TROUBLESHOOTING.md for how to diagnose problems better.

Anything else we should know about your project / environment?

Reproduction Steps

Client

using var channel = GrpcChannel.ForAddress("https://localhost:7215", new GrpcChannelOptions
{
    HttpHandler = new WinHttpHandler()
});

var client = new Greeter.GreeterClient(channel);
Console.Write("name: ");
var name = Console.ReadLine();
var reply = await client.SayHelloAsync(new HelloRequest { Name = name });
Console.WriteLine($"server: {reply.Message}");
Console.ReadKey();

Server:

"""The Python AsyncIO implementation of the GRPC greet.Greeter server."""

import asyncio
import logging

import grpc
import greet_pb2
import greet_pb2_grpc


class Greeter(greet_pb2_grpc.GreeterServicer):
    async def SayHello(
        self,
        request: greet_pb2.HelloRequest,
        context: grpc.aio.ServicerContext,
    ) -> greet_pb2.HelloReply:
        return greet_pb2.HelloReply(message="Hello, %s!" % request.name)


async def serve() -> None:
    server = grpc.aio.server()
    greet_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
    listen_addr = "[::]:7215"
    server.add_secure_port(listen_addr)
    logging.info("Starting server on %s", listen_addr)
    await server.start()
    await server.wait_for_termination()


if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO)
    asyncio.run(serve())
proto:
syntax = "proto3";

option csharp_namespace = "GrpcClientTest";

package greet;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply);
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings.
message HelloReply {
  string message = 1;
}

I have tried:

/*AppContext.SetSwitch(
 "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
*/

/*var httpHandler = new HttpClientHandler
{
    ServerCertificateCustomValidationCallback =
            HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
};
*/

Expected behavior

What did you expect to see?

a returned string value from my gRPC method call

Actual behavior

What did you see instead?

HttpRequestException

Regression?

works with .net 8 client
.net framework client to .net framework server works fine

Known Workarounds

No response

Configuration

What version of gRPC and what language are you using?

Grpc.Net.Client 2.62.0 C# .NET Framework 4.8.1

What operating system (Linux, Windows,...) and version?

Windows 11 Pro 23H2

What runtime / compiler are you using (e.g. .NET Core SDK version dotnet --info)

Visual Studio 2022 project; C# .NET Framework 4.8.1

c# greeter client example, python greeter server example

Other information

Please refer to:
grpc/grpc#36658
grpc/grpc#29659
grpc/grpc-dotnet#1733
grpc/grpc-dotnet#2439

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

.NET Framework is no longer in active development, we are unlikely to do any fixes there unless it is for a security vulnerability.

Does the problem reproduce with .NET Core?

Hi, @rzikm
No, it doesn't reproduce, .NET 8 client works fine with python server.
it says on the microsoft website :

gRPC client is fully supported on Windows 11 or later.

Isn't .NET Framework 4.8.1 continued to also be supported?
It might be a security vulnerability or TLS not properly configured.

Error 12175 calling WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, 'A security error occurred'.

Maybe there are some workarounds to mimic .NET Core behaviour?

Which http handler are you using for .NET Core?

WinHttpHandler is an external component provided by Windows. It's the default for .NET Framework, and also available for .NET Core. It would be surprising if WinHttpHandler behaves differently under .NET Framework and .NET Core.

"System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);

httpHandler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback =
HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
};

SocketsHttpHandler is the default handler in .NET Core. It's not available for .NET Framework.

HttpClientHandler is a facade that delegates to the default http handler. It doesn't has its own behavior and depends on underlying default implementation.

Isn't .NET Framework 4.8.1 continued to also be supported?

Only critical security fixes.

It might be a security vulnerability or TLS not properly configured.

TLS configuration would be something done at the target system, not in .NET source code.

Security vulnerabilities usually look differently than inability to connect to a server. Some examples would be making remote process crash or leak data, or ability to execute arbitrary code on remote machine. Such errors should also not be reported openly on GitHub.

According to the documentation at https://learn.microsoft.com/en-us/windows/win32/winhttp/error-messages, The error says that something went wrong when verifying the server certificate at TLS layer. What sort of certificate is it? If it is some locally generated (i.e. self-signed) by the GRPC server code not explicitly configured as trusted on the (client) machine, then this sounds like correct and expected behavior.

HttpClientHandler.DangerousAcceptAnyServerCertificateValidator not working may be due to some sequence of events received from http.sys not being handled properly (my guess only). Even if that was so, it would not be considered severe enough to warrant servicing .NET Framework.

If you could reproduce this using WinHttpHandler on .NET Core, then we would fix in for future .NET Core release. What would be useful for us would be the entire self-contained project which reproduces the issue (as a zip) so that we don't need to reverse-engineer it from description.

I find it weird that the error only reproduces on .NET Framework, since the underlying WinHttp logic should be more or less the same. We keep hitting similar issues in CI, see #69238. It would be nice to improve our diagnostics and provide more info about the underlying TLS issue by inspecting and logging lpvStatusInformation.

Regardless, I agree that this is not high priority for now, so triaging to Future.

@p1x31 it might be possible to troubleshoot this by capturing WinHttp traces:

- netsh trace start scenario=InternetClient_dbg capture=yes correlation=disabled report=disabled maxSize=1024
- <repro>
- netsh trace stop
- Inspect NetTrace.etl

Does it reveal anything interesting?

Hi @huoyaoyuan!

Which http handler are you using for .NET Core?

I was using the default SocketsHttpHandler so .NET Core client with python server or .NET Core server works as expected.

However when configuring WinHttpHandler on .NET Core client with python server I was able to reproduce this error
Therefore you are right that WinHttpHandler behaves in the same manner under both .NET Framework and .NET Core.

@rzikm sorry for confusing you, the problem doesn't reproduce with the default SocketsHttpHandler
here is the minimal reproducible example with .NET Core Client / python server:
link

I can confirm that the .NET Core Client to .NET Framework server works fine and backwards
.NET Framework Client to .NET Core Server also works fine

I'm guessing for now it might be python problem here

WinHttpHandler is indeed external. Its implementation does not belong to .NET. All we can do is providing suggestions to configure it, via .NET api or other ways.