带有证书、私钥和密码短语的 TLS
TLS with Certificate, Private Key and Pass Phrase
我正在与为我提供证书的银行服务器集成。我从证书中创建了一个 pem
文件,所以现在我在 pem
文件中有了证书、私钥和密钥的密码短语。
新生成的文件pem
正在使用 OpenSSL 命令建立 SSL 连接,如下所示:
openssl s_client -connect host:port -key key.pem -cert cert.pem
此命令要求输入密码,我可以连接。但是我无法使用我的 Go 代码连接到相同的代码,它看起来像这样:
package main
import (
"crypto/tls"
"crypto/x509"
"fmt"
"net/http"
)
func main() {
caCert := []byte(`certs pem data`) // this contains both private key and certificates
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
// Setup HTTPS client
tlsConfig := &tls.Config{
RootCAs: caCertPool,
InsecureSkipVerify: true,
}
tlsConfig.BuildNameToCertificate()
transport := &http.Transport{TLSClientConfig: tlsConfig}
client := &http.Client{Transport: transport}
httpRequest, _ := http.NewRequest("GET", "https://test.com", nil)
resp, err := client.Do(httpRequest)
fmt.Printf("resp: [%v] \n Error: [%v]", resp, err)
}
我也不确定在我的 HTTP 请求中在哪里添加密码。
我得到的错误:remote error: tls: bad certificate
您似乎混淆了证书颁发机构和客户端证书。客户端证书向服务器证明你就是你所说的那个人(很像用户名和密码),并且使用 CA 以便你知道你正在与正确的服务器对话。
从适用于您的 openssl 命令来看,您的银行给了您一个客户端证书和密钥(尽管这非常不常用;除了您自己,没有人应该持有您的私钥,尤其是密码)。
The tls.Config.Certificates
field,如果被客户端使用,用于配置客户端证书。
Certificates contains one or more certificate chains to present to the other side of the connection. [...] Clients doing client-authentication may set either Certificates or GetClientCertificate.
TLS 证书通常加载 tls.LoadX509KeyPair or tls.X509KeyPair。但是,这些函数并不直接支持加密密钥。
相反,您必须自己加载密钥,使用 x509.DecryptPEMBlock 解密它,然后您可以使用 tls.X509KeyPair。
以下示例使用 EC 密钥,因为它的编码很短,但它与 RSA 密钥的工作原理相同。
package main
import (
"crypto/tls"
"crypto/x509"
"encoding/pem"
"fmt"
"log"
"net/http"
)
var bundle = []byte(`
-----BEGIN EC PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,99586A658F5D2DAC4A8A3CA387CF71CE
25EtKb7ycOI/5R47fYwpiaNERgYnCxCtcrMXJuOgueuxUXjiU0n93hpUpIQqaTLH
dDKhsR1UHvGJVTV4h577RQ+nEJ5z8K5Y9NWFqzfa/Q5SY43kqqoJ/fS/OCnTmH48
z4bL/dJBDE/a5HwJINgqQhGi9iUkCWUiPQxriJQ0i2s=
-----END EC PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIB2TCCAX+gAwIBAgIUUTZvgwwnbC05WHgIHMXxrbZzr6wwCgYIKoZIzj0EAwIw
QjELMAkGA1UEBhMCWFgxFTATBgNVBAcMDERlZmF1bHQgQ2l0eTEcMBoGA1UECgwT
RGVmYXVsdCBDb21wYW55IEx0ZDAeFw0xOTA1MTQxMzAwMDJaFw0xOTA1MTUxMzAw
MDJaMEIxCzAJBgNVBAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNV
BAoME0RlZmF1bHQgQ29tcGFueSBMdGQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC
AAScgLGx6SXchEo/s0X3AoF0mQkh3bGf9QY0s/2dPqf3/9irwz35DiDGoaP+FDZv
HnUX+D3tUEPhxkLyzWKKT9HHo1MwUTAdBgNVHQ4EFgQU3eB8oRcmvzZrx9Dkb6ma
MMtu1MkwHwYDVR0jBBgwFoAU3eB8oRcmvzZrx9Dkb6maMMtu1MkwDwYDVR0TAQH/
BAUwAwEB/zAKBggqhkjOPQQDAgNIADBFAiAvw/FqAmGbSlBklp6AHJy9kf9VPyhe
RA93ccNQ+7m1fAIhAOXr8c2QsH2oOYRTbn6bPZjkYQ2jLMaxatKhChBIuyZA
-----END CERTIFICATE-----
`)
func main() {
keyBlock, certsPEM := pem.Decode(bundle)
fmt.Println(x509.IsEncryptedPEMBlock(keyBlock)) // Output: true
// Decrypt key
keyDER, err := x509.DecryptPEMBlock(keyBlock, []byte("foobar"))
if err != nil {
log.Fatal(err)
}
// Update keyBlock with the plaintext bytes and clear the now obsolete
// headers.
keyBlock.Bytes = keyDER
keyBlock.Headers = nil
// Turn the key back into PEM format so we can leverage tls.X509KeyPair,
// which will deal with the intricacies of error handling, different key
// types, certificate chains, etc.
keyPEM := pem.EncodeToMemory(keyBlock)
cert, err := tls.X509KeyPair(certsPEM, keyPEM)
if err != nil {
log.Fatal(err)
}
config := &tls.Config{
Certificates: []tls.Certificate{cert},
}
}
我正在与为我提供证书的银行服务器集成。我从证书中创建了一个 pem
文件,所以现在我在 pem
文件中有了证书、私钥和密钥的密码短语。
新生成的文件pem
正在使用 OpenSSL 命令建立 SSL 连接,如下所示:
openssl s_client -connect host:port -key key.pem -cert cert.pem
此命令要求输入密码,我可以连接。但是我无法使用我的 Go 代码连接到相同的代码,它看起来像这样:
package main
import (
"crypto/tls"
"crypto/x509"
"fmt"
"net/http"
)
func main() {
caCert := []byte(`certs pem data`) // this contains both private key and certificates
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
// Setup HTTPS client
tlsConfig := &tls.Config{
RootCAs: caCertPool,
InsecureSkipVerify: true,
}
tlsConfig.BuildNameToCertificate()
transport := &http.Transport{TLSClientConfig: tlsConfig}
client := &http.Client{Transport: transport}
httpRequest, _ := http.NewRequest("GET", "https://test.com", nil)
resp, err := client.Do(httpRequest)
fmt.Printf("resp: [%v] \n Error: [%v]", resp, err)
}
我也不确定在我的 HTTP 请求中在哪里添加密码。
我得到的错误:remote error: tls: bad certificate
您似乎混淆了证书颁发机构和客户端证书。客户端证书向服务器证明你就是你所说的那个人(很像用户名和密码),并且使用 CA 以便你知道你正在与正确的服务器对话。
从适用于您的 openssl 命令来看,您的银行给了您一个客户端证书和密钥(尽管这非常不常用;除了您自己,没有人应该持有您的私钥,尤其是密码)。
The tls.Config.Certificates
field,如果被客户端使用,用于配置客户端证书。
Certificates contains one or more certificate chains to present to the other side of the connection. [...] Clients doing client-authentication may set either Certificates or GetClientCertificate.
TLS 证书通常加载 tls.LoadX509KeyPair or tls.X509KeyPair。但是,这些函数并不直接支持加密密钥。
相反,您必须自己加载密钥,使用 x509.DecryptPEMBlock 解密它,然后您可以使用 tls.X509KeyPair。
以下示例使用 EC 密钥,因为它的编码很短,但它与 RSA 密钥的工作原理相同。
package main
import (
"crypto/tls"
"crypto/x509"
"encoding/pem"
"fmt"
"log"
"net/http"
)
var bundle = []byte(`
-----BEGIN EC PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,99586A658F5D2DAC4A8A3CA387CF71CE
25EtKb7ycOI/5R47fYwpiaNERgYnCxCtcrMXJuOgueuxUXjiU0n93hpUpIQqaTLH
dDKhsR1UHvGJVTV4h577RQ+nEJ5z8K5Y9NWFqzfa/Q5SY43kqqoJ/fS/OCnTmH48
z4bL/dJBDE/a5HwJINgqQhGi9iUkCWUiPQxriJQ0i2s=
-----END EC PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIB2TCCAX+gAwIBAgIUUTZvgwwnbC05WHgIHMXxrbZzr6wwCgYIKoZIzj0EAwIw
QjELMAkGA1UEBhMCWFgxFTATBgNVBAcMDERlZmF1bHQgQ2l0eTEcMBoGA1UECgwT
RGVmYXVsdCBDb21wYW55IEx0ZDAeFw0xOTA1MTQxMzAwMDJaFw0xOTA1MTUxMzAw
MDJaMEIxCzAJBgNVBAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNV
BAoME0RlZmF1bHQgQ29tcGFueSBMdGQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC
AAScgLGx6SXchEo/s0X3AoF0mQkh3bGf9QY0s/2dPqf3/9irwz35DiDGoaP+FDZv
HnUX+D3tUEPhxkLyzWKKT9HHo1MwUTAdBgNVHQ4EFgQU3eB8oRcmvzZrx9Dkb6ma
MMtu1MkwHwYDVR0jBBgwFoAU3eB8oRcmvzZrx9Dkb6maMMtu1MkwDwYDVR0TAQH/
BAUwAwEB/zAKBggqhkjOPQQDAgNIADBFAiAvw/FqAmGbSlBklp6AHJy9kf9VPyhe
RA93ccNQ+7m1fAIhAOXr8c2QsH2oOYRTbn6bPZjkYQ2jLMaxatKhChBIuyZA
-----END CERTIFICATE-----
`)
func main() {
keyBlock, certsPEM := pem.Decode(bundle)
fmt.Println(x509.IsEncryptedPEMBlock(keyBlock)) // Output: true
// Decrypt key
keyDER, err := x509.DecryptPEMBlock(keyBlock, []byte("foobar"))
if err != nil {
log.Fatal(err)
}
// Update keyBlock with the plaintext bytes and clear the now obsolete
// headers.
keyBlock.Bytes = keyDER
keyBlock.Headers = nil
// Turn the key back into PEM format so we can leverage tls.X509KeyPair,
// which will deal with the intricacies of error handling, different key
// types, certificate chains, etc.
keyPEM := pem.EncodeToMemory(keyBlock)
cert, err := tls.X509KeyPair(certsPEM, keyPEM)
if err != nil {
log.Fatal(err)
}
config := &tls.Config{
Certificates: []tls.Certificate{cert},
}
}