TPPZ
TPPZ

Reputation: 4891

Decrypt TLS in golang by storing SSL key to be used with Wireshark

I am trying to establish a TLS connection by providing a tls.Config struct containing a Rand field that should always return the same int when calling their Read method, cf. the docs here: https://golang.org/pkg/crypto/tls/#Config

I've written this builder:

func newZeroRand() *rand.Rand {
    return rand.New(rand.NewSource(0))
}

And a test to make sure that rand.Rand is always returning the same int when Read is invkoed multiple times, notice the different input params "foo" and "bar" providing the same output:

func TestPredictableZeroRandGenerator(t *testing.T) {
    zeroRand := newZeroRand()
    firstNum, err := zeroRand.Read([]byte("foo"))
    if err != nil {
        t.Error(err)
    }
    secondNum, err := zeroRand.Read([]byte("bar"))
    if err != nil {
        t.Error(err)
    }

    // fmt.Printf("firstNum %d secondNum %d \n", firstNum, secondNum)
    if firstNum != secondNum {
        t.Error(fmt.Sprintf("This is not a predictable zero random generator! The first number is: %d the second number is: %d", firstNum, secondNum))
    }
}

Using that previously defined newZeroRand() I was expecting to generate always the same SSL key inside the file same-key.log when providing the TLS configuration like this:

func tlsConfig() (*tls.Config, error) {
    w, err := os.OpenFile("same-key.log", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
    if err != nil {
        return nil, err
    }
    tlsConfig := tls.Config{
        Rand: newZeroRand(),
        KeyLogWriter: w,
    }
    return &tlsConfig, nil
}

But for multiple executions I get different file contents. I may be misunderstanding the details here: https://golang.org/pkg/crypto/tls/#example_Config_keyLogWriter because when I open those files same-key.log after each execution then I find the structure described here in the NSS Key Log Format from Mozilla: https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format

CLIENT_RANDOM <FIRST_LONG_ID> <SECOND_LONG_ID>

where:

When providing a key file same-key.log for a batch of packets from a different execution, then Wireshark is not able to decrpyt them!

I may be misunderstanding some internals about SSL cryptography here and I was wondering if I should also provide the certificates in the configuration struct? How could I generate these certificates?

Afaik when using certificates on top of the key there should be a piece of information coming from the other side at runtime, so then I can not decrypt the stream of packets if I don't have that information. This is why I thought certificates are not needed if I want to use Wireshark to decrypt those packets.

Otherwise I am not sure how could I force the TCP connection to always encrypt/decrypt the packets with the same key?

Edit:

As pointed out by @peter in his answer I was asserting on the length of the input byte slice rather than the actual "deterministic-random value".

I came out with this Read implementation for the tls.Config struct:

type debugRand struct {}
func (dr *debugRand) Read(p []byte) (n int, err error) {
    for i := range p {
        p[i] = byte(0)
    }
    return len(p), nil
}
func newZeroRand() *debugRand {
    return &debugRand{}
}

This is setting to 0 all the elements of the input slice.

However I still generate SSL keys which have different <SECOND_LONG_ID> values for different executions.

Is it possible at all to get Wireshark re-using SSL keys on different TLS connections when analysing those encrypted TCP packets?

Upvotes: 2

Views: 2355

Answers (1)

Peter
Peter

Reputation: 31681

You are using Read wrong. Your test doesn't test what you think it does. firstNum and secondNum are both 3 because you are reading three random bytes; because you are passing byte slices of length three. You never check the actual random bytes though.

Upvotes: 1

Related Questions