2

我正在尝试设置一个http.ListenAndServeTLS()带有自签名证书的 https 服务器 (

<date> <time> http: TLS handshake error from <IP>: remote error: tls: bad certificate

我已经寻找解决方案并尝试了几个(在 中设置InsecureSkipVerify为 true TLSConfig,将我的证书添加到Certificates配置字段或使用自签名证书签署另一个证书并将后者附加到RootCAs),但没有解决问题(最后一个解决方案不出所料地将错误更改为unknown certificate authority)。

正如我所提到的,我很确定问题与我正在尝试收听的服务无关,所以在 Go 中设置服务器时一定有一些非常简单的东西我错过了。我的代码看起来像这样:

    rootCAs, _ := x509.SystemCertPool()
    if rootCAs == nil {
        rootCAs = x509.NewCertPool()
    }
    certs, _ := ioutil.ReadFile(CA_PATH)
    _ = rootCAs.AppendCertsFromPEM(certs);

    server := http.Server{
        Addr: "",
        Handler: nil,
        TLSConfig: &tls.Config{
            InsecureSkipVerify: true,
            Certificates: []tls.Certificate{ my_cert },
            RootCAs: rootCAs,
        },
    }
    fmt.Println(server.ListenAnsServeTLS(PEM_PATH, KEY_PATH))
4

2 回答 2

5

RFC2246中所述,握手协议建立 TLS 会话并协商客户端和服务器之间的安全权限。默认情况下,您的机器已经信任来自许多证书颁发机构的一组证书,例如:GoDaddyIdenTrustDigiCert等。当您是证书颁发机构(自签名证书方式)时,您需要向客户端提供证书,并且客户端需要信任该证书。所以你需要做的是:

openssl工具安装后,运行以下命令:

openssl req -new -subj "/C=US/ST=Utah/CN=localhost" -newkey rsa:2048 -nodes -keyout localhost.key -out localhost.csr

该命令会生成一个localhost.key文件,该文件是私钥,localhost.csr并且是包含公钥的证书签名请求 (CSR)。CN传入是最-subj重要的字段,因为某些浏览器(如 chrome)需要该信息。CN表示通用名称,它是您希望 SSL 保护的域名。然后,您需要生成证书文件:

openssl x509 -req -days 365 -in localhost.csr -signkey localhost.key -out localhost.crt

localhost.crt文件由上面的命令生成,它是由您自己的localhost.key私钥签名的自签名证书。该x509标志表明 SSL/TLS 证书的标准格式是X.509.

之后,您需要使用证书和密钥来为https自签名服务器提供服务:

log.Fatal(http.ListenAndServeTLS("8081", "localhost.crt","localhost.key", router))

在客户端,它信任服务器证书非常重要,而不是使用 curl 的-k参数,该参数将忽略 TLS 协议。如果您使用的是 linux 操作系统,请安装该ca-certificates软件包,然后将其复制localhost.crtca-certificates文件夹:

cp localhost.crt /usr/local/share/ca-certificates/localhost.crt

最后使用以下命令信任该证书:

update-ca-certificates

如果您使用的操作系统与 linux 不同,则可以按照以下步骤之一进行操作:Mac OsWindowsLinux。你会在这个github repo中找到一个完整的例子。

于 2020-12-24T00:20:36.280 回答
4

创建目录golangssl并进入

mkdir golangssl
cd golangssl

生成自签名密钥和证书(如果尚未安装,请安装 openssl)

openssl genrsa -out server.key 2048
openssl ecparam -genkey -name secp384r1 -out server.key
openssl req -new -x509 -sha256 -key server.key -out server.crt -days 3650

使用以下内容创建文件 server.go

package main

import (
    "log"
    "net/http"
)

func SecureServer(w http.ResponseWriter, req *http.Request) {
    w.Header().Set("Content-Type", "text/plain")
    w.Write([]byte("Secure Hello World.\n"))
}

func main() {
    http.HandleFunc("/secure", SecureServer)
    err := http.ListenAndServeTLS(":443", "server.crt", "server.key", nil)
    if err != nil {
            log.Fatal("ListenAndServe: ", err)
    }
 }

运行服务器(需要root权限,因为绑定了443端口)

sudo go run server.go

执行请求(-k用于忽略自签名证书)

 curl -k https://localhost/secure

输出应该是

 Secure Hello World.
于 2020-08-26T04:00:06.780 回答