带有 WinHttpHander() 的 gRPC “ArgumentException:路径中有非法字符。”
Posted
技术标签:
【中文标题】带有 WinHttpHander() 的 gRPC “ArgumentException:路径中有非法字符。”【英文标题】:gRPC with WinHttpHander() "ArgumentException: Illegal characters in path." 【发布时间】:2021-11-09 09:46:13 【问题描述】:我正在尝试使用 .NET 5.0 服务器和 .NET Framework 客户端启动并运行 HTTP2 服务器端流。使用框架客户端时,我必须根据 Microsoft 文档(https://docs.microsoft.com/en-us/aspnet/core/grpc/netstandard?view=aspnetcore-5.0)使用 WinHttpHander。 当使用带有 X509Certificate 的 WinHttpHandler 时,我总是得到同样的错误。该错误似乎仅在使用证书时出现,这似乎是 Http2 与 gRPC 所需要的。
ArgumentException:路径中有非法字符。
我尝试了几种添加证书的方法,使用 X509Certificate.Import、X509Certificate.CreateFromCertFile、X509Certificate.CreateFromSignedFile 和 X509Certificate.Add,它们都给了我同样的错误。
通过以下过程建立客户端连接(代码为 F#)
let cacert = File.ReadAllText(@"ca.crt");
let clientCert = File.ReadAllText(@"client.crt");
let clientkey = File.ReadAllText(@"client.key");
let X509Cert = X509Certificate.CreateFromSignedFile(clientCert)
let handler = new WinHttpHandler()
handler.ClientCertificates.Add(X509Cert) |> ignore
handler.ServerCertificateValidationCallback <- fun msg clientcert cacert e -> true
let httpclient = new HttpClient(handler)
let channelOptions = GrpcChannelOptions(HttpClient = httpclient)
let channel = GrpcChannel.ForAddress("https://127.0.0.1:5001",channelOptions)
let client = DeFactoGrpc.EventSubscriberService.EventSubscriberServiceClient(channel)
如果需要,服务器按照以下步骤制作(代码为 F#)
let cacert = File.ReadAllText(@"ca.crt");
let servercert = File.ReadAllText(@"server.crt");
let serverkey = File.ReadAllText(@"server.key");
let certificatePair = new KeyCertificatePair(servercert, serverkey);
let certList = new System.Collections.Generic.List<KeyCertificatePair>()
certList.Add(certificatePair)
let server = new Server()
server.Services.Add(EventSubscriberService.EventSubscriberServiceMethodBinder.BindService(new EventSubscriber()))
server.Ports.Add(new ServerPort("localhost", 5001,SslServerCredentials(certList,cacert,false)))
|> ignore
【问题讨论】:
【参考方案1】:您似乎将错误的值传递给X509Certificate.CreateFromSignedFile(String)
。这个静态方法接受一个字符串,表示
签名文件的路径,从中创建 X.509 证书。
但是,您传递的是文件client.crt
的内容:
let clientCert = File.ReadAllText(@"client.crt"); // Here clientCert contains the contents of client.crt
let X509Cert = X509Certificate.CreateFromSignedFile(clientCert)
除非文件client.crt
包含包含实际签名文件的文件的路径,否则这种用法是不正确的,并且是您的ArgumentException:路径中的非法字符的原因。相反,您应该只传递文件名:
let X509Cert = X509Certificate.CreateFromSignedFile(@"client.crt")
为了比较,constructor for SslServerCredentials
将代表的字符串作为其第二个参数
PEM 编码的客户端根证书用于验证客户端。
因此,您传入ca.crt
内容的服务器端代码看起来是正确的:
let cacert = File.ReadAllText(@"ca.crt"); // Here cacert contains the contents of ca.crt
server.Ports.Add(new ServerPort("localhost", 5001, SslServerCredentials(certList,cacert,false)))
在客户端,您对WinHttpHandler.ServerCertificate
的回调只返回true
。根据文档,
定义
获取或设置一个回调方法来验证服务器证书。此回调是 SSL 握手的一部分。
member this.ServerCertificateValidationCallback : Func<System.Net.Http.HttpRequestMessage, System.Security.Cryptography.X509Certificates.X509Certificate2, System.Security.Cryptography.X509Certificates.X509Chain, System.Net.Security.SslPolicyErrors, bool> with get, set
资产价值
如果服务器证书被认为有效并且应该发送请求,回调应该返回
true
。否则,返回false
。备注
默认值为
null
。如果此属性为null
,则使用标准知名证书颁发机构验证服务器证书。
所以看来你仍然需要实现这个方法(或者让它为空)。
(你根本没有展示你如何使用clientkey
。)
【讨论】:
以上是关于带有 WinHttpHander() 的 gRPC “ArgumentException:路径中有非法字符。”的主要内容,如果未能解决你的问题,请参考以下文章
部署 Rest + gRPC 服务器部署到带有入口的 k8s