bool ccnxCodecSchemaV1PacketDecoder_Decode(CCNxCodecTlvDecoder *packetDecoder, CCNxTlvDictionary *packetDictionary) { bool decodeSuccess = false; _CCNxCodecSchemaV1Data data; // we temporarily store this reference, but we do not destroy it. This // is just to pass the reference down the decode chain, it is not // stored beyond the immediate scope. Therefore, no reference acquired. data.packetDictionary = packetDictionary; data.decoder = packetDecoder; if (ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data.decoder, data.packetDictionary)) { if (_decodeOptionalHeaders(&data)) { // Record the position we'd start the signature verification at size_t signatureStartPosition = ccnxCodecTlvDecoder_Position(data.decoder); // Mark the beginning of the ContentObject hash region. CCNxWireFormatFacadeV1_Implementation.setContentObjectHashRegionStart(data.packetDictionary, signatureStartPosition); if (_decodeMessage(&data)) { // If there's anything else left, it must be the validation alg and payload if (!ccnxCodecTlvDecoder_IsEmpty(data.decoder)) { if (_decodeValidationAlg(&data)) { // at this point, we've advanced to the end of the validation algorithm, // that's where we would end signature verification size_t signatureStopPosition = ccnxCodecTlvDecoder_Position(data.decoder); CCNxWireFormatFacadeV1_Implementation.setProtectedRegionStart(data.packetDictionary, signatureStartPosition); CCNxWireFormatFacadeV1_Implementation.setProtectedRegionLength(data.packetDictionary, signatureStopPosition - signatureStartPosition); if (_decodeValidationPayload(&data)) { decodeSuccess = true; } } } else { // nothing after the message, so that's a successful decode decodeSuccess = true; } // Mark the length of the ContentObject hash region (to the end of the packet). size_t contentObjectHashRegionLength = ccnxCodecTlvDecoder_Position(data.decoder) - signatureStartPosition; CCNxWireFormatFacadeV1_Implementation.setContentObjectHashRegionLength(data.packetDictionary, contentObjectHashRegionLength); } } } return decodeSuccess; }
LONGBOW_TEST_CASE(Global, ccnxTlvCodecName_Decode_WrongType) { uint8_t decodeBytes[] = { 0x10, 0x20, 0x00, 0x0E, 0x00, CCNxNameLabelType_NAME, 0x00, 0x0A, 'b', 'r', 'a', 'n', 'd', 'y', 'w', 'i', 'n', 'e' }; PARCBuffer *decodeBuffer = parcBuffer_Wrap(decodeBytes, sizeof(decodeBytes), 0, sizeof(decodeBytes)); CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(decodeBuffer); CCNxName *test = ccnxCodecSchemaV1NameCodec_Decode(decoder, 0xFFFF); assertNull(test, "Name should have returned NULL because the name type does not match"); assertTrue(ccnxCodecTlvDecoder_Position(decoder) == 0, "Position should not have moved, expected 0, got %zu", ccnxCodecTlvDecoder_Position(decoder)); ccnxCodecTlvDecoder_Destroy(&decoder); parcBuffer_Release(&decodeBuffer); }
bool ccnxCodecSchemaV1FixedHeaderDecoder_Decode(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary) { if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, _fixedHeaderBytes)) { PARCBuffer *buffer = ccnxCodecTlvDecoder_GetValue(decoder, _fixedHeaderBytes); bool success = ccnxTlvDictionary_PutBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader, buffer); // validation parcBuffer_SetPosition(buffer, _fixedHeader_VersionOffset); uint8_t version = parcBuffer_GetUint8(buffer); parcBuffer_SetPosition(buffer, _fixedHeader_PacketLengthOffset); uint16_t packetLength = parcBuffer_GetUint16(buffer); parcBuffer_SetPosition(buffer, _fixedHeader_HopLimitOffset); uint8_t hopLimit = parcBuffer_GetUint8(buffer); parcBuffer_SetPosition(buffer, _fixedHeader_HeaderLengthOffset); uint8_t headerLength = parcBuffer_GetUint8(buffer); if (version != 1) { CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_VERSION, __func__, __LINE__, _fixedHeader_VersionOffset); ccnxCodecTlvDecoder_SetError(decoder, error); ccnxCodecError_Release(&error); success = false; } else if (packetLength < _fixedHeaderBytes) { CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_PACKETLENGTH_TOO_SHORT, __func__, __LINE__, _fixedHeader_PacketTypeOffset); ccnxCodecTlvDecoder_SetError(decoder, error); ccnxCodecError_Release(&error); success = false; } else if (headerLength < _fixedHeaderBytes) { CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_HEADERLENGTH_TOO_SHORT, __func__, __LINE__, _fixedHeader_HeaderLengthOffset); ccnxCodecTlvDecoder_SetError(decoder, error); ccnxCodecError_Release(&error); success = false; } else if (packetLength < headerLength) { CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_PACKETLENGTHSHORTER, __func__, __LINE__, _fixedHeader_PacketTypeOffset); ccnxCodecTlvDecoder_SetError(decoder, error); ccnxCodecError_Release(&error); success = false; } // decoder now points to just past the fixed header parcBuffer_Release(&buffer); // Set the hoplimit in the dictionary. ccnxTlvDictionary_PutInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_HOPLIMIT, hopLimit); return success; } else { CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder)); ccnxCodecTlvDecoder_SetError(decoder, error); ccnxCodecError_Release(&error); return false; } }
static bool _decodeValidationAlg(_CCNxCodecSchemaV1Data *data) { bool success = false; if (ccnxCodecTlvDecoder_EnsureRemaining(data->decoder, 4)) { // what kind of message are we looking at? // Note that this is based on the TLV container, not the fixed head PacketType uint16_t tlv_type = ccnxCodecTlvDecoder_GetType(data->decoder); uint16_t tlv_length = ccnxCodecTlvDecoder_GetLength(data->decoder); if (tlv_type == CCNxCodecSchemaV1Types_MessageType_ValidationAlg && ccnxCodecTlvDecoder_EnsureRemaining(data->decoder, tlv_length)) { CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_GetContainer(data->decoder, tlv_length); success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, data->packetDictionary); ccnxCodecTlvDecoder_Destroy(&decoder); } else { // raise and error if (!ccnxCodecTlvDecoder_EnsureRemaining(data->decoder, tlv_length)) { // tlv_length goes beyond the decoder CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_TOO_LONG, __func__, __LINE__, ccnxCodecTlvDecoder_Position(data->decoder)); ccnxCodecTlvDecoder_SetError(data->decoder, error); ccnxCodecError_Release(&error); } else { // not CCNxCodecSchemaV1Types_MessageType_ValidationAlg CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, __func__, __LINE__, ccnxCodecTlvDecoder_Position(data->decoder)); ccnxCodecTlvDecoder_SetError(data->decoder, error); ccnxCodecError_Release(&error); } } } return success; }
/** * Decodes the CCNx message inside a TLV packet * * Creates an inner decoder that slices the decode buffer then passes that and our * message dictionary to the appropriate inner decoder. * * @param [in] data The packet decoder state * * @return true successful decode * @return false A decoding error * * Example: * @code * <#example#> * @endcode */ static bool _decodeMessage(_CCNxCodecSchemaV1Data *data) { bool success = false; if (ccnxCodecTlvDecoder_EnsureRemaining(data->decoder, 4)) { // what kind of message are we looking at? // Note that this is based on the TLV container, not the fixed head PacketType uint16_t tlv_type = ccnxCodecTlvDecoder_GetType(data->decoder); uint16_t tlv_length = ccnxCodecTlvDecoder_GetLength(data->decoder); // ensure its a proper tlv type switch (tlv_type) { case CCNxCodecSchemaV1Types_MessageType_Interest: // fallthrough case CCNxCodecSchemaV1Types_MessageType_ContentObject: // fallthrough case CCNxCodecSchemaV1Types_MessageType_Control: // fallthrough break; default: return false; } // cross check with the fixed header value // ccnxCodecSchemaV1FixedHeaderDecoder_Decode ensures that PacketLength is not less than HeaderLength size_t messageLength = ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength(data->packetDictionary) - ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength(data->packetDictionary); if (tlv_length <= messageLength && ccnxCodecTlvDecoder_EnsureRemaining(data->decoder, tlv_length)) { // This decode is for the "value" of the message, it does not include the wrapper CCNxCodecTlvDecoder *messageDecoder = ccnxCodecTlvDecoder_GetContainer(data->decoder, tlv_length); if (tlv_type == CCNxCodecSchemaV1Types_MessageType_Control) { // the CPI messages are not a proper "message" in that there's no inner TLV, its just data success = _decodeCPI(messageDecoder, data->packetDictionary); } else { success = ccnxCodecSchemaV1MessageDecoder_Decode(messageDecoder, data->packetDictionary); } ccnxCodecTlvDecoder_Destroy(&messageDecoder); } else { // raise an error CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_TOO_LONG, __func__, __LINE__, ccnxCodecTlvDecoder_Position(data->decoder)); ccnxCodecTlvDecoder_SetError(data->decoder, error); ccnxCodecError_Release(&error); } } return success; }
static bool _decodeType(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length) { bool success = false; switch (type) { case CCNxCodecSchemaV1Types_OptionalHeaders_InterestFragment: success = ccnxCodecTlvUtilities_PutAsBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG); break; case CCNxCodecSchemaV1Types_OptionalHeaders_ContentObjectFragment: success = ccnxCodecTlvUtilities_PutAsBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_OBJFRAG); break; case CCNxCodecSchemaV1Types_OptionalHeaders_InterestLifetime: // its a time, so use an Integer success = ccnxCodecTlvUtilities_PutAsInteger(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime); break; case CCNxCodecSchemaV1Types_OptionalHeaders_RecommendedCacheTime: // its a time, so use an Integer success = ccnxCodecTlvUtilities_PutAsInteger(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime); break; default: { // if we do not know the TLV type, put it in this container's unknown list success = ccnxCodecTlvUtilities_PutAsListBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_Lists_HEADERS); } break; } if (!success) { CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder)); ccnxCodecTlvDecoder_SetError(decoder, error); ccnxCodecError_Release(&error); } return success; }