# #go #ssl #ssl-certificate
Вопрос:
Контекст: Я хочу установить TLS-соединение с сервером, у которого есть сертификат с другим (но известным!) доменом.
Поэтому я хочу использовать tls.Dial('tcp', 'real-domain', conf)
, но проверить домен сертификата, как если бы это был другой домен (давайте назовем его wrong-domain
), из которого, как я знаю, сервер должен его вернуть.
Поэтому я думаю, что способ сделать это-переопределить VerifyPeerCertificate
в клиентах tls.Config
.
VerifyPeerCertificate
получает rawCerts [][]byte
в качестве параметра, но для использования x509.Verify
мне нужен сертификат в качестве x509.Certificate
типа.
Вопрос в следующем: как мне преобразовать значения rawCerts [][]byte
, которые передаются в качестве параметра для VerifyPeerCertificate
преобразования x509.Certificate
?
Вот как я хочу его использовать:
conf := amp;tls.Config{
VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
verifyOptions := x509.VerifyOptions{
DNSName: "wrong-domain",
Roots: serverCertPool,
}
cert := amp;x509.Certificate{???} // How do I get the x509.Certificate out of the rawCerts [][]byte parameter?
_, err := cert.Verify(verifyOptions)
return err
},
InsecureSkipVerify: true, // We verify in VerifyPeerCertificate
}
Ответ №1:
Воспользуйся x509.ParseCertificate
.
ParseCertificate анализирует один сертификат из данных ASN.1 DER.
Пример: cert, err := x509.ParseCertificate(rawCerts[0])
Кстати, именно так VerifyPeerCertificate
и делает вызывающая функция:
// crypto/tls/handshake/handshake_client.go
func (c *Conn) verifyServerCertificate(certificates [][]byte) error {
for i, asn1Data := range certificates {
cert, err := x509.ParseCertificate(asn1Data)
if err != nil {
c.sendAlert(alertBadCertificate)
return errors.New("tls: failed to parse certificate from server: " err.Error())
}
certs[i] = cert
}
// later on...
if c.config.VerifyPeerCertificate != nil {
if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil {
c.sendAlert(alertBadCertificate)
return err
}
}