忽略Golang X509密钥对

忽略Golang X509密钥对,go,ssl,Go,Ssl,我们正在使用Golang与使用HTTPS的外部服务进行通信。使用cURL尝试请求时,我们获得了成功。使用Go时,证书似乎被忽略,从外部服务生成403 我们无法发现cURL请求与Golang代码之间的任何差异。有人能帮我们找到不同吗 cURL请求为我们提供了一个正确的JSON响应。Go代码给出: 2020/09/07 15:05:57 request error: perform request: api response: 403 Forbidden 工作cURL请求(用于调试的用户代理):

我们正在使用Golang与使用HTTPS的外部服务进行通信。使用cURL尝试请求时,我们获得了成功。使用Go时,证书似乎被忽略,从外部服务生成403

我们无法发现cURL请求与Golang代码之间的任何差异。有人能帮我们找到不同吗

cURL请求为我们提供了一个正确的JSON响应。Go代码给出:

2020/09/07 15:05:57 request error: perform request: api response: 403 Forbidden
工作cURL请求(用于调试的用户代理):

Golang代码生成403: (注意:文件
ca.pem
client.pem
(cert)和
client.key.pem
必须位于同一目录中。运行脚本时应使用
go-run-catest.go--url“https://[redact]/path/to/endpoint”--标识符[redact]

主程序包
进口(
“加密/tls”
“加密/x509”
“旗帜”
“fmt”
“io/ioutil”
“日志”
“net/http”
)
func main(){
//获取要调用的URL。
url:=flag.String(“url”,“要调用的url”)
标识符:=flag.String(“标识符”、“X标识符值”)
flag.Parse()
如果url==nil | | identifier==nil | |*url==“”| |*identifier==“”{
致命(“'url'和'identifier'参数必须提供”)
}
//设立证书
caPEM,err:=ioutil.ReadFile(“ca.pem”)
如果错误!=零{
log.Fatalf(“无法读取当前目录中的'ca.pem',错误:%v”)
}
clientPEM,err:=ioutil.ReadFile(“client.pem”)
如果错误!=零{
log.Fatalf(“无法读取当前目录中的'client.pem',错误:%v”)
}
clientKeyPEM,err:=ioutil.ReadFile(“client.key.pem”)
如果错误!=零{
log.Fatalf(“无法读取当前目录:%v中的'client.key.pem',错误)
}
//打电话。
客户端,错误:=配置客户端(caPEM、clientPEM、clientKeyPEM)
如果错误!=零{
log.Fatalf(“无法设置客户端:%v”,错误)
}
_,err=performRequest(客户端,*url,*标识符)
如果错误!=零{
log.Fatalf(“请求错误:%v”,错误)
}
log.Printf(“请求成功”)
}
func configureClient(caCertPEM、clientCertPEM、clientKeyPEM[]字节)(*http.Client,错误){
//加载CA证书。
caCertPool,错误:=x509.SystemCertPool()
如果错误!=零{
返回nil,fmt.Errorf(“配置客户端:加载证书池:%w”,错误)
}
//从参数附加根CA证书
确定:=caCertPool.AppendCertsFromPEM(caCertPEM)
如果!好的{
返回nil,fmt.Errorf(“配置客户端:无法附加ca证书”)
}
//加载客户端证书。
clientCert,err:=tls.X509KeyPair(clientCertPEM,clientKeyPEM)
如果错误!=零{
返回nil,fmt.Errorf(“配置客户端:加载客户端证书:%w”,错误)
}
//安装HTTPS客户端。
tlsConfig:=&tls.Config{
RootCAs:caCertPool,
证书:[]tls.Certificate{clientCert},
重新协商:tls.RENEGATEONCEASCLIENT,
}
tlsConfig.BuildNameToCertificate()
传输:=&http.transport{TLSClientConfig:tlsConfig}
客户端:=&http.client{Transport:Transport}
返回客户端,无
}
func performRequest(客户端*http.client,u,标识符字符串)([]字节,错误){
如果客户端==nil{
返回nil,fmt.Errorf(“执行请求:nil客户端”)
}
//准备请求
req,err:=http.NewRequest(http.MethodGet,u,nil)
如果错误!=零{
返回nil,fmt.Errorf(“执行请求:创建获取请求:%w”,err)
}
//添加与cURL相同的标题。
req.Header.Add(“接受”,“应用程序/json;字符集=utf-8”)
添加(“用户代理”,“Apache HttpClient/4.5.5(Java/12.0.1)”)
添加(“接受编码”、“gzip、deflate”)
请求标题添加(“连接”,“保持活动”)
请求标题添加(“X标识符”,标识符)
//发送请求
resp,err:=client.Do(请求)
如果错误!=零{
返回nil,fmt.Errorf(“执行请求:客户端执行:%w”,err)
}
延迟响应主体关闭()
开关对应状态代码{
案例http.StatusOK:
打破
案例http.StatusUnauthorized:
返回nil,fmt.Errorf(“执行请求:api响应:未经授权”)
案例http.StatusBadRequest:
返回nil,fmt.Errorf(“执行请求:api响应:错误请求”)
违约:
返回nil,fmt.Errorf(“执行请求:api响应:%v”,响应状态)
}
数据,err:=ioutil.ReadAll(resp.Body)
如果错误!=零{
返回nil,fmt.Errorf(“执行请求:读取响应正文:%w”,错误)
}
返回数据,无
}

有几件事:1)你为什么打电话给
NameToCertificate
?2) 为什么要启用重新协商,这通常是非常糟糕的3)删减标题,除了
X-Identifier
4)将自定义CA证书添加到系统池之外,您可能不需要其他任何东西。你为什么不直接使用自定义CA?5) 检查有问题的API的文档,如果可能,链接到它们6)我假设没有错误7)响应状态说什么?可能是重新协商的问题,服务器或Go库有问题,但很难说。尝试设置
tls.Config.GetClientCertificate
回调,查看它是否被多次调用。您还可以尝试从中返回客户端证书(这不太可能有效,但您永远不知道)。另外,请参见我最初评论中的问题5)和问题6(已编辑)。还可以尝试使用
RenegotiateFreelyAsClient
进行重新协商。如果您可以访问服务器日志(听起来像是内部应用程序),这至少可以帮助您查看服务器端错误。除此之外,您还可以尝试检测标准库以记录更多详细信息。或者转储会话密钥并使用wireshark分析流量。还要确保你运行的是最新的Go版本。对不起,我没有。我在第一次评论中指出了所有稍微奇怪的事情,但这不太可能改变任何事情
curl -X GET --http1.1 -i -v --key client.key.pem --cacert ca.pem --cert client.pem "https://[redacted]/path/to/endpoint" -H "Accept: application/json; charset=utf-8" -H "User-Agent: Apache-HttpClient/4.5.5 (Java/12.0.1)" -H "X-Identifier: [redacted]" -H "Accept-Encoding: gzip, deflate" -H "Connection: Keep-Alive"