Ejemplo n.º 1
0
/* A TLS CBC record looks like ..
 *
 * [ Payload data ] [ HMAC ] [ Padding ] [ Padding length byte ]
 *
 * Each byte in the padding is expected to be set to the same value
 * as the padding length byte. So if the padding length byte is '2'
 * then the padding will be [ '2', '2' ] (there'll be three bytes
 * set to that value if you include the padding length byte).
 *
 * The goal of s2n_verify_cbc() is to verify that the padding and hmac
 * are correct, without leaking (via timing) how much padding there
 * actually is: as this is considered secret. 
 *
 * In addition to our efforts here though, s2n also wraps any CBC
 * verification error (or record parsing error in general) with
 * a randomized delay of between 1ms and 10 seconds. See s2n_connection.c.
 * This amount of delay randomization is sufficient to increase the
 * complexity of attack for even a 1 microsecond timing leak (which
 * is quite large) by a factor of around 83 trillion.
 */
int s2n_verify_cbc(struct s2n_connection *conn, struct s2n_hmac_state *hmac, struct s2n_blob *decrypted)
{
    struct s2n_hmac_state copy;

    int mac_digest_size = s2n_hmac_digest_size(hmac->alg);

    /* The record has to be at least big enough to contain the MAC,
     * plus the padding length byte */
    gt_check(decrypted->size, mac_digest_size);

    int payload_and_padding_size = decrypted->size - mac_digest_size;

    /* Determine what the padding length is */
    uint8_t padding_length = decrypted->data[decrypted->size - 1];

    int payload_length = MAX(payload_and_padding_size - padding_length - 1, 0);

    /* Update the MAC */
    GUARD(s2n_hmac_update(hmac, decrypted->data, payload_length));
    GUARD(s2n_hmac_copy(&copy, hmac));

    /* Check the MAC */
    uint8_t check_digest[S2N_MAX_DIGEST_LEN];
    lte_check(mac_digest_size, sizeof(check_digest));
    GUARD(s2n_hmac_digest_two_compression_rounds(hmac, check_digest, mac_digest_size));

    int mismatches = s2n_constant_time_equals(decrypted->data + payload_length, check_digest, mac_digest_size) ^ 1;

    /* Compute a MAC on the rest of the data so that we perform the same number of hash operations */
    GUARD(s2n_hmac_update(&copy, decrypted->data + payload_length + mac_digest_size, decrypted->size - payload_length - mac_digest_size - 1));

    /* SSLv3 doesn't specify what the padding should actually be */
    if (conn->actual_protocol_version == S2N_SSLv3) {
        return 0 - mismatches;
    }

    /* Check the maximum amount that could theoritically be padding */
    int check = MIN(255, (payload_and_padding_size - 1));

    int cutoff = check - padding_length;
    for (int i = 0, j = decrypted->size - 1 - check; i < check && j < decrypted->size; i++, j++) {
        uint8_t mask = ~(0xff << ((i >= cutoff) * 8));
        mismatches |= (decrypted->data[j] ^ padding_length) & mask;
    }

    if (mismatches) {
        S2N_ERROR(S2N_ERR_CBC_VERIFY);
    }

    return 0;
}
Ejemplo n.º 2
0
int main(int argc, char **argv)
{
    uint8_t digest_pad[256];
    uint8_t check_pad[256];
    uint8_t output_pad[256];
    struct s2n_stuffer output;
    uint8_t sekrit[] = "sekrit";
    uint8_t longsekrit[] = "This is a really really really long key on purpose to make sure that it's longer than the block size";
    uint8_t hello[] = "Hello world!";
    struct s2n_hmac_state hmac, copy;
    struct s2n_hmac_state cmac;

    struct s2n_blob out = {.data = output_pad,.size = sizeof(output_pad) };

    BEGIN_TEST();

    /* Initialise our output stuffers */
    EXPECT_SUCCESS(s2n_stuffer_init(&output, &out));

    EXPECT_EQUAL(s2n_hmac_digest_size(S2N_HMAC_MD5), 16);
    EXPECT_SUCCESS(s2n_hmac_init(&hmac, S2N_HMAC_MD5, sekrit, strlen((char *)sekrit)));
    EXPECT_SUCCESS(s2n_hmac_update(&hmac, hello, strlen((char *)hello)));
    EXPECT_SUCCESS(s2n_hmac_copy(&copy, &hmac));
    EXPECT_SUCCESS(s2n_hmac_digest(&hmac, digest_pad, 16));

    for (int i = 0; i < 16; i++) {
        EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i]));
    }

    /* Reference value from python */
    EXPECT_EQUAL(memcmp(output_pad, "3ad68c53dc1a3cf35f6469877fae4585", 16 * 2), 0);

    /* Check the copy */
    EXPECT_SUCCESS(s2n_hmac_digest(&copy, digest_pad, 16));

    for (int i = 0; i < 16; i++) {
        EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i]));
    }

    /* Reference value from python */
    EXPECT_EQUAL(memcmp(output_pad, "3ad68c53dc1a3cf35f6469877fae4585", 16 * 2), 0);

    /* Test that a reset works */
    EXPECT_SUCCESS(s2n_hmac_reset(&hmac));
    EXPECT_SUCCESS(s2n_hmac_update(&hmac, hello, strlen((char *)hello)));
    EXPECT_SUCCESS(s2n_hmac_digest(&hmac, digest_pad, 16));

    EXPECT_SUCCESS(s2n_stuffer_init(&output, &out));
    for (int i = 0; i < 16; i++) {
        EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i]));
    }

    /* Reference value from python */
    EXPECT_EQUAL(memcmp(output_pad, "3ad68c53dc1a3cf35f6469877fae4585", 16 * 2), 0);

    EXPECT_SUCCESS(s2n_hmac_init(&hmac, S2N_HMAC_MD5, longsekrit, strlen((char *)longsekrit)));
    EXPECT_SUCCESS(s2n_hmac_update(&hmac, hello, strlen((char *)hello)));
    EXPECT_SUCCESS(s2n_hmac_digest(&hmac, digest_pad, 16));

    EXPECT_SUCCESS(s2n_stuffer_init(&output, &out));
    for (int i = 0; i < 16; i++) {
        EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i]));
    }

    /* Reference value from python */
    EXPECT_EQUAL(memcmp(output_pad, "2ce569d61f4ee6ad9ceebe02a112ace7", 16 * 2), 0);

    /* Test that a reset works */
    EXPECT_SUCCESS(s2n_hmac_reset(&hmac));
    EXPECT_SUCCESS(s2n_hmac_update(&hmac, hello, strlen((char *)hello)));
    EXPECT_SUCCESS(s2n_hmac_digest(&hmac, digest_pad, 16));

    EXPECT_SUCCESS(s2n_stuffer_init(&output, &out));
    for (int i = 0; i < 16; i++) {
        EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i]));
    }

    /* Reference value from python */
    EXPECT_EQUAL(memcmp(output_pad, "2ce569d61f4ee6ad9ceebe02a112ace7", 16 * 2), 0);

    /* Verify that _verify works */
    EXPECT_SUCCESS(s2n_hmac_init(&cmac, S2N_HMAC_MD5, longsekrit, strlen((char *)longsekrit)));
    EXPECT_SUCCESS(s2n_hmac_update(&cmac, hello, strlen((char *)hello)));
    EXPECT_SUCCESS(s2n_hmac_digest(&cmac, check_pad, 16));
    EXPECT_SUCCESS(s2n_hmac_digest_verify(digest_pad, 16, check_pad, 16));

    /* Try SHA1 */
    EXPECT_EQUAL(s2n_hmac_digest_size(S2N_HMAC_SHA1), 20);
    EXPECT_SUCCESS(s2n_hmac_init(&hmac, S2N_HMAC_SHA1, sekrit, strlen((char *)sekrit)));
    EXPECT_SUCCESS(s2n_hmac_update(&hmac, hello, strlen((char *)hello)));
    EXPECT_SUCCESS(s2n_hmac_digest(&hmac, digest_pad, 20));

    EXPECT_SUCCESS(s2n_stuffer_init(&output, &out));
    for (int i = 0; i < 20; i++) {
        EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i]));
    }

    /* Reference value from python */
    EXPECT_EQUAL(memcmp(output_pad, "6d301861b599938eca94f6de917362886d97882f", 20 * 2), 0);

    /* Try SHA256 */
    EXPECT_EQUAL(s2n_hmac_digest_size(S2N_HMAC_SHA256), 32);
    EXPECT_SUCCESS(s2n_hmac_init(&hmac, S2N_HMAC_SHA256, sekrit, strlen((char *)sekrit)));
    EXPECT_SUCCESS(s2n_hmac_update(&hmac, hello, strlen((char *)hello)));
    EXPECT_SUCCESS(s2n_hmac_digest(&hmac, digest_pad, 32));

    EXPECT_SUCCESS(s2n_stuffer_init(&output, &out));
    for (int i = 0; i < 32; i++) {
        EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i]));
    }

    /* Reference value from python */
    EXPECT_EQUAL(memcmp(output_pad, "adc20b12d236e6d1824d690622e33ead4f67ba5a2be9606fe762b2dd859a78a9", 32 * 2), 0);

    /* Try SHA384 */
    EXPECT_EQUAL(s2n_hmac_digest_size(S2N_HMAC_SHA384), 48);
    EXPECT_SUCCESS(s2n_hmac_init(&hmac, S2N_HMAC_SHA384, sekrit, strlen((char *)sekrit)));
    EXPECT_SUCCESS(s2n_hmac_update(&hmac, hello, strlen((char *)hello)));
    EXPECT_SUCCESS(s2n_hmac_digest(&hmac, digest_pad, 48));

    EXPECT_SUCCESS(s2n_stuffer_init(&output, &out));
    for (int i = 0; i < 48; i++) {
        EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i]));
    }

    /* Reference value from python */
    EXPECT_EQUAL(memcmp(output_pad, "8552563cadd583b79dcc7225bb79bc6483c63f259187162e1c9d4283eb6299ef1bc3ca81c0c40fc7b22f7a1f3b93adb4", 48 * 2), 0);

    /* Try SHA512 */
    EXPECT_EQUAL(s2n_hmac_digest_size(S2N_HMAC_SHA512), 64);
    EXPECT_SUCCESS(s2n_hmac_init(&hmac, S2N_HMAC_SHA512, sekrit, strlen((char *)sekrit)));
    EXPECT_SUCCESS(s2n_hmac_update(&hmac, hello, strlen((char *)hello)));
    EXPECT_SUCCESS(s2n_hmac_digest(&hmac, digest_pad, 64));

    EXPECT_SUCCESS(s2n_stuffer_init(&output, &out));
    for (int i = 0; i < 64; i++) {
        EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i]));
    }

    /* Reference value from python */
    EXPECT_EQUAL(memcmp(output_pad, "0a834a1ed265042e2897405edb4fdd9818950cd5bea10b828f2fed45a1cb6dbd2107e4b04eb20f211998cd4e8c7e11ebdcb0103ac63882481e1bb8083d07f4be", 64 * 2), 0);

    /* Try SSLv3 MD5 */
    EXPECT_EQUAL(s2n_hmac_digest_size(S2N_HMAC_SSLv3_MD5), 16);
    EXPECT_SUCCESS(s2n_hmac_init(&hmac, S2N_HMAC_SSLv3_MD5, sekrit, strlen((char *)sekrit)));
    EXPECT_SUCCESS(s2n_hmac_update(&hmac, hello, strlen((char *)hello)));
    EXPECT_SUCCESS(s2n_hmac_digest(&hmac, digest_pad, 16));

    EXPECT_SUCCESS(s2n_stuffer_init(&output, &out));
    for (int i = 0; i < 16; i++) {
        EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i]));
    }

    /* Reference value from Go */
    EXPECT_EQUAL(memcmp(output_pad, "d4f0d06b9765de23e6c3e33a24c5ded0", 16 * 2), 0);

    /* Test that a reset works */
    EXPECT_SUCCESS(s2n_hmac_reset(&hmac));
    EXPECT_SUCCESS(s2n_hmac_update(&hmac, hello, strlen((char *)hello)));
    EXPECT_SUCCESS(s2n_hmac_digest(&hmac, digest_pad, 16));

    EXPECT_SUCCESS(s2n_stuffer_init(&output, &out));
    for (int i = 0; i < 16; i++) {
        EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i]));
    }

    EXPECT_EQUAL(memcmp(output_pad, "d4f0d06b9765de23e6c3e33a24c5ded0", 16 * 2), 0);

    /* Try SSLv3 SHA1 */
    EXPECT_EQUAL(s2n_hmac_digest_size(S2N_HMAC_SSLv3_SHA1), 20);
    EXPECT_SUCCESS(s2n_hmac_init(&hmac, S2N_HMAC_SSLv3_SHA1, sekrit, strlen((char *)sekrit)));
    EXPECT_SUCCESS(s2n_hmac_update(&hmac, hello, strlen((char *)hello)));
    EXPECT_SUCCESS(s2n_hmac_digest(&hmac, digest_pad, 20));

    EXPECT_SUCCESS(s2n_stuffer_init(&output, &out));
    for (int i = 0; i < 20; i++) {
        EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i]));
    }

    /* Reference value from Go */
    EXPECT_EQUAL(memcmp(output_pad, "b0c66179f6eb5a46b4b7c4fca84b3ea5161b7326", 20 * 2), 0);

    /* Test that a reset works */
    EXPECT_SUCCESS(s2n_hmac_reset(&hmac));
    EXPECT_SUCCESS(s2n_hmac_update(&hmac, hello, strlen((char *)hello)));
    EXPECT_SUCCESS(s2n_hmac_digest(&hmac, digest_pad, 20));

    EXPECT_SUCCESS(s2n_stuffer_init(&output, &out));
    for (int i = 0; i < 20; i++) {
        EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i]));
    }

    EXPECT_EQUAL(memcmp(output_pad, "b0c66179f6eb5a46b4b7c4fca84b3ea5161b7326", 20 * 2), 0);

    END_TEST();
}