From ca669fc1b57cdf119f5bf3af9607b9e1374faef3 Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Sun, 2 Feb 2020 08:22:58 +0200 Subject: [PATCH] Add CRC32 checksums to all message Calculate CRC32 checksum of the whole ZRTP packet and add it at the end of packet and verify the checksum when a packet is received. If the verification fails, the packet is simply discarded --- src/crypto/crypto.cc | 21 ++++++++++ src/crypto/crypto.hh | 6 +++ src/mzrtp/commit.cc | 8 +++- src/mzrtp/commit.hh | 1 + src/mzrtp/confack.cc | 3 ++ src/mzrtp/confack.hh | 1 + src/mzrtp/confirm.cc | 4 ++ src/mzrtp/defines.hh | 1 + src/mzrtp/dh_kxchng.cc | 5 ++- src/mzrtp/dh_kxchng.hh | 2 + src/mzrtp/hello.cc | 30 ++++++++----- src/mzrtp/hello.hh | 2 + src/mzrtp/hello_ack.cc | 4 ++ src/mzrtp/hello_ack.hh | 3 +- src/mzrtp/receiver.cc | 95 +++++++++++++++++++++++++++++++++++------- src/zrtp.cc | 12 ++++-- 16 files changed, 164 insertions(+), 34 deletions(-) diff --git a/src/crypto/crypto.cc b/src/crypto/crypto.cc index a012ce8..ba4b220 100644 --- a/src/crypto/crypto.cc +++ b/src/crypto/crypto.cc @@ -217,3 +217,24 @@ void kvz_rtp::crypto::random::generate_random(uint8_t *out, size_t len) /* do not block ever */ CryptoPP::OS_GenerateRandomBlock(false, out, len); } + +/* ***************** crc32 ***************** */ + +void kvz_rtp::crypto::crc32::get_crc32(uint8_t *input, size_t len, uint32_t *output) +{ + CryptoPP::CRC32 crc32; + + crc32.Update(input, len); + crc32.TruncatedFinal((uint8_t *)output, sizeof(uint32_t)); +} + +bool kvz_rtp::crypto::crc32::verify_crc32(uint8_t *input, size_t len, uint32_t old_crc) +{ + CryptoPP::CRC32 crc32; + uint32_t new_crc; + + crc32.Update(input, len); + crc32.TruncatedFinal((uint8_t *)&new_crc, sizeof(uint32_t)); + + return new_crc == old_crc; +} diff --git a/src/crypto/crypto.hh b/src/crypto/crypto.hh index 129e744..1d1a035 100644 --- a/src/crypto/crypto.hh +++ b/src/crypto/crypto.hh @@ -8,6 +8,7 @@ #include "crypto/3rdparty/cryptopp/modes.h" #include "crypto/3rdparty/cryptopp/osrng.h" #include "crypto/3rdparty/cryptopp/sha.h" +#include "crypto/3rdparty/cryptopp/crc.h" namespace kvz_rtp { @@ -120,5 +121,10 @@ namespace kvz_rtp { namespace random { void generate_random(uint8_t *out, size_t len); }; + + namespace crc32 { + void get_crc32(uint8_t *input, size_t len, uint32_t *output); + bool verify_crc32(uint8_t *input, size_t len, uint32_t old_crc); + }; }; }; diff --git a/src/mzrtp/commit.cc b/src/mzrtp/commit.cc index ee9d89d..03663e6 100644 --- a/src/mzrtp/commit.cc +++ b/src/mzrtp/commit.cc @@ -11,7 +11,7 @@ kvz_rtp::zrtp_msg::commit::commit(zrtp_session_t& session) { /* temporary storage for the full hmac hash */ - uint8_t mac_full[32]; + uint8_t mac_full[32] = { 0 }; LOG_DEBUG("Create ZRTP Commit message!"); @@ -44,13 +44,17 @@ kvz_rtp::zrtp_msg::commit::commit(zrtp_session_t& session) msg->auth_tag_type = session.auth_tag_type; msg->key_agreement_type = session.key_agreement_type; + /* Calculate truncated HMAC-SHA256 for the Commit Message */ auto hmac_sha256 = kvz_rtp::crypto::hmac::sha256(session.hashes[1], 32); - hmac_sha256.update((uint8_t *)frame_, len_ - 8); + hmac_sha256.update((uint8_t *)frame_, len_ - 8 - 4); hmac_sha256.final(mac_full); memcpy(&msg->mac, mac_full, sizeof(uint64_t)); + /* Calculate CRC32 for the whole ZRTP packet */ + kvz_rtp::crypto::crc32::get_crc32((uint8_t *)frame_, len_ - 4, &msg->crc); + /* Finally make a copy of the message and save it for later use */ session.l_msg.commit.first = len_; session.l_msg.commit.second = (kvz_rtp::zrtp_msg::zrtp_commit *)new uint8_t[len_]; diff --git a/src/mzrtp/commit.hh b/src/mzrtp/commit.hh index 906c665..a303bc5 100644 --- a/src/mzrtp/commit.hh +++ b/src/mzrtp/commit.hh @@ -26,6 +26,7 @@ namespace kvz_rtp { uint32_t hvi[8]; uint32_t mac[2]; + uint32_t crc; }; class commit { diff --git a/src/mzrtp/confack.cc b/src/mzrtp/confack.cc index b7c09b3..b757e39 100644 --- a/src/mzrtp/confack.cc +++ b/src/mzrtp/confack.cc @@ -35,6 +35,9 @@ kvz_rtp::zrtp_msg::confack::confack(zrtp_session_t& session) msg->msg_start.length = len_ - sizeof(zrtp_header); memcpy(&msg->msg_start.msgblock, ZRTP_CONFACK, 8); + + /* Calculate CRC32 for the whole ZRTP packet */ + kvz_rtp::crypto::crc32::get_crc32((uint8_t *)frame_, len_ - 4, &msg->crc); } kvz_rtp::zrtp_msg::confack::~confack() diff --git a/src/mzrtp/confack.hh b/src/mzrtp/confack.hh index 1d5d25f..f8b4cac 100644 --- a/src/mzrtp/confack.hh +++ b/src/mzrtp/confack.hh @@ -12,6 +12,7 @@ namespace kvz_rtp { struct zrtp_confack { zrtp_msg msg_start; + uint32_t crc; }; class confack { diff --git a/src/mzrtp/confirm.cc b/src/mzrtp/confirm.cc index f11ff5e..19490f3 100644 --- a/src/mzrtp/confirm.cc +++ b/src/mzrtp/confirm.cc @@ -66,10 +66,14 @@ kvz_rtp::zrtp_msg::confirm::confirm(zrtp_session_t& session, int part) aes_cfb->encrypt((uint8_t *)msg->hash, (uint8_t *)msg->hash, 40); + /* Calculate HMAC-SHA256 of the encrypted portion of the message */ hmac_sha256->update((uint8_t *)msg->hash, 40); hmac_sha256->final(mac_full); memcpy(&msg->confirm_mac, mac_full, sizeof(uint64_t)); + /* Calculate CRC32 for the whole ZRTP packet */ + kvz_rtp::crypto::crc32::get_crc32((uint8_t *)frame_, len_ - 4, &msg->crc); + delete hmac_sha256; delete aes_cfb; } diff --git a/src/mzrtp/defines.hh b/src/mzrtp/defines.hh index dad2f8f..8dd87ea 100644 --- a/src/mzrtp/defines.hh +++ b/src/mzrtp/defines.hh @@ -6,6 +6,7 @@ namespace kvz_rtp { namespace zrtp_msg { + struct zrtp_hello_ack; struct zrtp_commit; struct zrtp_hello; struct zrtp_dh; diff --git a/src/mzrtp/dh_kxchng.cc b/src/mzrtp/dh_kxchng.cc index 3f263be..4a3c9b4 100644 --- a/src/mzrtp/dh_kxchng.cc +++ b/src/mzrtp/dh_kxchng.cc @@ -78,13 +78,16 @@ kvz_rtp::zrtp_msg::dh_key_exchange::dh_key_exchange(zrtp_session_t& session, int /* public key */ memcpy(msg->pk, session.public_key, sizeof(session.public_key)); - /* Finally calculate MAC code for the message */ + /* Calculate truncated HMAC-SHA256 for the Commit Message */ hmac_sha256 = kvz_rtp::crypto::hmac::sha256(session.hashes[0], 32); hmac_sha256.update((uint8_t *)frame_, len_ - 8 - 4); hmac_sha256.final(mac_full); memcpy(msg->mac, mac_full, 8); + /* Calculate CRC32 for the whole ZRTP packet */ + kvz_rtp::crypto::crc32::get_crc32((uint8_t *)frame_, len_ - 4, &msg->crc); + /* Finally make a copy of the message and save it for later use */ session.l_msg.dh.first = len_; session.l_msg.dh.second = (kvz_rtp::zrtp_msg::zrtp_dh *)new uint8_t[len_]; diff --git a/src/mzrtp/dh_kxchng.hh b/src/mzrtp/dh_kxchng.hh index 194c419..2fca022 100644 --- a/src/mzrtp/dh_kxchng.hh +++ b/src/mzrtp/dh_kxchng.hh @@ -8,6 +8,8 @@ namespace kvz_rtp { + typedef struct zrtp_session zrtp_session_t; + namespace zrtp_msg { struct zrtp_dh { diff --git a/src/mzrtp/hello.cc b/src/mzrtp/hello.cc index f557b63..272c246 100644 --- a/src/mzrtp/hello.cc +++ b/src/mzrtp/hello.cc @@ -18,17 +18,22 @@ kvz_rtp::zrtp_msg::hello::hello(zrtp_session_t& session) /* We support only the mandatory algorithms etc. defined in RFC 6189 * so for us all the hash algos and key agreement types are set to zero */ - size_t common_size = sizeof(zrtp_hello) - sizeof(zrtp_header); - size_t our_size = common_size; + /* size_t common_size = sizeof(zrtp_hello) - sizeof(zrtp_header); */ + /* size_t our_size = common_size; */ /* assume remote supports everything so allocate space for all possible elements */ - size_t their_size = common_size + 5 * 8 * sizeof(uint32_t); + /* size_t their_size = common_size + 5 * 8 * sizeof(uint32_t); */ - frame_ = kvz_rtp::frame::alloc_zrtp_frame(our_size); - rframe_ = kvz_rtp::frame::alloc_zrtp_frame(their_size); + len_ = sizeof(zrtp_hello); + rlen_ = sizeof(zrtp_hello) + 5 * 8; - len_ = sizeof(kvz_rtp::frame::zrtp_frame) + our_size; - rlen_ = sizeof(kvz_rtp::frame::zrtp_frame) + their_size; + frame_ = kvz_rtp::frame::alloc_zrtp_frame(sizeof(zrtp_hello)); + rframe_ = kvz_rtp::frame::alloc_zrtp_frame(sizeof(zrtp_hello) + 5 * 8); + + memset(frame_, 0, sizeof(zrtp_hello)); + memset(rframe_, 0, sizeof(zrtp_hello) + 5 * 8); + + fprintf(stderr, "%zu\n", len_); zrtp_hello *msg = (zrtp_hello *)frame_; @@ -38,7 +43,7 @@ kvz_rtp::zrtp_msg::hello::hello(zrtp_session_t& session) msg->msg_start.header.seq = session.seq++; msg->msg_start.magic = ZRTP_MSG_MAGIC; - msg->msg_start.length = our_size; + msg->msg_start.length = len_ - sizeof(kvz_rtp::frame::zrtp_frame); memcpy(&msg->msg_start.msgblock, ZRTP_HELLO, 8); memcpy(&msg->version, ZRTP_VERSION, 4); @@ -50,19 +55,23 @@ kvz_rtp::zrtp_msg::hello::hello(zrtp_session_t& session) msg->s = 0; msg->m = 0; msg->p = 0; - msg->unused = 0; + /* msg->unused = 0; */ msg->hc = 0; msg->ac = 0; msg->kc = 0; msg->sc = 0; + /* Calculate MAC for the Hello message (only the ZRTP message part) */ auto hmac_sha256 = kvz_rtp::crypto::hmac::sha256(session.hashes[2], 32); - hmac_sha256.update((uint8_t *)frame_, our_size - 8); + hmac_sha256.update((uint8_t *)frame_, 81); hmac_sha256.final(mac_full); memcpy(&msg->mac, mac_full, sizeof(uint64_t)); + /* Calculate CRC32 of the whole packet (excluding crc) */ + kvz_rtp::crypto::crc32::get_crc32((uint8_t *)frame_, len_ - 4, &msg->crc); + /* Finally make a copy of the message and save it for later use */ session.l_msg.hello.first = len_; session.l_msg.hello.second = (kvz_rtp::zrtp_msg::zrtp_hello *)new uint8_t[len_]; @@ -73,6 +82,7 @@ kvz_rtp::zrtp_msg::hello::~hello() { LOG_DEBUG("Freeing ZRTP hello message..."); (void)kvz_rtp::frame::dealloc_frame(frame_); + (void)kvz_rtp::frame::dealloc_frame(rframe_); } rtp_error_t kvz_rtp::zrtp_msg::hello::send_msg(socket_t& socket, sockaddr_in& addr) diff --git a/src/mzrtp/hello.hh b/src/mzrtp/hello.hh index 2867558..3a214c0 100644 --- a/src/mzrtp/hello.hh +++ b/src/mzrtp/hello.hh @@ -9,6 +9,7 @@ namespace kvz_rtp { typedef struct capabilities zrtp_capab_t; + typedef struct zrtp_session zrtp_session_t; namespace zrtp_msg { @@ -39,6 +40,7 @@ namespace kvz_rtp { uint32_t sas_types[0]; uint64_t mac; + uint32_t crc; }; class hello { diff --git a/src/mzrtp/hello_ack.cc b/src/mzrtp/hello_ack.cc index debcf04..85d5ca9 100644 --- a/src/mzrtp/hello_ack.cc +++ b/src/mzrtp/hello_ack.cc @@ -14,6 +14,8 @@ kvz_rtp::zrtp_msg::hello_ack::hello_ack() zrtp_hello_ack *msg = (zrtp_hello_ack *)frame_; + memset(msg, 0, sizeof(zrtp_hello_ack)); + msg->msg_start.header.version = 0; msg->msg_start.header.magic = ZRTP_HEADER_MAGIC; @@ -21,6 +23,8 @@ kvz_rtp::zrtp_msg::hello_ack::hello_ack() msg->msg_start.length = 3; memcpy(&msg->msg_start.msgblock, ZRTP_HELLO_ACK, 8); + + kvz_rtp::crypto::crc32::get_crc32((uint8_t *)frame_, len_ - 4, &msg->crc); } kvz_rtp::zrtp_msg::hello_ack::~hello_ack() diff --git a/src/mzrtp/hello_ack.hh b/src/mzrtp/hello_ack.hh index 5f1671d..2846c95 100644 --- a/src/mzrtp/hello_ack.hh +++ b/src/mzrtp/hello_ack.hh @@ -9,8 +9,9 @@ namespace kvz_rtp { namespace zrtp_msg { - struct zrtp_hello_ack { + PACKED_STRUCT(zrtp_hello_ack) { zrtp_msg msg_start; + uint32_t crc; }; class hello_ack { diff --git a/src/mzrtp/receiver.cc b/src/mzrtp/receiver.cc index 483450d..032299d 100644 --- a/src/mzrtp/receiver.cc +++ b/src/mzrtp/receiver.cc @@ -12,7 +12,14 @@ #include "debug.hh" #include "util.hh" +#include "crypto/crypto.hh" #include "mzrtp/defines.hh" +#include "mzrtp/dh_kxchng.hh" +#include "mzrtp/commit.hh" +#include "mzrtp/confack.hh" +#include "mzrtp/confirm.hh" +#include "mzrtp/hello.hh" +#include "mzrtp/hello_ack.hh" #include "mzrtp/receiver.hh" using namespace kvz_rtp::zrtp_msg; @@ -77,36 +84,92 @@ int kvz_rtp::zrtp_msg::receiver::recv_msg(socket_t& socket, int flags) switch (msg->msgblock) { case ZRTP_MSG_HELLO: - LOG_DEBUG("Hello message received"); - return ZRTP_FT_HELLO; + { + LOG_DEBUG("Hello message received, verify CRC32!"); + + zrtp_hello *hello = (zrtp_hello *)msg; + + if (!kvz_rtp::crypto::crc32::verify_crc32(mem_, rlen_ - 4, hello->crc)) + return -EOPNOTSUPP; + } + return ZRTP_FT_HELLO; case ZRTP_MSG_HELLO_ACK: - LOG_DEBUG("HelloACK message received"); - return ZRTP_FT_HELLO_ACK; + { + LOG_DEBUG("HelloACK message received, verify CRC32!"); + + zrtp_hello_ack *ha_msg = (zrtp_hello_ack *)msg; + + if (!kvz_rtp::crypto::crc32::verify_crc32(mem_, rlen_ - 4, ha_msg->crc)) + return -EOPNOTSUPP; + } + return ZRTP_FT_HELLO_ACK; case ZRTP_MSG_COMMIT: - LOG_DEBUG("Commit message received"); - return ZRTP_FT_COMMIT; + { + LOG_DEBUG("Commit message received, verify CRC32!"); + + zrtp_commit *commit = (zrtp_commit *)msg; + + if (!kvz_rtp::crypto::crc32::verify_crc32(mem_, rlen_ - 4, commit->crc)) + return -EOPNOTSUPP; + } + return ZRTP_FT_COMMIT; case ZRTP_MSG_DH_PART1: - LOG_DEBUG("DH Part1 message received"); - return ZRTP_FT_DH_PART1; + { + LOG_DEBUG("DH Part1 message received, verify CRC32!"); + + zrtp_dh *dh = (zrtp_dh *)msg; + + if (!kvz_rtp::crypto::crc32::verify_crc32(mem_, rlen_ - 4, dh->crc)) + return -EOPNOTSUPP; + } + return ZRTP_FT_DH_PART1; case ZRTP_MSG_DH_PART2: - LOG_DEBUG("DH Part2 message received"); - return ZRTP_FT_DH_PART2; + { + LOG_DEBUG("DH Part2 message received, verify CRC32!"); + + zrtp_dh *dh = (zrtp_dh *)msg; + + if (!kvz_rtp::crypto::crc32::verify_crc32(mem_, rlen_ - 4, dh->crc)) + return -EOPNOTSUPP; + } + return ZRTP_FT_DH_PART2; case ZRTP_MSG_CONFIRM1: - LOG_DEBUG("Confirm1 message received"); - return ZRTP_FT_CONFIRM1; + { + LOG_DEBUG("Confirm1 message received, verify CRC32!"); + + zrtp_confirm *dh = (zrtp_confirm *)msg; + + if (!kvz_rtp::crypto::crc32::verify_crc32(mem_, rlen_ - 4, dh->crc)) + return -EOPNOTSUPP; + } + return ZRTP_FT_CONFIRM1; case ZRTP_MSG_CONFIRM2: - LOG_DEBUG("Confirm2 message received"); - return ZRTP_FT_CONFIRM2; + { + LOG_DEBUG("Confirm2 message received, verify CRC32!"); + + zrtp_confirm *dh = (zrtp_confirm *)msg; + + if (!kvz_rtp::crypto::crc32::verify_crc32(mem_, rlen_ - 4, dh->crc)) + return -EOPNOTSUPP; + } + return ZRTP_FT_CONFIRM2; case ZRTP_MSG_CONF2_ACK: - LOG_DEBUG("Conf2 ACK message received"); - return ZRTP_FT_CONF2_ACK; + { + LOG_DEBUG("Conf2 ACK message received, verify CRC32!"); + + zrtp_confack *ca = (zrtp_confack *)msg; + + if (!kvz_rtp::crypto::crc32::verify_crc32(mem_, rlen_ - 4, ca->crc)) + return -EOPNOTSUPP; + } + return ZRTP_FT_CONF2_ACK; case ZRTP_MSG_ERROR: LOG_DEBUG("Error message received"); diff --git a/src/zrtp.cc b/src/zrtp.cc index e81b3c4..a4d00cf 100644 --- a/src/zrtp.cc +++ b/src/zrtp.cc @@ -244,7 +244,7 @@ rtp_error_t kvz_rtp::zrtp::validate_session() if (RTP_INVALID_VALUE == verify_hash( (uint8_t *)hashes[1], (uint8_t *)session_.r_msg.commit.second, - session_.r_msg.commit.first - 8, + session_.r_msg.commit.first - 8 - 4, session_.remote_macs[2] )) { @@ -307,8 +307,9 @@ rtp_error_t kvz_rtp::zrtp::begin_session() for (i = 0; i < 20; ++i) { set_timeout(rto); - if ((ret = hello.send_msg(socket_, addr_)) != RTP_OK) + if ((ret = hello.send_msg(socket_, addr_)) != RTP_OK) { LOG_ERROR("Failed to send Hello message"); + } if ((type = receiver_.recv_msg(socket_, 0)) > 0) { /* We received something interesting, either Hello message from remote in which case @@ -383,8 +384,9 @@ rtp_error_t kvz_rtp::zrtp::init_session() for (int i = 0; i < 10; ++i) { set_timeout(rto); - if ((ret = commit.send_msg(socket_, addr_)) != RTP_OK) + if ((ret = commit.send_msg(socket_, addr_)) != RTP_OK) { LOG_ERROR("Failed to send Commit message!"); + } if ((type = receiver_.recv_msg(socket_, 0)) > 0) { @@ -471,8 +473,9 @@ rtp_error_t kvz_rtp::zrtp::dh_part2() for (int i = 0; i < 10; ++i) { set_timeout(rto); - if ((ret = dhpart.send_msg(socket_, addr_)) != RTP_OK) + if ((ret = dhpart.send_msg(socket_, addr_)) != RTP_OK) { LOG_ERROR("Failed to send DHPart2 Message!"); + } if ((type = receiver_.recv_msg(socket_, 0)) > 0) { if (type == ZRTP_FT_CONFIRM1) { @@ -571,6 +574,7 @@ rtp_error_t kvz_rtp::zrtp::init(uint32_t ssrc, socket_t& socket, sockaddr_in& ad rtp_error_t ret = RTP_OK; /* TODO: set all fields initially to zero */ + memset(session_.hvi, 0, sizeof(session_.hvi)); generate_zid(); generate_secrets();