Nathan
Nathan

Reputation: 7709

With golang and tls, how to convert rawCerts [][]byte (passed to VerifyPeerCertificate) to an x509.Certificate?

Context: I want to establish a TLS Connection to a server, which has a certificate with a different (but known!) domain.

So I want to use tls.Dial('tcp', 'real-domain', conf), but verify the domain of the certificate as if it would be the other domain (lets call it wrong-domain), of which I know the server should return it.

So I think the way to do this is override VerifyPeerCertificate in the clients tls.Config.

VerifyPeerCertificate gets rawCerts [][]byte as parameter, but to use x509.Verify I need the certificate as a x509.Certificate type.

The question is: How do I cenvert the rawCerts [][]byte, which are passed as a parameter to VerifyPeerCertificate converted to x509.Certificate?

This is how I want to use it:

    conf := &tls.Config{
        VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
            verifyOptions := x509.VerifyOptions{
                DNSName:                   "wrong-domain",
                Roots:                     serverCertPool,
            }
            cert := &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
    }

Upvotes: 2

Views: 2248

Answers (1)

blackgreen
blackgreen

Reputation: 45100

Use x509.ParseCertificate.

ParseCertificate parses a single certificate from the given ASN.1 DER data.

Example: cert, err := x509.ParseCertificate(rawCerts[0])

By the way this is also how the function that calls VerifyPeerCertificate does:

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

Upvotes: 2

Related Questions