go - Golang X509 密钥对被忽略
问题描述
我们正在使用 Golang 与使用 HTTPS 的外部服务进行通信。当使用 cURL 尝试请求时,我们获得了成功。使用 Go 时,证书似乎被忽略,从外部服务产生 403。
我们无法发现 cURL 请求与 Golang 代码的任何差异。有人可以帮助我们找到不同之处吗?
cURL-request 为我们提供了正确的 JSON 响应。Go 代码给出:
2020/09/07 15:05:57 request error: perform request: api response: 403 Forbidden
工作 cURL 请求(用于调试目的的用户代理):
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"
产生 403 的 Golang 代码:(注意:文件ca.pem
,client.pem
(证书)并且client.key.pem
必须在同一目录中。运行脚本为go run catest.go --url "https://[redacted]/path/to/endpoint" --identifier [redacted]
)
package main
import (
"crypto/tls"
"crypto/x509"
"flag"
"fmt"
"io/ioutil"
"log"
"net/http"
)
func main() {
// Get URL to call.
url := flag.String("url", "", "URL to call")
identifier := flag.String("identifier", "", "the X-Identifier value")
flag.Parse()
if url == nil || identifier == nil || *url == "" || *identifier == "" {
log.Fatal("'url' and 'identifier' arguments must be provided")
}
// Set up certificates
caPEM, err := ioutil.ReadFile("ca.pem")
if err != nil {
log.Fatalf("unable to read 'ca.pem' in current directory: %v", err)
}
clientPEM, err := ioutil.ReadFile("client.pem")
if err != nil {
log.Fatalf("unable to read 'client.pem' in current directory: %v", err)
}
clientKeyPEM, err := ioutil.ReadFile("client.key.pem")
if err != nil {
log.Fatalf("unable to read 'client.key.pem' in current directory: %v", err)
}
// Make calls.
client, err := configureClient(caPEM, clientPEM, clientKeyPEM)
if err != nil {
log.Fatalf("unable to setup client: %v", err)
}
_, err = performRequest(client, *url, *identifier)
if err != nil {
log.Fatalf("request error: %v", err)
}
log.Printf("request successful")
}
func configureClient(caCertPEM, clientCertPEM, clientKeyPEM []byte) (*http.Client, error) {
// Load the CA certificate.
caCertPool, err := x509.SystemCertPool()
if err != nil {
return nil, fmt.Errorf("configure client: load cert pool: %w", err)
}
// Append root CA cert from parameter
ok := caCertPool.AppendCertsFromPEM(caCertPEM)
if !ok {
return nil, fmt.Errorf("configure client: could not append ca certificate")
}
// Load the client certificate.
clientCert, err := tls.X509KeyPair(clientCertPEM, clientKeyPEM)
if err != nil {
return nil, fmt.Errorf("configure client: load client certificate: %w", err)
}
// Setup HTTPS client.
tlsConfig := &tls.Config{
RootCAs: caCertPool,
Certificates: []tls.Certificate{clientCert},
Renegotiation: tls.RenegotiateOnceAsClient,
}
tlsConfig.BuildNameToCertificate()
transport := &http.Transport{TLSClientConfig: tlsConfig}
client := &http.Client{Transport: transport}
return client, nil
}
func performRequest(client *http.Client, u, identifier string) ([]byte, error) {
if client == nil {
return nil, fmt.Errorf("perform request: nil client")
}
// Prepare request
req, err := http.NewRequest(http.MethodGet, u, nil)
if err != nil {
return nil, fmt.Errorf("perform request: create GET request: %w", err)
}
// Add same headers as cURL.
req.Header.Add("Accept", "application/json; charset=utf-8")
req.Header.Add("User-Agent", "Apache-HttpClient/4.5.5 (Java/12.0.1)")
req.Header.Add("Accept-Encoding", "gzip, deflate")
req.Header.Add("Connection", "Keep-Alive")
req.Header.Add("X-Identifier", identifier)
// Send request
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("perform request: client do: %w", err)
}
defer resp.Body.Close()
switch resp.StatusCode {
case http.StatusOK:
break
case http.StatusUnauthorized:
return nil, fmt.Errorf("perform request: api response: unauthorized")
case http.StatusBadRequest:
return nil, fmt.Errorf("perform request: api response: bad request")
default:
return nil, fmt.Errorf("perform request: api response: %v", resp.Status)
}
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("perform request: read response body: %w", err)
}
return data, nil
}
解决方案
推荐阅读
- angularjs - 量角器中的 For 循环在该循环中的最后一个数字处给出错误“使用定位器找不到元素:By(css 选择器,span.ng-binding)”
- swift - 第一个 TableView 部分标题不滚动 Swift 4
- jsf - Primefaces 组件的属性值何时更新?
- c# - 为什么我的 cancelTokenSource 会抛出空对象异常?
- php - Symfony bundle - REST API 两种类型的身份验证
- rxjs - 用其他 Observable 替换已经有订阅者的 Observable
- html - CSS Flexbox:对齐具有不同宽度的弹性项目
- verilog - VVP开始模拟时如何修复无限运行时间?
- java - 使用spring bean xml初始化自定义内部对象
- python - 对值和百分比进行排序会导致不准确