From 39e1ddec2ed3480e0edc07bbabfacbf907dc4e3f Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Sat, 11 Apr 2015 14:59:22 +0200 Subject: [PATCH 1/5] scripts: Add a tool that tries to guess MAC/ICV values using validation times This tool shows that it is trivial to re-construct the value memcmp() compares against by just measuring the time the non-time-constant memcmp() requires to fail. It also shows that even when running without any network latencies it gets very difficult to reconstruct MAC/ICV values, as the time variances due to the crypto routines are large enough that it gets difficult to measure the time that memcmp() actually requires after computing the MAC. However, the faster/time constant an algorithm is, the more likely is a successful attack. When using AES-NI, it is possible to reconstruct (parts of) a valid MAC with this tool, for example with AES-GCM. While this is all theoretical, and way more difficult to exploit with network jitter, it nonetheless shows that we should replace any use of memcmp/memeq() with a constant-time alternative in all sensitive places. --- scripts/.gitignore | 1 + scripts/Makefile.am | 4 +- scripts/timeattack.c | 365 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 369 insertions(+), 1 deletion(-) create mode 100644 scripts/timeattack.c diff --git a/scripts/.gitignore b/scripts/.gitignore index b876a3ac2..7883d9cca 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -15,3 +15,4 @@ pubkey_speed settings-test thread_analysis tls_test +timeattack diff --git a/scripts/Makefile.am b/scripts/Makefile.am index abc6d75dd..c5155efc2 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -5,7 +5,7 @@ AM_CPPFLAGS = \ noinst_PROGRAMS = bin2array bin2sql id2sql key2keyid keyid2sql oid2der \ thread_analysis dh_speed pubkey_speed crypt_burn hash_burn fetch \ - dnssec malloc_speed aes-test settings-test + dnssec malloc_speed aes-test settings-test timeattack if USE_TLS noinst_PROGRAMS += tls_test @@ -28,6 +28,7 @@ hash_burn_SOURCES = hash_burn.c malloc_speed_SOURCES = malloc_speed.c fetch_SOURCES = fetch.c dnssec_SOURCES = dnssec.c +timeattack_SOURCES = timeattack.c id2sql_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la key2keyid_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la keyid2sql_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la @@ -41,6 +42,7 @@ fetch_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la dnssec_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la aes_test_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la settings_test_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la +timeattack_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la key2keyid.o : $(top_builddir)/config.status diff --git a/scripts/timeattack.c b/scripts/timeattack.c new file mode 100644 index 000000000..0a53abae9 --- /dev/null +++ b/scripts/timeattack.c @@ -0,0 +1,365 @@ +#include +#include + +#include + +typedef bool (*attackfn_t)(void *subj, u_char *data, size_t len); + +static void start_timing(struct timespec *start) +{ + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, start); +} + +static u_int64_t end_timing(struct timespec *start) +{ + struct timespec end; + + clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end); + return (end.tv_nsec - start->tv_nsec) + + (end.tv_sec - start->tv_sec) * 1000000000; +} + +static int intcmp(const void *a, const void *b) +{ + return *(u_int64_t*)a - *(u_int64_t*)b; +} + +static u_int64_t median(u_int64_t *m, int count) +{ + qsort(m, count, sizeof(u_int64_t), intcmp); + return m[count / 2]; +} + +static bool timeattack(attackfn_t attackfn, void *subj, size_t dlen, + u_int iterations, u_int distance) +{ + struct timespec start; + u_char test[dlen]; + u_int64_t mini, maxi, t[256], m[256][10]; + float fastdist = 0, slowdist = 0; + int i, j, k, l, byte, limit, retry = 0; + int fastest = 0, slowest = 0; + + memset(test, 0, dlen); + + /* do some iterations to fill caches */ + for (i = 0; i < iterations; i++) + { + attackfn(subj, test, dlen); + } + + for (byte = 0; byte < dlen;) + { + memset(t, 0, sizeof(t)); + memset(m, 0, sizeof(m)); + + limit = iterations * (retry + 1); + + /* measure timing for all patterns in next byte */ + for (k = 0; k < 10; k++) + { + for (j = 0; j < 256; j++) + { + for (l = 0; l < 100; l++) + { + test[byte] = j; + start_timing(&start); + for (i = 0; i < limit; i++) + { + attackfn(subj, test, dlen); + } + m[j][k] += end_timing(&start); + } + } + } + + for (j = 0; j < 256; j++) + { + t[j] = median(m[j], countof(m[j])); + } + + /* find fastest/slowest runs */ + mini = ~0; + maxi = 0; + for (j = 0; j < 256; j++) + { + if (t[j] < mini) + { + mini = min(t[j], mini); + fastest = j; + } + if (t[j] > maxi) + { + maxi = max(t[j], maxi); + slowest = j; + } + } + /* calculate distance to next result */ + mini = ~0; + maxi = 0; + for (j = 0; j < 256; j++) + { + if (fastest != j && t[j] < mini) + { + mini = min(t[j], mini); + fastdist = (float)(t[j] - t[fastest]) / distance; + } + if (slowest != j && t[j] > maxi) + { + maxi = max(t[j], maxi); + slowdist = (float)(t[slowest] - t[j]) / distance; + } + } + if (fastdist > 1.0f) + { + fprintf(stderr, "byte %02d: %02x (fastest, dist %02.2f)\n", + byte, fastest, fastdist); + test[byte] = fastest; + retry = 0; + byte++; + } + else if (slowdist > 1.0f) + { + fprintf(stderr, "byte %02d: %02x (slowest, dist %02.2f)\n", + byte, slowest, slowdist); + test[byte] = slowest; + retry = 0; + byte++; + } + else + { + if (retry++ > 5 && byte > 0) + { + fprintf(stderr, "distance fastest %02.2f (%02x), " + "slowest %02.2f (%02x), stepping back\n", + fastdist, fastest, slowdist, slowest); + test[byte--] = 0; + } + else if (retry < 10) + { + fprintf(stderr, "distance fastest %02.2f (%02x), " + "slowest %02.2f (%02x), retrying (%d)\n", + fastdist, fastest, slowdist, slowest, retry); + } + else + { + printf("attack failed, giving up\n"); + return FALSE; + } + } + } + if (attackfn(subj, test, dlen)) + { + printf("attack successful with %b\n", test, dlen); + return TRUE; + } + printf("attack failed with %b\n", test, dlen); + return FALSE; +} + +CALLBACK(attack_memeq1, bool, + u_char *subj, u_char *data, size_t len) +{ + return memeq(data, subj, len); +} + +CALLBACK(attack_memeq2, bool, + u_char *subj, u_char *data, size_t len) +{ + return memeq(subj, data, len); +} + +CALLBACK(attack_memeq3, bool, + u_char *subj, u_char *data, size_t len) +{ + int i; + + for (i = 0; i < len; i++) + { + if (subj[i] != data[i]) + { + return FALSE; + } + } + return TRUE; +} + +CALLBACK(attack_memeq4, bool, + u_char *subj, u_char *data, size_t len) +{ + int i, m = 0; + + for (i = 0; i < len; i++) + { + m |= subj[i] != data[i]; + } + return !m; +} + +static bool attack_memeq(char *name, u_int iterations, u_int distance) +{ + struct { + char *name; + attackfn_t fn; + } attacks[] = { + { "memeq1", attack_memeq1 }, + { "memeq2", attack_memeq2 }, + { "memeq3", attack_memeq3 }, + { "memeq4", attack_memeq4 }, + }; + u_char exp[16]; + int i; + + srandom(time(NULL)); + for (i = 0; i < sizeof(exp); i++) + { + exp[i] = random(); + } + fprintf(stderr, "attacking %b\n", exp, sizeof(exp)); + + for (i = 0; i < countof(attacks); i++) + { + if (streq(name, attacks[i].name)) + { + return timeattack(attacks[i].fn, exp, sizeof(exp), + iterations, distance); + } + } + return FALSE; +} + +CALLBACK(attack_aead, bool, + aead_t *aead, u_char *data, size_t len) +{ + u_char iv[aead->get_iv_size(aead)]; + + memset(iv, 0, sizeof(iv)); + return aead->decrypt(aead, chunk_create(data, len), chunk_empty, + chunk_from_thing(iv), NULL); +} + +static bool attack_aeads(encryption_algorithm_t alg, size_t key_size, + u_int iterations, u_int distance) +{ + u_char buf[64]; + aead_t *aead; + bool res; + + aead = lib->crypto->create_aead(lib->crypto, alg, key_size, 0); + if (!aead) + { + fprintf(stderr, "creating AEAD %N failed\n", + encryption_algorithm_names, alg); + return FALSE; + } + memset(buf, 0xe3, sizeof(buf)); + if (!aead->set_key(aead, chunk_create(buf, aead->get_key_size(aead)))) + { + aead->destroy(aead); + return FALSE; + } + memset(buf, 0, aead->get_iv_size(aead)); + if (!aead->encrypt(aead, chunk_create(buf, 0), chunk_empty, + chunk_create(buf, aead->get_iv_size(aead)), NULL)) + { + aead->destroy(aead); + return FALSE; + } + fprintf(stderr, "attacking %b\n", buf, aead->get_icv_size(aead)); + + res = timeattack(attack_aead, aead, aead->get_icv_size(aead), + iterations, distance); + aead->destroy(aead); + return res; +} + +CALLBACK(attack_signer, bool, + signer_t *signer, u_char *data, size_t len) +{ + return signer->verify_signature(signer, chunk_empty, chunk_create(data, len)); +} + +static bool attack_signers(integrity_algorithm_t alg, + u_int iterations, u_int distance) +{ + u_char buf[64]; + signer_t *signer; + bool res; + + signer = lib->crypto->create_signer(lib->crypto, alg); + if (!signer) + { + fprintf(stderr, "creating signer %N failed\n", + integrity_algorithm_names, alg); + return FALSE; + } + memset(buf, 0xe3, sizeof(buf)); + if (!signer->set_key(signer, chunk_create(buf, signer->get_key_size(signer)))) + { + signer->destroy(signer); + return FALSE; + } + if (!signer->get_signature(signer, chunk_empty, buf)) + { + signer->destroy(signer); + return FALSE; + } + fprintf(stderr, "attacking %b\n", buf, signer->get_block_size(signer)); + + res = timeattack(attack_signer, signer, signer->get_block_size(signer), + iterations, distance); + signer->destroy(signer); + return res; +} + +static bool attack_transform(char *name, u_int iterations, u_int distance) +{ + const proposal_token_t *token; + + token = lib->proposal->get_token(lib->proposal, name); + if (!token) + { + fprintf(stderr, "algorithm '%s' unknown\n", name); + return FALSE; + } + + switch (token->type) + { + case ENCRYPTION_ALGORITHM: + if (encryption_algorithm_is_aead(token->algorithm)) + { + return attack_aeads(token->algorithm, token->keysize / 8, + iterations, distance); + } + fprintf(stderr, "can't attack a crypter\n"); + return FALSE; + case INTEGRITY_ALGORITHM: + return attack_signers(token->algorithm, iterations, distance); + default: + fprintf(stderr, "can't attack a %N\n", transform_type_names, token->type); + return FALSE; + } +} + +int main(int argc, char *argv[]) +{ + library_init(NULL, "timeattack"); + atexit(library_deinit); + lib->plugins->load(lib->plugins, getenv("PLUGINS") ?: PLUGINS); + + if (argc < 3) + { + fprintf(stderr, "usage: %s \n", argv[0]); + fprintf(stderr, " : memeq[1-4] / aead / signer\n"); + fprintf(stderr, " : number of invocations * 1000\n"); + fprintf(stderr, " : time difference in ns for a hit\n"); + fprintf(stderr, " example: %s memeq1 100 500\n", argv[0]); + fprintf(stderr, " example: %s aes128gcm16 100 4000\n", argv[0]); + return 1; + } + if (strpfx(argv[1], "memeq")) + { + return !attack_memeq(argv[1], atoi(argv[2]), atoi(argv[3])); + } + return !attack_transform(argv[1], atoi(argv[2]), atoi(argv[3])); +} From b833963270fbffe3186f5c71c7584c2347a44038 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Sat, 11 Apr 2015 16:44:18 +0200 Subject: [PATCH 2/5] utils: Add a constant time memeq() variant for cryptographic purposes --- scripts/timeattack.c | 9 +++- src/libstrongswan/tests/suites/test_utils.c | 47 +++++++++++++++++++++ src/libstrongswan/utils/utils.c | 19 +++++++++ src/libstrongswan/utils/utils.h | 5 +++ 4 files changed, 79 insertions(+), 1 deletion(-) diff --git a/scripts/timeattack.c b/scripts/timeattack.c index 0a53abae9..3d7ffee7d 100644 --- a/scripts/timeattack.c +++ b/scripts/timeattack.c @@ -196,6 +196,12 @@ CALLBACK(attack_memeq4, bool, return !m; } +CALLBACK(attack_memeq5, bool, + u_char *subj, u_char *data, size_t len) +{ + return memeq_const(subj, data, len); +} + static bool attack_memeq(char *name, u_int iterations, u_int distance) { struct { @@ -206,6 +212,7 @@ static bool attack_memeq(char *name, u_int iterations, u_int distance) { "memeq2", attack_memeq2 }, { "memeq3", attack_memeq3 }, { "memeq4", attack_memeq4 }, + { "memeq5", attack_memeq5 }, }; u_char exp[16]; int i; @@ -350,7 +357,7 @@ int main(int argc, char *argv[]) if (argc < 3) { fprintf(stderr, "usage: %s \n", argv[0]); - fprintf(stderr, " : memeq[1-4] / aead / signer\n"); + fprintf(stderr, " : memeq[1-5] / aead / signer\n"); fprintf(stderr, " : number of invocations * 1000\n"); fprintf(stderr, " : time difference in ns for a hit\n"); fprintf(stderr, " example: %s memeq1 100 500\n", argv[0]); diff --git a/src/libstrongswan/tests/suites/test_utils.c b/src/libstrongswan/tests/suites/test_utils.c index 85a854456..f151fb35e 100644 --- a/src/libstrongswan/tests/suites/test_utils.c +++ b/src/libstrongswan/tests/suites/test_utils.c @@ -306,6 +306,48 @@ START_TEST(test_memxor_aligned) } END_TEST +/******************************************************************************* + * memeq/const + */ + +static struct { + char *a; + char *b; + size_t n; + bool res; +} memeq_data[] = { + {NULL, NULL, 0, TRUE}, + {"a", "b", 0, TRUE}, + {"", "", 1, TRUE}, + {"abcdefgh", "abcdefgh", 8, TRUE}, + {"a", "b", 1, FALSE}, + {"A", "a", 1, FALSE}, + {"\0a", "\0b", 2, FALSE}, + {"abc", "abd", 3, FALSE}, + {"abc", "dbd", 3, FALSE}, + {"abcdefgh", "abcdffgh", 8, FALSE}, + {"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", 52, TRUE}, + {"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyy", 52, FALSE}, + {"bbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", 52, FALSE}, +}; + +START_TEST(test_memeq) +{ + ck_assert(memeq(memeq_data[_i].a, memeq_data[_i].b, + memeq_data[_i].n) == memeq_data[_i].res); +} +END_TEST + +START_TEST(test_memeq_const) +{ + ck_assert(memeq_const(memeq_data[_i].a, memeq_data[_i].b, + memeq_data[_i].n) == memeq_data[_i].res); +} +END_TEST + /******************************************************************************* * memstr */ @@ -779,6 +821,11 @@ Suite *utils_suite_create() tcase_add_test(tc, test_memxor_aligned); suite_add_tcase(s, tc); + tc = tcase_create("memeq"); + tcase_add_loop_test(tc, test_memeq, 0, countof(memeq_data)); + tcase_add_loop_test(tc, test_memeq_const, 0, countof(memeq_data)); + suite_add_tcase(s, tc); + tc = tcase_create("memstr"); tcase_add_loop_test(tc, test_memstr, 0, countof(memstr_data)); suite_add_tcase(s, tc); diff --git a/src/libstrongswan/utils/utils.c b/src/libstrongswan/utils/utils.c index 02a720945..3d5e3dfc9 100644 --- a/src/libstrongswan/utils/utils.c +++ b/src/libstrongswan/utils/utils.c @@ -109,6 +109,25 @@ void memwipe_noinline(void *ptr, size_t n) memwipe_inline(ptr, n); } +/** + * Described in header. + */ +bool memeq_const(const void *x, const void *y, size_t len) +{ + const u_char *a, *b; + u_int bad = 0; + size_t i; + + a = (const u_char*)x; + b = (const u_char*)y; + + for (i = 0; i < len; i++) + { + bad |= a[i] != b[i]; + } + return !bad; +} + /** * Described in header. */ diff --git a/src/libstrongswan/utils/utils.h b/src/libstrongswan/utils/utils.h index 7c48d949f..2675acae8 100644 --- a/src/libstrongswan/utils/utils.h +++ b/src/libstrongswan/utils/utils.h @@ -184,6 +184,11 @@ static inline bool memeq(const void *x, const void *y, size_t len) return memcmp(x, y, len) == 0; } +/** + * Same as memeq(), but with a constant runtime, safe for cryptographic use. + */ +bool memeq_const(const void *x, const void *y, size_t len); + /** * Calling memcpy() with NULL pointers, even with n == 0, results in undefined * behavior according to the C standard. This version is guaranteed to not From 71afe0a5567ff4cc51e536913f5c009700d3dcf8 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Sat, 11 Apr 2015 15:25:21 +0200 Subject: [PATCH 3/5] utils: Use memeq_const() for all cryptographic purposes --- src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_card.c | 3 +-- src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_provider.c | 3 +-- src/libcharon/plugins/eap_md5/eap_md5.c | 3 +-- src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c | 5 ++--- src/libcharon/plugins/eap_sim/eap_sim_peer.c | 3 +-- src/libcharon/plugins/eap_sim_file/eap_sim_file_card.c | 3 +-- src/libradius/radius_message.c | 2 +- src/libstrongswan/crypto/signers/mac_signer.c | 3 +-- src/libstrongswan/plugins/af_alg/af_alg_signer.c | 2 +- src/libstrongswan/plugins/ccm/ccm_aead.c | 2 +- src/libstrongswan/plugins/gcm/gcm_aead.c | 2 +- src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c | 5 ++--- 12 files changed, 14 insertions(+), 22 deletions(-) diff --git a/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_card.c b/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_card.c index a71dae78a..e38ee5b70 100644 --- a/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_card.c +++ b/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_card.c @@ -87,7 +87,7 @@ METHOD(simaka_card_t, get_quintuplet, status_t, { return FAILED; } - if (!memeq(mac, xmac, AKA_MAC_LEN)) + if (!memeq_const(mac, xmac, AKA_MAC_LEN)) { DBG1(DBG_IKE, "received MAC does not match XMAC"); DBG3(DBG_IKE, "MAC %b\nXMAC %b", mac, AKA_MAC_LEN, xmac, AKA_MAC_LEN); @@ -184,4 +184,3 @@ eap_aka_3gpp2_card_t *eap_aka_3gpp2_card_create(eap_aka_3gpp2_functions_t *f) return &this->public; } - diff --git a/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_provider.c b/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_provider.c index 0be122158..f272e1ec8 100644 --- a/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_provider.c +++ b/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_provider.c @@ -158,7 +158,7 @@ METHOD(simaka_provider_t, resync, bool, { return FALSE; } - if (!memeq(macs, xmacs, AKA_MAC_LEN)) + if (!memeq_const(macs, xmacs, AKA_MAC_LEN)) { DBG1(DBG_IKE, "received MACS does not match XMACS"); DBG3(DBG_IKE, "MACS %b XMACS %b", @@ -205,4 +205,3 @@ eap_aka_3gpp2_provider_t *eap_aka_3gpp2_provider_create( return &this->public; } - diff --git a/src/libcharon/plugins/eap_md5/eap_md5.c b/src/libcharon/plugins/eap_md5/eap_md5.c index b2640d104..d314e7a9e 100644 --- a/src/libcharon/plugins/eap_md5/eap_md5.c +++ b/src/libcharon/plugins/eap_md5/eap_md5.c @@ -193,7 +193,7 @@ METHOD(eap_method_t, process_server, status_t, } response = chunk_create(data.ptr + 6, data.ptr[5]); if (response.len < expected.len || - !memeq(response.ptr, expected.ptr, expected.len)) + !memeq_const(response.ptr, expected.ptr, expected.len)) { chunk_free(&expected); DBG1(DBG_IKE, "EAP-MD5 verification failed"); @@ -299,4 +299,3 @@ eap_md5_t *eap_md5_create_peer(identification_t *server, identification_t *peer) return &this->public; } - diff --git a/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c b/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c index 511506869..688b816ca 100644 --- a/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c +++ b/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c @@ -1087,8 +1087,8 @@ static status_t process_server_response(private_eap_mschapv2_t *this, userid->destroy(userid); chunk_clear(&nt_hash); - if (memeq(res->response.nt_response, this->nt_response.ptr, - this->nt_response.len)) + if (memeq_const(res->response.nt_response, this->nt_response.ptr, + this->nt_response.len)) { chunk_t hex; char msg[AUTH_RESPONSE_LEN + sizeof(SUCCESS_MESSAGE)]; @@ -1267,4 +1267,3 @@ eap_mschapv2_t *eap_mschapv2_create_peer(identification_t *server, identificatio return &this->public; } - diff --git a/src/libcharon/plugins/eap_sim/eap_sim_peer.c b/src/libcharon/plugins/eap_sim/eap_sim_peer.c index ff96e9279..2637b4314 100644 --- a/src/libcharon/plugins/eap_sim/eap_sim_peer.c +++ b/src/libcharon/plugins/eap_sim/eap_sim_peer.c @@ -310,7 +310,7 @@ static status_t process_challenge(private_eap_sim_peer_t *this, /* excepting two or three RAND, each 16 bytes. We require two valid * and different RANDs */ if ((rands.len != 2 * SIM_RAND_LEN && rands.len != 3 * SIM_RAND_LEN) || - memeq(rands.ptr, rands.ptr + SIM_RAND_LEN, SIM_RAND_LEN)) + memeq_const(rands.ptr, rands.ptr + SIM_RAND_LEN, SIM_RAND_LEN)) { DBG1(DBG_IKE, "no valid AT_RAND received"); if (!create_client_error(this, SIM_INSUFFICIENT_CHALLENGES, out)) @@ -734,4 +734,3 @@ eap_sim_peer_t *eap_sim_peer_create(identification_t *server, return &this->public; } - diff --git a/src/libcharon/plugins/eap_sim_file/eap_sim_file_card.c b/src/libcharon/plugins/eap_sim_file/eap_sim_file_card.c index bd47e5085..0a6aec083 100644 --- a/src/libcharon/plugins/eap_sim_file/eap_sim_file_card.c +++ b/src/libcharon/plugins/eap_sim_file/eap_sim_file_card.c @@ -52,7 +52,7 @@ METHOD(simaka_card_t, get_triplet, bool, c_rand, SIM_RAND_LEN, c_sres, SIM_SRES_LEN, c_kc, SIM_KC_LEN); if (id->matches(id, cand)) { - if (memeq(c_rand, rand, SIM_RAND_LEN)) + if (memeq_const(c_rand, rand, SIM_RAND_LEN)) { DBG2(DBG_CFG, " => triplet matches"); memcpy(sres, c_sres, SIM_SRES_LEN); @@ -105,4 +105,3 @@ eap_sim_file_card_t *eap_sim_file_card_create(eap_sim_file_triplets_t *triplets) return &this->public; } - diff --git a/src/libradius/radius_message.c b/src/libradius/radius_message.c index 3905a06c7..e6abfe2c2 100644 --- a/src/libradius/radius_message.c +++ b/src/libradius/radius_message.c @@ -536,7 +536,7 @@ METHOD(radius_message_t, verify, bool, /* verify Response-Authenticator */ if (!hasher->get_hash(hasher, msg, NULL) || !hasher->get_hash(hasher, secret, buf) || - !memeq(buf, res_auth, HASH_SIZE_MD5)) + !memeq_const(buf, res_auth, HASH_SIZE_MD5)) { DBG1(DBG_CFG, "RADIUS Response-Authenticator verification failed"); return FALSE; diff --git a/src/libstrongswan/crypto/signers/mac_signer.c b/src/libstrongswan/crypto/signers/mac_signer.c index 7c52aa305..1094c4473 100644 --- a/src/libstrongswan/crypto/signers/mac_signer.c +++ b/src/libstrongswan/crypto/signers/mac_signer.c @@ -85,7 +85,7 @@ METHOD(signer_t, verify_signature, bool, return FALSE; } return this->mac->get_mac(this->mac, data, mac) && - memeq(signature.ptr, mac, this->truncation); + memeq_const(signature.ptr, mac, this->truncation); } METHOD(signer_t, get_key_size, size_t, @@ -136,4 +136,3 @@ signer_t *mac_signer_create(mac_t *mac, size_t len) return &this->public; } - diff --git a/src/libstrongswan/plugins/af_alg/af_alg_signer.c b/src/libstrongswan/plugins/af_alg/af_alg_signer.c index 9ad01103a..1403144ab 100644 --- a/src/libstrongswan/plugins/af_alg/af_alg_signer.c +++ b/src/libstrongswan/plugins/af_alg/af_alg_signer.c @@ -138,7 +138,7 @@ METHOD(signer_t, verify_signature, bool, { return FALSE; } - return memeq(signature.ptr, sig, signature.len); + return memeq_const(signature.ptr, sig, signature.len); } METHOD(signer_t, get_key_size, size_t, diff --git a/src/libstrongswan/plugins/ccm/ccm_aead.c b/src/libstrongswan/plugins/ccm/ccm_aead.c index 6d4b2e13c..676d67681 100644 --- a/src/libstrongswan/plugins/ccm/ccm_aead.c +++ b/src/libstrongswan/plugins/ccm/ccm_aead.c @@ -256,7 +256,7 @@ static bool verify_icv(private_ccm_aead_t *this, chunk_t plain, chunk_t assoc, char buf[this->icv_size]; return create_icv(this, plain, assoc, iv, buf) && - memeq(buf, icv, this->icv_size); + memeq_const(buf, icv, this->icv_size); } METHOD(aead_t, encrypt, bool, diff --git a/src/libstrongswan/plugins/gcm/gcm_aead.c b/src/libstrongswan/plugins/gcm/gcm_aead.c index 4ab17017f..6e1694a34 100644 --- a/src/libstrongswan/plugins/gcm/gcm_aead.c +++ b/src/libstrongswan/plugins/gcm/gcm_aead.c @@ -276,7 +276,7 @@ static bool verify_icv(private_gcm_aead_t *this, chunk_t assoc, chunk_t crypt, char tmp[this->icv_size]; return create_icv(this, assoc, crypt, j, tmp) && - memeq(tmp, icv, this->icv_size); + memeq_const(tmp, icv, this->icv_size); } METHOD(aead_t, encrypt, bool, diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c b/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c index ad659e4d7..e738908e2 100644 --- a/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c +++ b/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c @@ -187,7 +187,7 @@ static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this, " %u bytes", em.len, data.len); goto end; } - success = memeq(em.ptr, data.ptr, data.len); + success = memeq_const(em.ptr, data.ptr, data.len); } else { /* IKEv2 and X.509 certificate signatures */ @@ -258,7 +258,7 @@ static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this, goto end_parser; } hasher->destroy(hasher); - success = memeq(object.ptr, hash.ptr, hash.len); + success = memeq_const(object.ptr, hash.ptr, hash.len); free(hash.ptr); break; } @@ -500,4 +500,3 @@ gmp_rsa_public_key_t *gmp_rsa_public_key_load(key_type_t type, va_list args) return &this->public; } - From 9d6e952201a1292087dc42b16a3055a99dbee7ba Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Sat, 11 Apr 2015 15:55:26 +0200 Subject: [PATCH 4/5] utils: Add a constant time chunk_equals() variant for cryptographic purposes --- scripts/timeattack.c | 48 ++++++++++++++++++++- src/libstrongswan/tests/suites/test_chunk.c | 27 ++++++++++++ src/libstrongswan/utils/chunk.h | 13 ++++++ 3 files changed, 87 insertions(+), 1 deletion(-) diff --git a/scripts/timeattack.c b/scripts/timeattack.c index 3d7ffee7d..ef00e8c4e 100644 --- a/scripts/timeattack.c +++ b/scripts/timeattack.c @@ -235,6 +235,48 @@ static bool attack_memeq(char *name, u_int iterations, u_int distance) return FALSE; } +CALLBACK(attack_chunk1, bool, + u_char *subj, u_char *data, size_t len) +{ + return chunk_equals(chunk_create(subj, len), chunk_create(data, len)); +} + +CALLBACK(attack_chunk2, bool, + u_char *subj, u_char *data, size_t len) +{ + return chunk_equals_const(chunk_create(subj, len), chunk_create(data, len)); +} + +static bool attack_chunk(char *name, u_int iterations, u_int distance) +{ + struct { + char *name; + attackfn_t fn; + } attacks[] = { + { "chunk1", attack_chunk1 }, + { "chunk2", attack_chunk2 }, + }; + u_char exp[16]; + int i; + + srandom(time(NULL)); + for (i = 0; i < sizeof(exp); i++) + { + exp[i] = random(); + } + fprintf(stderr, "attacking %b\n", exp, sizeof(exp)); + + for (i = 0; i < countof(attacks); i++) + { + if (streq(name, attacks[i].name)) + { + return timeattack(attacks[i].fn, exp, sizeof(exp), + iterations, distance); + } + } + return FALSE; +} + CALLBACK(attack_aead, bool, aead_t *aead, u_char *data, size_t len) { @@ -357,7 +399,7 @@ int main(int argc, char *argv[]) if (argc < 3) { fprintf(stderr, "usage: %s \n", argv[0]); - fprintf(stderr, " : memeq[1-5] / aead / signer\n"); + fprintf(stderr, " : memeq[1-5] / chunk[1-2] / aead / signer\n"); fprintf(stderr, " : number of invocations * 1000\n"); fprintf(stderr, " : time difference in ns for a hit\n"); fprintf(stderr, " example: %s memeq1 100 500\n", argv[0]); @@ -368,5 +410,9 @@ int main(int argc, char *argv[]) { return !attack_memeq(argv[1], atoi(argv[2]), atoi(argv[3])); } + if (strpfx(argv[1], "chunk")) + { + return !attack_chunk(argv[1], atoi(argv[2]), atoi(argv[3])); + } return !attack_transform(argv[1], atoi(argv[2]), atoi(argv[3])); } diff --git a/src/libstrongswan/tests/suites/test_chunk.c b/src/libstrongswan/tests/suites/test_chunk.c index b5d23658d..312a187ac 100644 --- a/src/libstrongswan/tests/suites/test_chunk.c +++ b/src/libstrongswan/tests/suites/test_chunk.c @@ -60,6 +60,32 @@ START_TEST(test_chunk_equals) } END_TEST +/******************************************************************************* + * equals_const + */ + +START_TEST(test_chunk_equals_const) +{ + chunk_t chunk = chunk_from_str("chunk"); + chunk_t chunk_a, chunk_b; + + chunk_a = chunk_empty; + chunk_b = chunk_empty; + ck_assert(!chunk_equals_const(chunk_a, chunk_b)); + + chunk_a = chunk; + ck_assert(!chunk_equals_const(chunk_a, chunk_b)); + chunk_b = chunk; + ck_assert(chunk_equals_const(chunk_a, chunk_b)); + + chunk_b = chunk_from_str("asdf"); + ck_assert(!chunk_equals_const(chunk_a, chunk_b)); + + chunk_b = chunk_from_str("chunk"); + ck_assert(chunk_equals_const(chunk_a, chunk_b)); +} +END_TEST + /******************************************************************************* * chunk_compare test */ @@ -1013,6 +1039,7 @@ Suite *chunk_suite_create() tc = tcase_create("equals"); tcase_add_test(tc, test_chunk_equals); + tcase_add_test(tc, test_chunk_equals_const); suite_add_tcase(s, tc); tc = tcase_create("chunk_compare"); diff --git a/src/libstrongswan/utils/chunk.h b/src/libstrongswan/utils/chunk.h index 48405b77e..2ec7f7543 100644 --- a/src/libstrongswan/utils/chunk.h +++ b/src/libstrongswan/utils/chunk.h @@ -309,6 +309,19 @@ static inline bool chunk_equals(chunk_t a, chunk_t b) a.len == b.len && memeq(a.ptr, b.ptr, a.len); } +/** + * Compare two chunks for equality, constant time for cryptographic purposes. + * + * Note that this function is constant time only for chunks with the same + * length, i.e. it does not protect against guessing the length of one of the + * chunks. + */ +static inline bool chunk_equals_const(chunk_t a, chunk_t b) +{ + return a.ptr != NULL && b.ptr != NULL && + a.len == b.len && memeq_const(a.ptr, b.ptr, a.len); +} + /** * Compare two chunks (given as pointers) for equality (useful as callback), * NULL chunks are never equal. From 161a015782dbd7acf291f621d50cde24a6ed813d Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Sat, 11 Apr 2015 15:56:42 +0200 Subject: [PATCH 5/5] utils: Use chunk_equals_const() for all cryptographic purposes --- src/libcharon/encoding/message.c | 2 +- src/libcharon/network/receiver.c | 2 +- src/libcharon/plugins/eap_aka/eap_aka_server.c | 5 ++--- src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c | 2 +- src/libcharon/plugins/eap_sim/eap_sim_server.c | 3 +-- src/libcharon/plugins/xauth_generic/xauth_generic.c | 2 +- .../sa/ikev1/authenticators/psk_v1_authenticator.c | 2 +- .../sa/ikev2/authenticators/eap_authenticator.c | 2 +- .../sa/ikev2/authenticators/psk_authenticator.c | 2 +- src/libcharon/sa/ikev2/tasks/ike_mobike.c | 2 +- .../plugins/imv_attestation/imv_attestation_process.c | 7 +++---- src/libimcv/pts/components/ita/ita_comp_ima.c | 9 ++++----- src/libimcv/pts/components/ita/ita_comp_tboot.c | 3 +-- src/libimcv/pts/components/ita/ita_comp_tgrub.c | 2 +- src/libimcv/pts/pts_database.c | 4 ++-- src/libimcv/pts/pts_file_meas.c | 8 ++++---- src/libpttls/sasl/sasl_plain/sasl_plain.c | 2 +- src/libstrongswan/plugins/openssl/openssl_pkcs7.c | 2 +- .../plugins/openssl/openssl_rsa_public_key.c | 2 +- src/libstrongswan/plugins/pkcs12/pkcs12_decode.c | 2 +- src/libstrongswan/plugins/pkcs7/pkcs7_signed_data.c | 2 +- src/libtls/tls_peer.c | 2 +- src/libtls/tls_server.c | 2 +- 23 files changed, 33 insertions(+), 38 deletions(-) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 0a596ffb0..e51c94691 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -2625,7 +2625,7 @@ METHOD(message_t, parse_body, status_t, other_hash = hash_payload->get_hash(hash_payload); DBG3(DBG_ENC, "HASH received %B\nHASH expected %B", &other_hash, &hash); - if (!chunk_equals(hash, other_hash)) + if (!chunk_equals_const(hash, other_hash)) { DBG1(DBG_ENC, "received HASH payload does not match"); chunk_free(&hash); diff --git a/src/libcharon/network/receiver.c b/src/libcharon/network/receiver.c index 5ce9471bd..6902c4847 100644 --- a/src/libcharon/network/receiver.c +++ b/src/libcharon/network/receiver.c @@ -247,7 +247,7 @@ static bool cookie_verify(private_receiver_t *this, message_t *message, { return FALSE; } - if (chunk_equals(reference, cookie)) + if (chunk_equals_const(reference, cookie)) { chunk_free(&reference); return TRUE; diff --git a/src/libcharon/plugins/eap_aka/eap_aka_server.c b/src/libcharon/plugins/eap_aka/eap_aka_server.c index eba7af874..04bfc170b 100644 --- a/src/libcharon/plugins/eap_aka/eap_aka_server.c +++ b/src/libcharon/plugins/eap_aka/eap_aka_server.c @@ -425,7 +425,7 @@ static status_t process_challenge(private_eap_aka_server_t *this, enumerator->destroy(enumerator); /* compare received RES against stored XRES */ - if (!chunk_equals(res, this->xres)) + if (!chunk_equals_const(res, this->xres)) { DBG1(DBG_IKE, "received RES does not match XRES"); return FAILED; @@ -486,7 +486,7 @@ static status_t process_reauthentication(private_eap_aka_server_t *this, this->crypto->clear_keys(this->crypto); return challenge(this, out); } - if (!chunk_equals(counter, this->counter)) + if (!chunk_equals_const(counter, this->counter)) { DBG1(DBG_IKE, "received counter does not match"); return FAILED; @@ -730,4 +730,3 @@ eap_aka_server_t *eap_aka_server_create(identification_t *server, return &this->public; } - diff --git a/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c b/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c index 688b816ca..f7f39f984 100644 --- a/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c +++ b/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c @@ -812,7 +812,7 @@ static status_t process_peer_success(private_eap_mschapv2_t *this, goto error; } - if (!chunk_equals(this->auth_response, auth_string)) + if (!chunk_equals_const(this->auth_response, auth_string)) { DBG1(DBG_IKE, "EAP-MS-CHAPv2 verification failed"); goto error; diff --git a/src/libcharon/plugins/eap_sim/eap_sim_server.c b/src/libcharon/plugins/eap_sim/eap_sim_server.c index f22266bda..5aa54db3e 100644 --- a/src/libcharon/plugins/eap_sim/eap_sim_server.c +++ b/src/libcharon/plugins/eap_sim/eap_sim_server.c @@ -262,7 +262,7 @@ static status_t process_reauthentication(private_eap_sim_server_t *this, this->crypto->clear_keys(this->crypto); return initiate(this, out); } - if (!chunk_equals(counter, this->counter)) + if (!chunk_equals_const(counter, this->counter)) { DBG1(DBG_IKE, "received counter does not match"); return FAILED; @@ -644,4 +644,3 @@ eap_sim_server_t *eap_sim_server_create(identification_t *server, return &this->public; } - diff --git a/src/libcharon/plugins/xauth_generic/xauth_generic.c b/src/libcharon/plugins/xauth_generic/xauth_generic.c index c37da0cb0..e65d1a1fe 100644 --- a/src/libcharon/plugins/xauth_generic/xauth_generic.c +++ b/src/libcharon/plugins/xauth_generic/xauth_generic.c @@ -180,7 +180,7 @@ METHOD(xauth_method_t, process_server, status_t, SHARED_EAP, this->server, this->peer); while (enumerator->enumerate(enumerator, &shared, NULL, NULL)) { - if (chunk_equals(shared->get_key(shared), pass)) + if (chunk_equals_const(shared->get_key(shared), pass)) { status = SUCCESS; break; diff --git a/src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.c b/src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.c index bb187f07c..5debeeb37 100644 --- a/src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.c +++ b/src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.c @@ -124,7 +124,7 @@ METHOD(authenticator_t, process, status_t, return FAILED; } free(dh.ptr); - if (chunk_equals(hash, hash_payload->get_hash(hash_payload))) + if (chunk_equals_const(hash, hash_payload->get_hash(hash_payload))) { free(hash.ptr); if (!this->hybrid) diff --git a/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c index ebef31930..f1442096c 100644 --- a/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c +++ b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c @@ -464,7 +464,7 @@ static bool verify_auth(private_eap_authenticator_t *this, message_t *message, return FALSE; } recv_auth_data = auth_payload->get_data(auth_payload); - if (!auth_data.len || !chunk_equals(auth_data, recv_auth_data)) + if (!auth_data.len || !chunk_equals_const(auth_data, recv_auth_data)) { DBG1(DBG_IKE, "verification of AUTH payload with%s EAP MSK failed", this->msk.ptr ? "" : "out"); diff --git a/src/libcharon/sa/ikev2/authenticators/psk_authenticator.c b/src/libcharon/sa/ikev2/authenticators/psk_authenticator.c index c6a4b6ba4..535581068 100644 --- a/src/libcharon/sa/ikev2/authenticators/psk_authenticator.c +++ b/src/libcharon/sa/ikev2/authenticators/psk_authenticator.c @@ -123,7 +123,7 @@ METHOD(authenticator_t, process, status_t, { continue; } - if (auth_data.len && chunk_equals(auth_data, recv_auth_data)) + if (auth_data.len && chunk_equals_const(auth_data, recv_auth_data)) { DBG1(DBG_IKE, "authentication of '%Y' with %N successful", other_id, auth_method_names, AUTH_PSK); diff --git a/src/libcharon/sa/ikev2/tasks/ike_mobike.c b/src/libcharon/sa/ikev2/tasks/ike_mobike.c index 6295d7960..11b0bb281 100644 --- a/src/libcharon/sa/ikev2/tasks/ike_mobike.c +++ b/src/libcharon/sa/ikev2/tasks/ike_mobike.c @@ -537,7 +537,7 @@ METHOD(task_t, process_i, status_t, cookie2 = this->cookie2; this->cookie2 = chunk_empty; process_payloads(this, message); - if (!chunk_equals(cookie2, this->cookie2)) + if (!chunk_equals_const(cookie2, this->cookie2)) { chunk_free(&cookie2); DBG1(DBG_IKE, "COOKIE2 mismatch, closing IKE_SA"); diff --git a/src/libimcv/plugins/imv_attestation/imv_attestation_process.c b/src/libimcv/plugins/imv_attestation/imv_attestation_process.c index fbeb6618e..c3e053d9b 100644 --- a/src/libimcv/plugins/imv_attestation/imv_attestation_process.c +++ b/src/libimcv/plugins/imv_attestation/imv_attestation_process.c @@ -181,7 +181,7 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg, DBG1(DBG_IMV, "verifying AIK with keyid %#B", &keyid); keyid_hex = chunk_to_hex(keyid, NULL, FALSE); if (session->get_device_id(session, &device_id) && - chunk_equals(keyid_hex, device_id)) + chunk_equals_const(keyid_hex, device_id)) { trusted = session->get_device_trust(session); } @@ -290,7 +290,7 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg, /* check hashes from database against measurements */ e = pts_db->create_file_hash_enumerator(pts_db, - pts->get_platform_id(pts), + pts->get_platform_id(pts), algo, is_dir, arg_int); if (!e) { @@ -446,7 +446,7 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg, return FALSE; } - if (!chunk_equals(pcr_comp, pcr_composite)) + if (!chunk_equals_const(pcr_comp, pcr_composite)) { DBG1(DBG_IMV, "received PCR Composite does not match " "constructed one"); @@ -564,4 +564,3 @@ quote_error: } return TRUE; } - diff --git a/src/libimcv/pts/components/ita/ita_comp_ima.c b/src/libimcv/pts/components/ita/ita_comp_ima.c index 3f92b04b1..448ca9ffb 100644 --- a/src/libimcv/pts/components/ita/ita_comp_ima.c +++ b/src/libimcv/pts/components/ita/ita_comp_ima.c @@ -307,7 +307,7 @@ static bool check_boot_aggregate(pts_pcr_t *pcrs, chunk_t measurement, } if (pcr_ok) { - success = chunk_equals(boot_aggregate, measurement); + success = chunk_equals_const(boot_aggregate, measurement); DBG1(DBG_PTS, "boot aggregate value is %scorrect", success ? "":"in"); return success; @@ -693,7 +693,7 @@ METHOD(pts_component_t, verify, status_t, status = FAILED; break; } - if (chunk_equals(measurement, hash)) + if (chunk_equals_const(measurement, hash)) { status = SUCCESS; break; @@ -748,7 +748,7 @@ METHOD(pts_component_t, verify, status_t, has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after); if (has_pcr_info) { - if (!chunk_equals(pcr_before, pcrs->get(pcrs, pcr))) + if (!chunk_equals_const(pcr_before, pcrs->get(pcrs, pcr))) { DBG1(DBG_PTS, "PCR %2u: pcr_before is not equal to register value", pcr); @@ -876,7 +876,7 @@ METHOD(pts_component_t, destroy, void, DESTROY_IF(this->bios_list); DESTROY_IF(this->ima_list); this->name->destroy(this->name); - + free(this); } } @@ -911,4 +911,3 @@ pts_component_t *pts_ita_comp_ima_create(uint32_t depth, return &this->public; } - diff --git a/src/libimcv/pts/components/ita/ita_comp_tboot.c b/src/libimcv/pts/components/ita/ita_comp_tboot.c index ce318ec84..3d990f6f2 100644 --- a/src/libimcv/pts/components/ita/ita_comp_tboot.c +++ b/src/libimcv/pts/components/ita/ita_comp_tboot.c @@ -249,7 +249,7 @@ METHOD(pts_component_t, verify, status_t, has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after); if (has_pcr_info) { - if (!chunk_equals(pcr_before, pcrs->get(pcrs, extended_pcr))) + if (!chunk_equals_const(pcr_before, pcrs->get(pcrs, extended_pcr))) { DBG1(DBG_PTS, "PCR %2u: pcr_before is not equal to register value", extended_pcr); @@ -354,4 +354,3 @@ pts_component_t *pts_ita_comp_tboot_create(u_int32_t depth, return &this->public; } - diff --git a/src/libimcv/pts/components/ita/ita_comp_tgrub.c b/src/libimcv/pts/components/ita/ita_comp_tgrub.c index 097e4c89c..e9555726a 100644 --- a/src/libimcv/pts/components/ita/ita_comp_tgrub.c +++ b/src/libimcv/pts/components/ita/ita_comp_tgrub.c @@ -141,7 +141,7 @@ METHOD(pts_component_t, verify, status_t, has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after); if (has_pcr_info) { - if (!chunk_equals(pcr_before, pcrs->get(pcrs, extended_pcr))) + if (!chunk_equals_const(pcr_before, pcrs->get(pcrs, extended_pcr))) { DBG1(DBG_PTS, "PCR %2u: pcr_before is not equal to pcr value"); } diff --git a/src/libimcv/pts/pts_database.c b/src/libimcv/pts/pts_database.c index d7b85c138..1a4c4212d 100644 --- a/src/libimcv/pts/pts_database.c +++ b/src/libimcv/pts/pts_database.c @@ -187,7 +187,7 @@ METHOD(pts_database_t, add_file_measurement, status_t, } if (e->enumerate(e, &hash_id, &hash_value)) { - if (!chunk_equals(measurement, hash_value)) + if (!chunk_equals_const(measurement, hash_value)) { /* update hash measurement value */ if (this->db->execute(this->db, &hash_id, @@ -289,7 +289,7 @@ METHOD(pts_database_t, check_comp_measurement, status_t, while (e->enumerate(e, &hash)) { - if (chunk_equals(hash, measurement)) + if (chunk_equals_const(hash, measurement)) { status = SUCCESS; break; diff --git a/src/libimcv/pts/pts_file_meas.c b/src/libimcv/pts/pts_file_meas.c index 478892aea..966d54ba2 100644 --- a/src/libimcv/pts/pts_file_meas.c +++ b/src/libimcv/pts/pts_file_meas.c @@ -133,7 +133,7 @@ METHOD(pts_file_meas_t, check, bool, { while (e->enumerate(e, &hash)) { - if (chunk_equals(entry->measurement, hash)) + if (chunk_equals_const(entry->measurement, hash)) { status = SUCCESS; break; @@ -223,7 +223,7 @@ METHOD(pts_file_meas_t, verify, bool, } } - /* no PTS measurement returned for this filename */ + /* no PTS measurement returned for this filename */ if (!found) { success = FALSE; @@ -234,7 +234,7 @@ METHOD(pts_file_meas_t, verify, bool, if (found && !match) { - if (chunk_equals(measurement, entry->measurement)) + if (chunk_equals_const(measurement, entry->measurement)) { match = TRUE; DBG2(DBG_PTS, " %#B for '%s' is ok", @@ -252,7 +252,7 @@ METHOD(pts_file_meas_t, verify, bool, &entry->measurement, entry->filename); enumerator->destroy(enumerator); } - + return success; } diff --git a/src/libpttls/sasl/sasl_plain/sasl_plain.c b/src/libpttls/sasl/sasl_plain/sasl_plain.c index 019c1b011..b2d30e680 100644 --- a/src/libpttls/sasl/sasl_plain/sasl_plain.c +++ b/src/libpttls/sasl/sasl_plain/sasl_plain.c @@ -86,7 +86,7 @@ METHOD(sasl_mechanism_t, process_server, status_t, DBG1(DBG_CFG, "no shared secret found for '%Y'", this->client); return FAILED; } - if (!chunk_equals(shared->get_key(shared), password)) + if (!chunk_equals_const(shared->get_key(shared), password)) { DBG1(DBG_CFG, "shared secret for '%Y' does not match", this->client); shared->destroy(shared); diff --git a/src/libstrongswan/plugins/openssl/openssl_pkcs7.c b/src/libstrongswan/plugins/openssl/openssl_pkcs7.c index 9c3c4040c..891e829ae 100644 --- a/src/libstrongswan/plugins/openssl/openssl_pkcs7.c +++ b/src/libstrongswan/plugins/openssl/openssl_pkcs7.c @@ -305,7 +305,7 @@ static bool verify_digest(CMS_ContentInfo *cms, CMS_SignerInfo *si, int hash_oid } hasher->destroy(hasher); - if (!chunk_equals(digest, hash)) + if (!chunk_equals_const(digest, hash)) { free(hash.ptr); DBG1(DBG_LIB, "invalid messageDigest"); diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c index 9748e28f2..aa54d3bbd 100644 --- a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c @@ -74,7 +74,7 @@ static bool verify_emsa_pkcs1_signature(private_openssl_rsa_public_key_t *this, RSA_PKCS1_PADDING); if (len != -1) { - valid = chunk_equals(data, chunk_create(buf, len)); + valid = chunk_equals_const(data, chunk_create(buf, len)); } free(buf); } diff --git a/src/libstrongswan/plugins/pkcs12/pkcs12_decode.c b/src/libstrongswan/plugins/pkcs12/pkcs12_decode.c index 379f24796..4441b278f 100644 --- a/src/libstrongswan/plugins/pkcs12/pkcs12_decode.c +++ b/src/libstrongswan/plugins/pkcs12/pkcs12_decode.c @@ -356,7 +356,7 @@ static bool verify_mac(hash_algorithm_t hash, chunk_t salt, { break; } - if (chunk_equals(mac, calculated)) + if (chunk_equals_const(mac, calculated)) { success = TRUE; break; diff --git a/src/libstrongswan/plugins/pkcs7/pkcs7_signed_data.c b/src/libstrongswan/plugins/pkcs7/pkcs7_signed_data.c index 48fb5e6a4..d224ef3aa 100644 --- a/src/libstrongswan/plugins/pkcs7/pkcs7_signed_data.c +++ b/src/libstrongswan/plugins/pkcs7/pkcs7_signed_data.c @@ -269,7 +269,7 @@ METHOD(enumerator_t, enumerate, bool, hasher->destroy(hasher); DBG3(DBG_LIB, "hash: %B", &hash); - valid = chunk_equals(chunk, hash); + valid = chunk_equals_const(chunk, hash); free(hash.ptr); if (!valid) { diff --git a/src/libtls/tls_peer.c b/src/libtls/tls_peer.c index e6be36b7b..86b94ab85 100644 --- a/src/libtls/tls_peer.c +++ b/src/libtls/tls_peer.c @@ -641,7 +641,7 @@ static status_t process_finished(private_tls_peer_t *this, bio_reader_t *reader) this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); return NEED_MORE; } - if (!chunk_equals(received, chunk_from_thing(buf))) + if (!chunk_equals_const(received, chunk_from_thing(buf))) { DBG1(DBG_TLS, "received server finished invalid"); this->alert->add(this->alert, TLS_FATAL, TLS_DECRYPT_ERROR); diff --git a/src/libtls/tls_server.c b/src/libtls/tls_server.c index b1a214f7f..f9295a160 100644 --- a/src/libtls/tls_server.c +++ b/src/libtls/tls_server.c @@ -607,7 +607,7 @@ static status_t process_finished(private_tls_server_t *this, this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); return NEED_MORE; } - if (!chunk_equals(received, chunk_from_thing(buf))) + if (!chunk_equals_const(received, chunk_from_thing(buf))) { DBG1(DBG_TLS, "received client finished invalid"); this->alert->add(this->alert, TLS_FATAL, TLS_DECRYPT_ERROR);