Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to MITM with known keys and certificates #71

Closed
freman opened this issue Nov 5, 2014 · 16 comments
Closed

Ability to MITM with known keys and certificates #71

freman opened this issue Nov 5, 2014 · 16 comments

Comments

@freman
Copy link

freman commented Nov 5, 2014

Hi, it looks like the ConnectMitm action always generates a new key/certificate for every request.

I actually have our production keys/certificates that I'd like to use (as the reason we're doing this is for development)

Would love to be able to load up the list of known keys/certificates for given domains.

@elazarl
Copy link
Owner

elazarl commented Nov 5, 2014

Good comment. The use case I was thinking about is a single CA that generates certificates.

Here's what I suggest:

Instead of the Ca and TlsConfig fields, ConnectAction would have one field TLSConfig which is a function, accepting host name requested by the CONNECT request, and returning a *tls.Config object that would be used.

We would still have a function func TLSConfigFromCA(*tls.Certificate) that would return a function generating a *tls.Config from the given CA, with an automatically generated certificate. The TLSConfig field would contain the TLSConfigFromCA function by default.

The user would instead of setting ConnectAction{Ca: ca}, would do ConnectAction{Ca: TLSConfigFromCA(ca).

The code would be more or less:

type ConnectAction struct {
        Action    ConnectActionLiteral
        Hijack    func(req *http.Request, client net.Conn, ctx *ProxyCtx)
        TlsConfig func(host string, ctx *ProxyCtx) (*tls.Config, error)
}

func TLSConfigFromCA(ca *tls.Certificate) func (host string, ctx *ProxyCtx) (*tls.Config, error) {
        return func (host string, ctx *ProxyCtx) *tls.Config {
                config := *defaultTlsConfig
                cert, err := signHost(*ca, []string{stripPort(host)})
                if err != nil {
                        ctx.Warnf("Cannot sign host certificate with provided CA: %s", err)
                        return nil, err
                }
                config.Certificates = append(config.Certificates, cert)
                return config, nil
        }
}

What do you think?

@freman
Copy link
Author

freman commented Nov 5, 2014

Looks like it would achive my goals very nicely 👍

@elazarl
Copy link
Owner

elazarl commented Nov 5, 2014

I've sent a message about breaking changes in the mailing list. If no one
would object, I'll commit that tonight, and then update the tag for 1.1
next week.

Thanks for the report.

On Wed Nov 05 2014 at 8:03:01 AM freman notifications@github.com wrote:

Looks like it would achive my goals very nicely [image: 👍]


Reply to this email directly or view it on GitHub
#71 (comment).

@elazarl elazarl closed this as completed in 4cdd809 Nov 9, 2014
@elazarl
Copy link
Owner

elazarl commented Nov 9, 2014

@freman,

Please let me know if it works for you.

Thanks,

@k2xl
Copy link

k2xl commented Nov 21, 2014

Note that this definitely breaks :-). How can we get it to work with the previous ca.pem?

@elazarl
Copy link
Owner

elazarl commented Nov 22, 2014

By default it does. The default function takes certain.pem as a CA and
generate signed cert for each site like it used to do.

It's just that now you can change the default behavior.

On Fri, Nov 21, 2014, 6:07 PM k2xl notifications@github.com wrote:

Note that this definitely breaks :-). How can we get it to work with the
previous ca.pem?


Reply to this email directly or view it on GitHub
#71 (comment).

@swynter-ladbrokes
Copy link

Hi @elazarl sorry it's taken so long to get back to you, but I'd like to let you know that yes, this works perfectly for what we're trying to do - and with any luck (pending legal), I'll be able to pop our project up on our github soon

@k2xl
Copy link

k2xl commented Nov 24, 2014

@elazarl - So when we upgraded we started getting the SSL warnings on the browsers (using the ca.pem uploaded to our Key chain). When we went back one commit the warnings disappeared.

@elazarl
Copy link
Owner

elazarl commented Nov 25, 2014

@k2xl can you identify the problematic commit?

Thanks

@elazarl elazarl reopened this Nov 25, 2014
@k2xl
Copy link

k2xl commented Nov 25, 2014

@elazarl - the one that fixed this issue. 4cdd809

@freman
Copy link
Author

freman commented Nov 25, 2014

If it helps, I noticed that, when using the defaults, that if I went to https://foo.com then https://bar.com that foo's certificate would be presented for bar - this isn't a problem I have with pre-generated certificates, I just fill up tlsConfig.Certificates with the pre-generated certificates.

@elazarl
Copy link
Owner

elazarl commented Nov 26, 2014

Stupid bug, I've been reusing the tls.Config. Hence tests, and first access
worked. Sigh.

PS,
I need to replace the CA cert with a SHA-256 one, chrome would deprecate
those....

Thanks for noticing,

On Wed Nov 26 2014 at 12:21:45 AM freman notifications@github.com wrote:

If it helps, I noticed that, when using the defaults, that if I went to
https://foo.com then https://bar.com that foo's certificate would be
presented for bar - this isn't a problem I have with pre-generated
certificates, I just fill up tlsConfig.Certificates with the pre-generated
certificates.


Reply to this email directly or view it on GitHub
#71 (comment).

@k2xl
Copy link

k2xl commented Dec 8, 2014

Hey @elazarl , will you update this ticket when it is fixed? Or will it appear on a new ticket (since this one is closed)

@elazarl
Copy link
Owner

elazarl commented Dec 8, 2014

Hey, the issue is already closed with commit 2fc78d.

Thanks

@k2xl
Copy link

k2xl commented Dec 8, 2014

Can someone provide example code of using a pre generated cert?

@freman
Copy link
Author

freman commented Dec 8, 2014

package main

import (
    "crypto/tls"
    "github.com/elazarl/goproxy"
    "log"
    "net/http"
)


func main() {
    certificate := "example.com.crt";
    key         := "example.com.key";

    tlsConfig := &tls.Config{InsecureSkipVerify: true};
    proxy := goproxy.NewProxyHttpServer();

    x509pair, err := tls.LoadX509KeyPair(certificate, key)
    if err != nil {
        log.Fatalf("Unable to load certificate %s: %v", certificate, err)
    }
    tlsConfig.Certificates = append(tlsConfig.Certificates, x509pair)

        // Not strictly required but appears to help with SNI
    tlsConfig.BuildNameToCertificate()

    goproxy.MitmConnect.TLSConfig = func(host string, ctx *goproxy.ProxyCtx) (*tls.Config, error) {
        return tlsConfig, nil;
    }

    proxy.OnRequest(goproxy.ReqHostIs("example.com:443")).HandleConnect(goproxy.AlwaysMitm);
    proxy.OnRequest(goproxy.ReqHostIs("example.com", "example.com:443")).DoFunc(
        func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
            log.Printf("Got request for %v", req);
            // Have access to the request here...
            req.Header.Set("x-proxied", "you betcha");
            return req, nil;
    });

    log.Fatal(http.ListenAndServe(":9999", proxy));
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants