diff --git a/inc/ECSS_Definitions.hpp b/inc/ECSS_Definitions.hpp
index a8523462496cad6652af9cb1c8eeb05d02fee2f4..3ae97055f0221c61079d2c14bf1d86af01f1b56f 100644
--- a/inc/ECSS_Definitions.hpp
+++ b/inc/ECSS_Definitions.hpp
@@ -145,4 +145,10 @@
  * @brief Size of the array holding the Parameter objects for the ST[20] parameter service
  */
 #define ECSS_PARAMETER_COUNT 3
+
+/**
+ * @brief Defines whether the optional CRC field is included
+ */
+#define ECSS_CRC_INCLUDED true
+
 #endif // ECSS_SERVICES_ECSS_DEFINITIONS_H
diff --git a/src/MessageParser.cpp b/src/MessageParser.cpp
index b4eb3953d2e6ecba5f4115759ba0ac062fb2847e..b3a082ca954afda75806e6add9fbe64b14378a4b 100644
--- a/src/MessageParser.cpp
+++ b/src/MessageParser.cpp
@@ -5,6 +5,7 @@
 #include "macros.hpp"
 #include "Services/TestService.hpp"
 #include "Services/RequestVerificationService.hpp"
+#include "Helpers/CRCHelper.hpp"
 
 void MessageParser::execute(Message& message) {
 	switch (message.serviceType) {
@@ -194,6 +195,14 @@ String<CCSDS_MAX_MESSAGE_SIZE> MessageParser::compose(const Message& message) {
 	String<CCSDS_MAX_MESSAGE_SIZE> ccsdsMessage(header, 6);
 	ccsdsMessage.append(ecssMessage);
 
+#if ECSS_CRC_INCLUDED
+	// Append CRC field
+	uint16_t crcField = CRCHelper::calculateCRC(reinterpret_cast<uint8_t*>(ccsdsMessage.data()), 6 +
+	packetDataLength);
+	ccsdsMessage.push_back(static_cast<uint8_t>(crcField >> 8U));
+	ccsdsMessage.push_back(static_cast<uint8_t>(crcField & 0xFF));
+#endif
+
 	return ccsdsMessage;
 }
 
diff --git a/test/MessageParser.cpp b/test/MessageParser.cpp
index c416f1b5d6cdecf2c0b19f311bde1963540b3716..c2e8981bb71d7285cc06dfd40b60070ead233255 100644
--- a/test/MessageParser.cpp
+++ b/test/MessageParser.cpp
@@ -3,6 +3,7 @@
 #include <Services/RequestVerificationService.hpp>
 #include <Message.hpp>
 #include <cstring>
+#include "Helpers/CRCHelper.hpp"
 #include "MessageParser.hpp"
 #include "Services/ServiceTests.hpp"
 #include "ServicePool.hpp"
@@ -35,10 +36,17 @@ TEST_CASE("TC Message parsing into a string", "[MessageParser]") {
 	message.dataSize = 5;
 
 	String<CCSDS_MAX_MESSAGE_SIZE> createdPacket = MessageParser::compose(message);
+#if ECSS_CRC_INCLUDED
+	CHECK(createdPacket.size() == 18);
+	CHECK(memcmp(createdPacket.data(), wantedPacket, 16) == 0);
 
+	const uint8_t* packet = reinterpret_cast<uint8_t*>(&createdPacket.data()[0]);
+	uint8_t crc_verification = CRCHelper::validateCRC(packet, 18);
+	CHECK(crc_verification == 0);
+#else
 	CHECK(createdPacket.size() == 16);
-	// The two parentheses are necessary so that Catch2 doesn't try to parse the strings here
 	CHECK((createdPacket == String<16>(wantedPacket)));
+#endif
 }
 
 TEST_CASE("TM message parsing", "[MessageParser]") {
@@ -67,10 +75,17 @@ TEST_CASE("TM Message parsing into a string", "[MessageParser]") {
 	message.messageType = 17;
 	memcpy(message.data, "hellohi", 7);
 	message.dataSize = 7;
-
 	String<CCSDS_MAX_MESSAGE_SIZE> createdPacket = MessageParser::compose(message);
 
+#if ECSS_CRC_INCLUDED
+	CHECK(createdPacket.size() == 20);
+	CHECK(memcmp(createdPacket.data(), wantedPacket, 18) == 0);
+
+	const uint8_t* packet = reinterpret_cast<uint8_t*>(&createdPacket.data()[0]);
+	uint8_t crc_verification = CRCHelper::validateCRC(packet, 20);
+	CHECK(crc_verification == 0);
+#else
 	CHECK(createdPacket.size() == 18);
-	// The two parentheses are necessary so that Catch2 doesn't try to parse the strings here
 	CHECK((createdPacket == String<18>(wantedPacket)));
+#endif
 }