why do I get mac_bad_record error with my tls1.2 implementation

0

so I'm writing my own tls 1.2 implementation for learning's sake and because the server I'm connecting to use a modified version of the protocol that ask for a non random client_random anyway (TL;DR: I'm having a bad_record_mac error on finished message with my implementation and can't find where I made a mistake)

I have to precise the only cipher suite I'm concerned about is TLS_RSA_WITH_AES_128_CBC_SHA

so first I create my client random and the handshake begins with the server sending server_random and the RSA public key in the certificate

I generate a random pre_master_secret and encrypt it with the RSA public key (done by a native module of the language, so no mess up by me on this) and send it back in a client_key_exchange message

I then generate the master_secret from: PRF(pre_master_secret, "master secret", client_random+server_random) where PRF is:

class TlsMasterSecret {
    constructor(pre_master_secret, client_random, server_random) {
        this.master_secret = TlsMasterSecret.PRF(pre_master_secret, Buffer.from("master secret", "ascii"), Buffer.concat([client_random, server_random]), 48);
        this.master_secret = this.master_secret.slice(0, 48);
        this.key_block = TlsMasterSecret.PRF(this.master_secret, Buffer.from("key expansion", "ascii"),Buffer.concat([server_random, client_random]), 104);
        // 20 20 16 16
        this.client_write_MAC_key = this.key_block.slice(0, 20);
        this.server_write_MAC_key = this.key_block.slice(20, 40);
        this.client_write_key = this.key_block.slice(40, 56);
        this.server_write_key = this.key_block.slice(56, 72);
    }
    static PRF(secret, label, seed, neededLength) {
        return TlsMasterSecret.P_hash(secret, Buffer.concat([label, seed]), neededLength)
    }
    static P_hash(secret, seed, neededLength) {
        const A = [seed];
        let resultHash = Buffer.from("", "hex");
        // HMAC_SHA256 generates 32 bytes per update
        const iterations = Math.ceil(neededLength / 32);
        // generate A
        for(let i = 1; i < iterations + 1; i++) {
            A[i] = TlsMasterSecret.HMAC_hash(secret, A[i-1]);
        }
        // calculates the hash
        for(let i = 1; i < iterations + 1; i++) {
            resultHash = Buffer.concat([resultHash, TlsMasterSecret.HMAC_hash(secret, A[i])]);
        }
        return resultHash;
    }
    static HMAC_hash(secret, seed) {
        const hmac = crypto.createHmac("sha256", secret);
        hmac.update(seed);
        return hmac.digest();
    }
}

then I create the Finished message from 0x1400000c followed by 12 bytes of verify_data

verify_data is generated like this:

// I strip the record layer headers off the messages
client_hello = 0x0100002f03032668f90d7d3b3420f7712a3004247d233d90cc63fb4b23f77912b31c8c89893b000008002f0035003c003d0100
server_hello = 0x0200002603031296263fba0a7955a83b2bf9c3716c8ee1c52e9065b89ee5649b31391d7ce84700002f00
certificate = 0b00034e00034b00034830820344308202ada00302.......
server_hello_done = 0e000000
client_key_exchange = 100000820080673f1772e35c7565a1e0c2fae5ee1b5bf92211ba9e4de14620f43856d954cf737aa04c48f8b2ffa182f652fedd68523056acda3c7cd101c5a2c3a625655df67ad9fb7ca082cf68476f174ea7b83eab980b7b15657036ad0e26883c9bfe368847a02b052817cb80dabafc6af1dac8064ea0dc676e0f8ea74f84a122135f31b612

handshake_messages = client_hello + server_hello + certificate + server_hello_done + client_key_exchange

verify_data = PRF(master_secret, "client finished", sha256(handshake_messages))[0..12]

then I create the MAC that will go along this message:


// hmac_sha1(secret, seed)
// seq_num is a uint64 @ 0 for the first message, 0x00000000
// type = 0x16
// version = 0x0303
// length = 0x0010
// content = 0x1400000c + verify_data
MAC = hmac_sha1(client_write_MAC_key, seq_num + type + version + length + content)
plaintext = content + MAC

IV = randomBytes(16)

// aes_128_cbc(key, IV, message)
ciphertext = aes_128_cbc(client_write_key, IV, plaintext)

final = 0x16 + 0x0303 + 0x0040 + IV + ciphertext

if you read all of this and still willing to help thank you so much I think I followed the specification but I'm getting a bad_record_mac error in wireshark so there's something wrong somewhere, I just can't find it :(

node.js
aes
tls1.2
sha1
sha256
asked on Stack Overflow Mar 11, 2019 by torsina • edited Apr 15, 2019 by Shanika Harshani

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0