Home > Enterprise >  building https proxy failed with error SSL_ERROR_BAD_MAC_READ
building https proxy failed with error SSL_ERROR_BAD_MAC_READ

Time:10-26

I am trying to make an HTTP/HTTPS proxy with Golang like this link. This is all my code : First get command from browser. If it's CONNECT mean HTTPS and make simple TCP socket and let browser continue it. then pipe each connection together.

package main

import (
    "bufio"
    "fmt"
    "net"
    "strings"
)

func main() {
    fmt.Println("Start server...")

    ln, _ := net.Listen("tcp", ":8000")

    conn, _ := ln.Accept()
    handleSocket(conn)

}

func handleSocket(client_to_proxy net.Conn) {
    message, e := bufio.NewReader(client_to_proxy).ReadString('\n')
    message = strings.ReplaceAll(message, "\r\n", "")
    if e != nil {
        fmt.Println("ERROR1 ", e)
        return
    }

    splited := strings.Split(message, " ")
    host := strings.Split(splited[1], ":")
    if splited[0] == "CONNECT" {
        proxy_to_server, e := net.Dial("tcp", splited[1])
        if e != nil {
            fmt.Println("ERROR2 ", e)
            return
        }
        lenn, e := client_to_proxy.Write([]byte("HTTP/1.1 200 OK\r\n\r\n"))
        if e != nil {
            fmt.Println("ERROR8 ", e)
            return
        }
        fmt.Println(lenn)

        readAll(client_to_proxy, proxy_to_server)

    } else if splited[0] == "GET" {
        remote_conn, e := net.Dial("tcp", strings.Replace(splited[1][:len(splited[1])-1], "http://", "", 2) ":80")
        if e != nil {
            fmt.Println("ERROR7 ", e)
            return
        }
        _, e = remote_conn.Write([]byte("GET / "   splited[2]   "\r\n"   "Host: "   host[0]   "\r\n\r\n"))
        if e != nil {
            fmt.Println("ERROR6 ", e)
            return
        }
        writeAll(client_to_proxy, remote_conn)
    }
}

func writeAll(client_to_proxy net.Conn, proxy_to_server net.Conn) {
    buffer := make([]byte, 32*1024)
    for {
        readLeng, err := proxy_to_server.Read(buffer)
        if err != nil {
            fmt.Println("ERROR9 ", err)
            return
        }
        if readLeng > 0 {
            _, err := client_to_proxy.Write(buffer)
            if err != nil {
                fmt.Println("ERR4 ", err)
                return
            }
        }
    }
}

func readAll(client_to_proxy net.Conn, proxy_to_server net.Conn) {
    buffer := make([]byte, 32*1024)
    go writeAll(client_to_proxy, proxy_to_server)

    for {
        read, err := client_to_proxy.Read(buffer)
        if err != nil {
            return
        }
        if read > 0 {
            _, err := proxy_to_server.Write(buffer)
            if err != nil {
                fmt.Println("ERR5 ", err)
                return
            }
        }
    }
}

It works OK with HTTP but when trying for HTTPS in Firefox, I receive this error:

Secure Connection Failed

An error occurred during a connection to www.google.com. SSL received a record with an incorrect Message Authentication Code.

Error code: SSL_ERROR_BAD_MAC_READ

CodePudding user response:

Like all HTTP requests the CONNECT request starts with a multi-line request header which ends with a line consisting of only \r\n. But you only read the first line of it:

message, e := bufio.NewReader(client_to_proxy).ReadString('\n')

The rest of the request is send to the server, which likely returns some error, since this is not the expected start of a TLS handshake. This start of a TLS handshake only comes after the request header. The error returned by the server is then forwarded to the client and interpreted as TLS message - which is seen as a corrupt message, hence "bad mac".

   readAll(client_to_proxy, proxy_to_server)

Instead of forwarding all remaining data (i.e. everything except the first line of the request) to the server you need to first read the full request header and only then forward everything between client and server.

CodePudding user response:

Many Thanks to @steffen-ullrich, This is final solution for who comes later. works for http/https:

package main

import (
    "fmt"
    "net"
    "strings"
)

func main() {
    fmt.Println("Start server...")

    ln, _ := net.Listen("tcp", ":8000")

    for {
        conn, _ := ln.Accept()
        handleSocket(conn)
    }
}

func handleSocket(client_to_proxy net.Conn) {
    buffer := make([]byte, 32*1024)
    _, e := client_to_proxy.Read(buffer)
    if e != nil {
        fmt.Println("ERROR1 ", e)
        return
    }
    message := string(buffer)
    a := strings.Count(message, "\r\n")
    fmt.Println(message)
    fmt.Println(a)
    if e != nil {
        fmt.Println("ERROR1 ", e)
        return
    }

    splited := strings.Split(message, " ")
    //host := strings.Split(splited[1], ":")
    if splited[0] == "CONNECT" {
        //message = strings.Replace(message, "CONNECT", "GET", 1)
        proxy_to_server, e := net.Dial("tcp", splited[1])
        if e != nil {
            fmt.Println("ERROR2 ", e)
            return
        }
        //_, e = proxy_to_server.Write([]byte(message))
        //if e != nil {
        //  fmt.Println("ERROR2 ", e)
        //  return
        //}
        lenn, e := client_to_proxy.Write([]byte("HTTP/1.1 200 OK\r\n\r\n"))
        if e != nil {
            fmt.Println("ERROR8 ", e)
            return
        }
        fmt.Println(lenn)

        read443(client_to_proxy, proxy_to_server)
    } else if splited[0] == "GET" {
        host1 := strings.Replace(splited[1], "http://", "", 1)
        host2 := host1[:len(host1)-1]
        var final_host string
        if strings.LastIndexAny(host2, "/") > 0 {
            final_host = host2[:strings.LastIndexAny(host2, "/")]
        } else {
            final_host = host2
        }
        proxy_to_server, e := net.Dial("tcp", final_host ":80")
        if e != nil {
            fmt.Println("ERROR7 ", e)
            return
        }
        _, e = proxy_to_server.Write([]byte(message))
        if e != nil {
            fmt.Println("ERROR6 ", e)
            return
        }

        write80(client_to_proxy, proxy_to_server)
    }
}

func write80(client_to_proxy net.Conn, proxy_to_server net.Conn) {
    buffer := make([]byte, 64*1024)

    readLeng, err := proxy_to_server.Read(buffer)
    if err != nil {
        fmt.Println("ERROR9 ", err)
        return
    }
    fmt.Println("WRIIIIIIIIIIIIIIIIIIIIIIT from server:")
    fmt.Println(string(buffer[:readLeng]))
    if readLeng > 0 {
        _, err := client_to_proxy.Write(buffer[:readLeng])
        if err != nil {
            fmt.Println("ERR4 ", err)
            return
        }
    }

    go read80(client_to_proxy, proxy_to_server)
    for {
        readLeng, err := proxy_to_server.Read(buffer)
        if err != nil {
            fmt.Println("ERROR10 ", err)
            return
        }
        fmt.Println("WRIIIIIIIIIIIIIIIIIIIIIIT from server:")
        fmt.Println(string(buffer[:readLeng]))
        if readLeng > 0 {
            _, err := client_to_proxy.Write(buffer[:readLeng])
            if err != nil {
                fmt.Println("ERR4 ", err)
                return
            }
        }
    }
}

func read80(client_to_proxy net.Conn, proxy_to_server net.Conn) {
    buffer := make([]byte, 32*1024)

    for {
        readLeng, err := client_to_proxy.Read(buffer)
        if err != nil {
            return
        }
        fmt.Println("REEEEEEEEEEEEEEEEEEEEEEED from client:")
        fmt.Println(string(buffer[:readLeng]))
        if readLeng > 0 {
            _, err := proxy_to_server.Write(buffer[:readLeng])
            if err != nil {
                fmt.Println("ERR5 ", err)
                return
            }
        }
    }
}

func write443(client_to_proxy net.Conn, proxy_to_server net.Conn) {
    buffer := make([]byte, 32*1024)
    for {
        readLeng, err := proxy_to_server.Read(buffer)
        if err != nil {
            fmt.Println("ERROR10 ", err)
            return
        }
        fmt.Println("WRIIIIIIIIIIIIIIIIIIIIIIT from server:")
        fmt.Println(string(buffer[:readLeng]))
        if readLeng > 0 {
            _, err := client_to_proxy.Write(buffer[:readLeng])
            if err != nil {
                fmt.Println("ERR4 ", err)
                return
            }
        }
    }
}

func read443(client_to_proxy net.Conn, proxy_to_server net.Conn) {
    buffer := make([]byte, 32*1024)

    readLeng, err := client_to_proxy.Read(buffer)
    if err != nil {
        return
    }
    fmt.Println("REEEEEEEEEEEEEEEEEEEEEEED from client:")
    fmt.Println(string(buffer[:readLeng]))
    if readLeng > 0 {
        _, err := proxy_to_server.Write(buffer[:readLeng])
        if err != nil {
            fmt.Println("ERR5 ", err)
            return
        }
    }

    go write443(client_to_proxy, proxy_to_server)

    for {
        readLeng, err := client_to_proxy.Read(buffer)
        if err != nil {
            return
        }
        fmt.Println("REEEEEEEEEEEEEEEEEEEEEEED from client:")
        fmt.Println(string(buffer[:readLeng]))
        if readLeng > 0 {
            _, err := proxy_to_server.Write(buffer[:readLeng])
            if err != nil {
                fmt.Println("ERR5 ", err)
                return
            }
        }
    }
}
  • Related