С помощью golang и tls, как преобразовать байт rawCerts [] [] (переданный в VerifyPeerCertificate) в сертификат x509.?

# #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
        }
    }