From d18ae43123fcd7604d1c36a1ec8450dbe6071824 Mon Sep 17 00:00:00 2001 From: Luca Muscariello Date: Thu, 23 Feb 2017 20:44:26 +0100 Subject: Initial commit: ccnxlibs. Change-Id: I1b376527a7dd01a6b9e083a6cb646955902f45c0 Signed-off-by: Luca Muscariello --- .../schema_v1/ccnxCodecSchemaV1_CryptoSuite.c | 137 +++ .../schema_v1/ccnxCodecSchemaV1_CryptoSuite.h | 85 ++ .../schema_v1/ccnxCodecSchemaV1_FixedHeader.h | 51 + .../ccnxCodecSchemaV1_FixedHeaderDecoder.c | 210 ++++ .../ccnxCodecSchemaV1_FixedHeaderDecoder.h | 165 +++ .../ccnxCodecSchemaV1_FixedHeaderEncoder.c | 64 ++ .../ccnxCodecSchemaV1_FixedHeaderEncoder.h | 50 + .../codec/schema_v1/ccnxCodecSchemaV1_HashCodec.c | 149 +++ .../codec/schema_v1/ccnxCodecSchemaV1_HashCodec.h | 74 ++ .../codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.c | 165 +++ .../codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.h | 76 ++ .../schema_v1/ccnxCodecSchemaV1_ManifestDecoder.c | 187 ++++ .../schema_v1/ccnxCodecSchemaV1_ManifestDecoder.h | 52 + .../schema_v1/ccnxCodecSchemaV1_ManifestEncoder.c | 166 +++ .../schema_v1/ccnxCodecSchemaV1_ManifestEncoder.h | 31 + .../schema_v1/ccnxCodecSchemaV1_MessageDecoder.c | 140 +++ .../schema_v1/ccnxCodecSchemaV1_MessageDecoder.h | 57 ++ .../schema_v1/ccnxCodecSchemaV1_MessageEncoder.c | 340 +++++++ .../schema_v1/ccnxCodecSchemaV1_MessageEncoder.h | 47 + .../codec/schema_v1/ccnxCodecSchemaV1_NameCodec.c | 85 ++ .../codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h | 83 ++ .../schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.c | 59 ++ .../schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.h | 64 ++ .../ccnxCodecSchemaV1_OptionalHeadersDecoder.c | 125 +++ .../ccnxCodecSchemaV1_OptionalHeadersDecoder.h | 144 +++ .../ccnxCodecSchemaV1_OptionalHeadersEncoder.c | 187 ++++ .../ccnxCodecSchemaV1_OptionalHeadersEncoder.h | 46 + .../schema_v1/ccnxCodecSchemaV1_PacketDecoder.c | 289 ++++++ .../schema_v1/ccnxCodecSchemaV1_PacketDecoder.h | 91 ++ .../schema_v1/ccnxCodecSchemaV1_PacketEncoder.c | 353 +++++++ .../schema_v1/ccnxCodecSchemaV1_PacketEncoder.h | 85 ++ .../schema_v1/ccnxCodecSchemaV1_TlvDictionary.c | 68 ++ .../schema_v1/ccnxCodecSchemaV1_TlvDictionary.h | 250 +++++ .../codec/schema_v1/ccnxCodecSchemaV1_Types.h | 211 ++++ .../ccnxCodecSchemaV1_ValidationDecoder.c | 176 ++++ .../ccnxCodecSchemaV1_ValidationDecoder.h | 74 ++ .../ccnxCodecSchemaV1_ValidationEncoder.c | 253 +++++ .../ccnxCodecSchemaV1_ValidationEncoder.h | 79 ++ .../ccnx/common/codec/schema_v1/test/.gitignore | 19 + .../common/codec/schema_v1/test/CMakeLists.txt | 29 + .../test/test_ccnxCodecSchemaV1_CryptoSuite.c | 154 +++ .../test_ccnxCodecSchemaV1_FixedHeaderDecoder.c | 350 +++++++ .../test_ccnxCodecSchemaV1_FixedHeaderEncoder.c | 174 ++++ .../test/test_ccnxCodecSchemaV1_HashCodec.c | 235 +++++ .../test/test_ccnxCodecSchemaV1_LinkCodec.c | 450 +++++++++ .../test/test_ccnxCodecSchemaV1_ManifestDecoder.c | 267 +++++ .../test/test_ccnxCodecSchemaV1_ManifestEncoder.c | 306 ++++++ .../test/test_ccnxCodecSchemaV1_MessageDecoder.c | 320 ++++++ .../test/test_ccnxCodecSchemaV1_MessageEncoder.c | 644 ++++++++++++ .../test/test_ccnxCodecSchemaV1_NameCodec.c | 139 +++ .../test/test_ccnxCodecSchemaV1_NameSegmentCodec.c | 149 +++ ...test_ccnxCodecSchemaV1_OptionalHeadersDecoder.c | 321 ++++++ ...test_ccnxCodecSchemaV1_OptionalHeadersEncoder.c | 205 ++++ .../test/test_ccnxCodecSchemaV1_PacketDecoder.c | 684 +++++++++++++ .../test/test_ccnxCodecSchemaV1_PacketEncoder.c | 1054 ++++++++++++++++++++ .../test/test_ccnxCodecSchemaV1_TlvDictionary.c | 118 +++ .../test_ccnxCodecSchemaV1_ValidationDecoder.c | 450 +++++++++ .../test_ccnxCodecSchemaV1_ValidationEncoder.c | 565 +++++++++++ .../common/codec/schema_v1/test/testrig_encoder.c | 472 +++++++++ .../codec/schema_v1/test/testrig_packetwrapper.c | 516 ++++++++++ .../common/codec/schema_v1/testdata/CMakeLists.txt | 27 + .../common/codec/schema_v1/testdata/v1_CPISchema.h | 50 + .../schema_v1/testdata/v1_ContentObjectSchema.h | 74 ++ .../codec/schema_v1/testdata/v1_InterestSchema.h | 54 + .../schema_v1/testdata/v1_content_nameA_crc32c.h | 114 +++ .../testdata/v1_content_nameA_keyid1_rsasha256.h | 181 ++++ .../schema_v1/testdata/v1_content_nameless_nosig.h | 65 ++ .../schema_v1/testdata/v1_content_no_payload.h | 55 + .../schema_v1/testdata/v1_content_zero_payload.h | 57 ++ .../codec/schema_v1/testdata/v1_cpi_add_route.h | 50 + .../schema_v1/testdata/v1_cpi_add_route_crc32c.h | 78 ++ .../schema_v1/testdata/v1_interest_all_fields.h | 102 ++ .../testdata/v1_interest_bad_message_length.h | 57 ++ .../testdata/v1_interest_bad_validation_alg.h | 74 ++ .../codec/schema_v1/testdata/v1_interest_nameA.h | 75 ++ .../testdata/v1_interest_nameA_badcrc32c.h | 76 ++ .../schema_v1/testdata/v1_interest_nameA_crc32c.h | 102 ++ .../testdata/v1_interest_validation_alg_overrun.h | 74 ++ .../codec/schema_v1/testdata/v1_testrig_truthSet.h | 68 ++ .../schema_v1/testdata/v1_testrig_truthTable.h | 34 + 80 files changed, 14056 insertions(+) create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.c create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.h create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderDecoder.c create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderDecoder.h create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.c create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.h create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.c create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.h create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.c create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.h create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.c create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.h create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.c create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.h create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.c create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.h create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.c create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.h create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.c create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.c create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.h create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.c create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.h create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.c create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.h create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.c create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.h create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.c create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.h create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.c create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.c create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.h create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.c create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.h create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/test/.gitignore create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/test/CMakeLists.txt create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_CryptoSuite.c create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderDecoder.c create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderEncoder.c create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_HashCodec.c create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_LinkCodec.c create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestDecoder.c create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestEncoder.c create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageDecoder.c create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageEncoder.c create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameCodec.c create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameSegmentCodec.c create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersDecoder.c create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersEncoder.c create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketDecoder.c create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketEncoder.c create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_TlvDictionary.c create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationDecoder.c create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationEncoder.c create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/test/testrig_encoder.c create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/test/testrig_packetwrapper.c create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/testdata/CMakeLists.txt create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_CPISchema.h create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_ContentObjectSchema.h create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameA_crc32c.h create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameless_nosig.h create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_no_payload.h create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_zero_payload.h create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route.h create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route_crc32c.h create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_bad_message_length.h create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_bad_validation_alg.h create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA.h create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_badcrc32c.h create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_crc32c.h create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_validation_alg_overrun.h create mode 100644 libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_testrig_truthSet.h create mode 100755 libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_testrig_truthTable.h (limited to 'libccnx-common/ccnx/common/codec/schema_v1') diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.c new file mode 100755 index 00000000..588694b0 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ + +#include + +#include + + +bool +ccnxCodecSchemaV1CryptoSuite_ParcToTlv(PARCCryptoSuite parcSuite, CCNxCodecSchemaV1TlvDictionary_CryptoSuite *outputValue) +{ + bool matchFound = false; + switch (parcSuite) { + case PARCCryptoSuite_RSA_SHA256: + *outputValue = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256; + matchFound = true; + break; + + case PARCCryptoSuite_DSA_SHA256: + // not supported yet + break; + + case PARCCryptoSuite_RSA_SHA512: + // not supported yet + break; + + case PARCCryptoSuite_HMAC_SHA256: + *outputValue = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256; + matchFound = true; + break; + + case PARCCryptoSuite_HMAC_SHA512: + // not supported yet + break; + + case PARCCryptoSuite_NULL_CRC32C: + *outputValue = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C; + matchFound = true; + break; + + default: + // unknown + break; + } + return matchFound; +} + +bool +ccnxCodecSchemaV1CryptoSuite_TlvToParc(CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvValue, PARCCryptoSuite *outputSuite) +{ + bool matchFound = false; + switch (tlvValue) { + case CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256: + *outputSuite = PARCCryptoSuite_RSA_SHA256; + matchFound = true; + break; + + case CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C: + *outputSuite = PARCCryptoSuite_NULL_CRC32C; + matchFound = true; + break; + + case CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256: + *outputSuite = PARCCryptoSuite_HMAC_SHA256; + matchFound = true; + break; + + case CCNxCodecSchemaV1TlvDictionary_CryptoSuite_EcSecp256K1: + // not supported yet + break; + + default: + // unknown + break; + } + return matchFound; +} + +bool +ccnxCodecSchemaV1CryptoSuite_SignAndHashToTlv(PARCSigningAlgorithm signAlgorithm, PARCCryptoHashType hashType, CCNxCodecSchemaV1TlvDictionary_CryptoSuite *outputValue) +{ + bool matchFound = false; + switch (signAlgorithm) { + case PARCSigningAlgorithm_RSA: { + switch (hashType) { + case PARCCryptoHashType_SHA256: + *outputValue = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256; + matchFound = true; + + default: + break; + } + break; + } + + case PARCSigningAlgorithm_HMAC: { + switch (hashType) { + case PARCCryptoHashType_SHA256: + *outputValue = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256; + matchFound = true; + default: + break; + } + break; + } + + case PARCSigningAlgortihm_NULL: { + switch (hashType) { + case PARCCryptoHashType_CRC32C: + *outputValue = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C; + matchFound = true; + default: + break; + } + break; + } + default: + break; + } + return matchFound; +} + diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.h new file mode 100755 index 00000000..68e90749 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_CryptoSuite.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file ccnxCodecSchemaV1_CryptoSuite.h + * @brief Translates between PARC CryptoSuite values and the wire encoding + * + * <#Detailed Description#> + * + */ + +#include +#include +#include +#include + +/** + * Converts a PARC Crypto Suite to its TLV value + * + * Looks up the PARC cryptosuite value and returns the corresponding TLV wire format value. + * If no match is found, returns false and outputSuite is not modified. + * + * + * @param [in] parcSuite The PARC cryptosuite + * @param [out] outputValue The wire encoding equivalent + * + * @retval true if supported suite and outputValue set. + * @retval false if not supported. + * + * Example: + * @code + * <#example#> + * @endcode + */ +bool ccnxCodecSchemaV1CryptoSuite_ParcToTlv(PARCCryptoSuite parcSuite, CCNxCodecSchemaV1TlvDictionary_CryptoSuite *outputValue); + +/** + * Converts a wire format cryptosuite value to the PARC cryptosuite + * + * Looks up the TLV wire format value and returns the corresponding PARC cryptosuite. + * If no match is found, returns false and outputSuite is not modified. + * + * @param [in] tlvValue The wire format value + * @param [out] outputValue The PARC equivalent + * + * @return true if match found and parcSuite set. + * @return false if no match found. + * + * Example: + * @code + * <#example#> + * @endcode + */ +bool ccnxCodecSchemaV1CryptoSuite_TlvToParc(CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvValue, PARCCryptoSuite *outputSuite); + +/** + * Lookup a signing algorithm and hash type and convert to a wire format value + * + * Based on a PARCSigner's algorithm and hash type, find the corresponding wire format crypto suite. + * + * @param [in] signAlgorithm The signing algorithm + * @param [in] hashType The hash used by the signing algorithm + * @param [out] outputValue The wire format value + * + * @retval true if supported suite and outputValue set. + * @retval false if not supported. + * + * Example: + * @code + * <#example#> + * @endcode + */ +bool ccnxCodecSchemaV1CryptoSuite_SignAndHashToTlv(PARCSigningAlgorithm signAlgorithm, PARCCryptoHashType hashType, CCNxCodecSchemaV1TlvDictionary_CryptoSuite *outputValue); diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h new file mode 100755 index 00000000..3055c054 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeader.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file ccnxCodecSchemaV1_FixedHeader.h + * @brief common definitions and functions for the FixedHeader + * + * See ccnxCodecSchemaV1_Packet.h for an overview of the version 1 codec + * + * This is the one file you need to include for all FixedHeader operations. It will + * include all the Decoders and Encoders. + * + */ + +#ifndef TransportRTA_ccnxCodecSchemaV1_FixedHeader_h +#define TransportRTA_ccnxCodecSchemaV1_FixedHeader_h + +typedef struct __attribute__ ((__packed__)) rta_tlv_schema_v1_fixed_header { + uint8_t version; + uint8_t packetType; + uint16_t packetLength; + uint8_t reserved[3]; + uint8_t headerLength; +} CCNxCodecSchemaV1FixedHeader; + +typedef struct __attribute__ ((__packed__)) rta_tlv_schema_v1_interest_header { + uint8_t version; + uint8_t packetType; + uint16_t packetLength; + uint8_t hopLimit; + uint8_t returnCode; + uint8_t flags; + uint8_t headerLength; +} CCNxCodecSchemaV1InterestHeader; + + +#include +#include +#endif // TransportRTA_ccnxCodecSchemaV1_FixedHeader_h diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderDecoder.c new file mode 100755 index 00000000..fcec49b3 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderDecoder.c @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ + +#include + +#include +#include + +#include + +#include +#include + +#include +#include +#include + +static const size_t _fixedHeaderBytes = 8; + +static const int _fixedHeader_VersionOffset = 0; +static const int _fixedHeader_PacketTypeOffset = 1; +static const int _fixedHeader_PacketLengthOffset = 2; +static const int _fixedHeader_HopLimitOffset = 4; +static const int _fixedHeader_ReturnCodeOffset = 5; +static const int _fixedHeader_FlagsOffset = 6; +static const int _fixedHeader_HeaderLengthOffset = 7; + +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_ReturnCodeOffset); + uint8_t interestReturnCode = parcBuffer_GetUint8(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); + + // Set the InterestReturn code in the dictionary. + ccnxTlvDictionary_PutInteger(packetDictionary, + CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestReturnCode, + interestReturnCode); + + return success; + } else { + CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder)); + ccnxCodecTlvDecoder_SetError(decoder, error); + ccnxCodecError_Release(&error); + return false; + } +} + +int +ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion(CCNxTlvDictionary *packetDictionary) +{ + PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader); + if (fixedHeader != NULL) { + parcBuffer_SetPosition(fixedHeader, _fixedHeader_VersionOffset); + uint8_t version = parcBuffer_GetUint8(fixedHeader); + return version; + } + + return -1; +} + +int +ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType(CCNxTlvDictionary *packetDictionary) +{ + PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader); + if (fixedHeader != NULL) { + parcBuffer_SetPosition(fixedHeader, _fixedHeader_PacketTypeOffset); + uint8_t packetType = parcBuffer_GetUint8(fixedHeader); + return packetType; + } + + return -1; +} + +int +ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength(CCNxTlvDictionary *packetDictionary) +{ + PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader); + if (fixedHeader != NULL) { + parcBuffer_SetPosition(fixedHeader, _fixedHeader_PacketLengthOffset); + uint16_t payloadLength = parcBuffer_GetUint16(fixedHeader); + return payloadLength; + } + + return -1; +} + +int +ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength(CCNxTlvDictionary *packetDictionary) +{ + int length = -1; + PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader); + if (fixedHeader != NULL) { + parcBuffer_SetPosition(fixedHeader, _fixedHeader_HeaderLengthOffset); + uint8_t headerLength = parcBuffer_GetUint8(fixedHeader); + + // 8 is the minimum size of headerLength + if (headerLength >= _fixedHeaderBytes) { + length = headerLength; + } + } + + return length; +} + +int +ccnxCodecSchemaV1FixedHeaderDecoder_GetOptionalHeaderLength(CCNxTlvDictionary *packetDictionary) +{ + int headerLength = ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength(packetDictionary); + return headerLength - _fixedHeaderBytes; +} + +int +ccnxCodecSchemaV1FixedHeaderDecoder_GetHopLimit(CCNxTlvDictionary *packetDictionary) +{ + PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader); + if (fixedHeader != NULL) { + parcBuffer_SetPosition(fixedHeader, _fixedHeader_HopLimitOffset); + uint8_t hopLimit = parcBuffer_GetUint8(fixedHeader); + return hopLimit; + } + + return -1; +} + +int +ccnxCodecSchemaV1FixedHeaderDecoder_GetReturnCode(CCNxTlvDictionary *packetDictionary) +{ + PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader); + if (fixedHeader != NULL) { + parcBuffer_SetPosition(fixedHeader, _fixedHeader_ReturnCodeOffset); + uint8_t returnCode = parcBuffer_GetUint8(fixedHeader); + return returnCode; + } + + return -1; +} + +int +ccnxCodecSchemaV1FixedHeaderDecoder_GetFlags(CCNxTlvDictionary *packetDictionary) +{ + PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader); + if (fixedHeader != NULL) { + parcBuffer_SetPosition(fixedHeader, _fixedHeader_FlagsOffset); + uint8_t flags = parcBuffer_GetUint8(fixedHeader); + return flags; + } + + return -1; +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderDecoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderDecoder.h new file mode 100755 index 00000000..5d15f40b --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderDecoder.h @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ +#ifndef Libccnx_ccnxCodecSchemaV1_FixedHeaderDecoder_h +#define Libccnx_ccnxCodecSchemaV1_FixedHeaderDecoder_h + +#include + +#include + +#include +#include + +/** + * The decode a V1 fixed header + * + * The decoder should point to byte 0 of the Fixed Header. + * It will be advanced to the first byte following it. + * The results are put in the provided. + * + * @param [in] decoder The decoder to parse + * @param [in] dictionary The results go directly in to the provided dictionary. + * + * @return true Fully parsed interest, no errors + * @return false Error decoding, decoder is left pointing to the first byte of the error + * + * Example: + * @code + * <#example#> + * @endcode + */ +bool ccnxCodecSchemaV1FixedHeaderDecoder_Decode(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary); + +/** + * A convenience function to return the version + * + * <#Paragraphs Of Explanation#> + * + * @param [in] fixedHeaderDictionary The FixedHeader dictionary + * + * @return positive The Version + * @return -1 The field does not exist + * + * Example: + * @code + * <#example#> + * @endcode + */ +int ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion(CCNxTlvDictionary *packetDictionary); + +/** + * A convenience function to return the PacketType + * + * <#Paragraphs Of Explanation#> + * + * @param [in] fixedHeaderDictionary The FixedHeader dictionary + * + * @return positive The PacketType + * @return -1 The field does not exist + * + * Example: + * @code + * <#example#> + * @endcode + */ +int ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType(CCNxTlvDictionary *packetDictionary); + +/** + * A convenience function to return the PacketLength + * + * The PacketLength is measured from byte 0 to the end of the packet + * + * @param [in] fixedHeaderDictionary The FixedHeader dictionary + * + * @return positive The packet length (in host byte order) + * @return -1 The field does not exist + * + * Example: + * @code + * <#example#> + * @endcode + */ +int ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength(CCNxTlvDictionary *packetDictionary); + +/** + * A convenience function to return the HeaderLength + * + * In a version 1 packet, the header length includes the fixed header. It is measured from + * byte 0 to the end of the hop-by-hop headers. + * + * @param [in] fixedHeaderDictionary The FixedHeader dictionary + * + * @return positive The header length + * @return -1 The field does not exist + * + * Example: + * @code + * <#example#> + * @endcode + */ +int ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength(CCNxTlvDictionary *packetDictionary); + +/** + * Returns the bytes of the optional headers + * + * Computes ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength() - sizeof(fixedHeader) + * + * @param [in] fixedHeaderDictionary The FixedHeader dictionary + * + * @retval non-negative The length of the optional headers + * @retval negative An error + * + * Example: + * @code + * <#example#> + * @endcode + */ +int ccnxCodecSchemaV1FixedHeaderDecoder_GetOptionalHeaderLength(CCNxTlvDictionary *packetDictionary); + + +/** + * A convenience function to return the ReturnCode of an Interest or InterestReturn + * + * @param [in] fixedHeaderDictionary The FixedHeader dictionary + * + * @return positive The Return Code + * @return -1 The field does not exist + * + * Example: + * @code + * <#example#> + * @endcode + */ +int ccnxCodecSchemaV1FixedHeaderDecoder_GetReturnCode(CCNxTlvDictionary *packetDictionary); + +/** + * A convenience function to return the header Flags + * + * @param [in] fixedHeaderDictionary The FixedHeader dictionary + * + * @return positive The flags + * @return -1 The field does not exist + * + * Example: + * @code + * <#example#> + * @endcode + */ +int ccnxCodecSchemaV1FixedHeaderDecoder_GetFlags(CCNxTlvDictionary *packetDictionary); + +#endif // Libccnx_ccnxCodecSchemaV1_FixedHeaderDecoder_h diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.c new file mode 100755 index 00000000..3b6eca67 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ +#include + +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include + +ssize_t +ccnxCodecSchemaV1FixedHeaderEncoder_EncodeHeader(CCNxCodecTlvEncoder *fixedHeaderEncoder, const CCNxCodecSchemaV1FixedHeader *header) +{ + assertNotNull(fixedHeaderEncoder, "Parameter fixedHeaderEncoder must be non-null"); + assertNotNull(header, "Parameter header must be non-null"); + trapIllegalValueIf(header->version != 1, "Header wrong version, must be 1"); + + CCNxCodecSchemaV1InterestHeader copy; + + memcpy(©, header, sizeof(CCNxCodecSchemaV1InterestHeader)); + + copy.packetLength = htons(header->packetLength); + + switch (header->packetType) { + case CCNxCodecSchemaV1Types_PacketType_Interest: + copy.returnCode = 0; + break; + + case CCNxCodecSchemaV1Types_PacketType_InterestReturn: + // nothing to do, all fields used + break; + + default: + copy.hopLimit = 0; + copy.returnCode = 0; + copy.flags = 0; + break; + } + + ccnxCodecTlvEncoder_AppendRawArray(fixedHeaderEncoder, sizeof(CCNxCodecSchemaV1FixedHeader), (uint8_t *) ©); + return sizeof(CCNxCodecSchemaV1FixedHeader); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.h new file mode 100755 index 00000000..0981f4bd --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_FixedHeaderEncoder.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file ccnxCodecSchemaV1_FixedHeaderEncoder.h + * @brief <#Brief Description#> + * + * <#Detailed Description#> + * + */ +#ifndef Libccnx_ccnxCodecSchemaV1_FixedHeaderEncoder_h +#define Libccnx_ccnxCodecSchemaV1_FixedHeaderEncoder_h + +#include + +#include + +/** + * Set the values in the fixed header + * + * Put the provided fixed header at the given byte location. The provided fixed header is not put + * in as-is (i.e byte for byte), but is parsed and put in the correct byte positions and encodings + * assuming the fixed header starts at the given position. + * + * The encoder is returned to its current position after putting the header. + * + * @param [in] encoder The encoder to append the fixed header in to + * @param [in] The header, in host byte order + * + * @return Number The bytes appended, or -1 on error + * + * Example: + * @code + * <#example#> + * @endcode + */ +ssize_t ccnxCodecSchemaV1FixedHeaderEncoder_EncodeHeader(CCNxCodecTlvEncoder *encoder, const CCNxCodecSchemaV1FixedHeader *header); +#endif // Libccnx_ccnxCodecSchemaV1_FixedHeaderEncoder_h diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.c new file mode 100644 index 00000000..23a559cc --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ + +#include + +#include + +#include + +#include +#include + +#include +#include + +#include + +/** + * These are the accepted sizes for the pre-defined hash types. + * Hash TLVs with lengths that do not match one of these values will be deemed + * invalid and not parse correctly. + */ +static const size_t _PARCCryptoHashType_SHA256_Sizes[] = { 32 }; +static const size_t _PARCCryptoHashType_SHA512_Sizes[] = { 32, 64 }; + +static bool +_ccnxCodecSchemaV1HashCodec_ValidHashSize(size_t size, size_t numSizes, size_t sizes[numSizes]) +{ + for (size_t i = 0; i < numSizes; i++) { + if (sizes[i] == size) { + return true; + } + } + return false; +} + +ssize_t +ccnxCodecSchemaV1HashCodec_Encode(CCNxCodecTlvEncoder *encoder, const PARCCryptoHash *hash) +{ + PARCBuffer *digest = parcCryptoHash_GetDigest(hash); + PARCCryptoHashType hashType = parcCryptoHash_GetDigestType(hash); + size_t digestLength = parcBuffer_Remaining(digest); + + uint16_t tlvHashType = CCNxCodecSchemaV1Types_HashType_App; + bool validHash = true; + switch (hashType) { + case PARCCryptoHashType_SHA256: + tlvHashType = CCNxCodecSchemaV1Types_HashType_SHA256; + validHash = _ccnxCodecSchemaV1HashCodec_ValidHashSize(digestLength, + sizeof(_PARCCryptoHashType_SHA256_Sizes) / sizeof(size_t), (size_t *) _PARCCryptoHashType_SHA256_Sizes); + break; + case PARCCryptoHashType_SHA512: + tlvHashType = CCNxCodecSchemaV1Types_HashType_SHA512; + validHash = _ccnxCodecSchemaV1HashCodec_ValidHashSize(digestLength, + sizeof(_PARCCryptoHashType_SHA512_Sizes) / sizeof(size_t), (size_t *) _PARCCryptoHashType_SHA512_Sizes); + break; + default: + break; + } + + if (validHash) { + return ccnxCodecTlvEncoder_AppendBuffer(encoder, tlvHashType, digest); + } else { + CCNxCodecError *error = ccnxCodecError_Create(TLV_MISSING_MANDATORY, __func__, __LINE__, ccnxCodecTlvEncoder_Position(encoder)); + ccnxCodecTlvEncoder_SetError(encoder, error); + ccnxCodecError_Release(&error); + + return -1; + } +} + +static bool +_ccnxCodecSchemaV1HashCodec_ValidHash(uint16_t hashType, uint16_t hashSize) +{ + bool validHash = true; + + switch (hashType) { + case CCNxCodecSchemaV1Types_HashType_SHA256: + validHash = _ccnxCodecSchemaV1HashCodec_ValidHashSize(hashSize, + sizeof(_PARCCryptoHashType_SHA256_Sizes) / sizeof(size_t), (size_t *) _PARCCryptoHashType_SHA256_Sizes); + break; + case CCNxCodecSchemaV1Types_HashType_SHA512: + validHash = _ccnxCodecSchemaV1HashCodec_ValidHashSize(hashSize, + sizeof(_PARCCryptoHashType_SHA512_Sizes) / sizeof(size_t), (size_t *) _PARCCryptoHashType_SHA512_Sizes); + break; + default: + break; + } + + return validHash; +} + +PARCCryptoHash * +ccnxCodecSchemaV1HashCodec_DecodeValue(CCNxCodecTlvDecoder *decoder, size_t limit) +{ + PARCCryptoHash *hash = NULL; + uint16_t hashType = 0; + uint16_t length = 0; + + if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, 4)) { + hashType = ccnxCodecTlvDecoder_GetType(decoder); + length = ccnxCodecTlvDecoder_GetLength(decoder); + + if (length > limit) { + CCNxCodecError *error = ccnxCodecError_Create(TLV_MISSING_MANDATORY, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder)); + ccnxCodecTlvDecoder_SetError(decoder, error); + ccnxCodecError_Release(&error); + return NULL; + } + + if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, length)) { + PARCBuffer *value = ccnxCodecTlvDecoder_GetValue(decoder, length); + switch (hashType) { + case CCNxCodecSchemaV1Types_HashType_SHA256: + hash = parcCryptoHash_Create(PARCCryptoHashType_SHA256, value); + break; + case CCNxCodecSchemaV1Types_HashType_SHA512: + hash = parcCryptoHash_Create(PARCCryptoHashType_SHA512, value); + break; + case CCNxCodecSchemaV1Types_HashType_App: + hash = parcCryptoHash_Create(PARCCryptoHashType_NULL, value); + break; + } + parcBuffer_Release(&value); + } + } + + // Verify the hash size, if one was parsed correctly. + if (hash != NULL && !_ccnxCodecSchemaV1HashCodec_ValidHash(hashType, length)) { + parcCryptoHash_Release(&hash); + } + + return hash; +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.h new file mode 100755 index 00000000..f03b3746 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_HashCodec.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file ccnxCodecSchemaV1_HashCodec.h + * @brief A cryptographic hash digest encoded + * + */ + +#ifndef __CCNx_Common__ccnxCodecSchemaV1_HashCodec__ +#define __CCNx_Common__ccnxCodecSchemaV1_HashCodec__ + +#include +#include + +#include + +/** + * Encodes the hash, but without a "TL" container + * + * Will append the Link in it's well-known TLV format, but without any + * "TL" container. + * + * If the link does not have a name, will return -1 with the error TLV_MISSING_MANDATORY. + * + * @param [in] encoder The hash will be appended to the encoder + * @param [in] hash The hash to append + * + * @retval non-negative The number of bytes appended to the encoder + * @retval negative An error, look at the CCNxCodecError of the encoder + * + * Example: + * @code + * <#example#> + * @endcode + */ +ssize_t ccnxCodecSchemaV1HashCodec_Encode(CCNxCodecTlvEncoder *encoder, const PARCCryptoHash *hash); + +/** + * The decoder points to the first byte of the "value" of something that is a Link + * + * For a KeyName, decoder should be pointed to the "value" of the KeyName. for a ContentObject + * of type Link, it should be the first byte of the Payload. + * + * A link is the tuple {Name, [KeyId], [Hash]}, where KeyId is the keyIdRestriction and + * Hash is the ContentObjectHash restriction to use in an Interest for Name. + * No additional fields are allowed in the Link. + * + * @param [in] decoder The Tlv Decoder pointing to the start of the Name value + * @param [in] length the length of the Hash value + * + * @return non-null A parsed name + * @return null An error, check the decoder's error message + * + * Example: + * @code + * <#example#> + * @endcode + */ +PARCCryptoHash *ccnxCodecSchemaV1HashCodec_DecodeValue(CCNxCodecTlvDecoder *decoder, size_t length); + +#endif // __CCNx_Common__ccnxCodecSchemaV1_HashCodec__ diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.c new file mode 100755 index 00000000..cc78c28e --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ + +#include + +#include +#include + +#include + +#include +#include + +#include +#include + +#include +#include + +ssize_t +ccnxCodecSchemaV1LinkCodec_Encode(CCNxCodecTlvEncoder *encoder, const CCNxLink *link) +{ + ssize_t length = 0; + + const CCNxName *name = ccnxLink_GetName(link); + if (name) { + length += ccnxCodecSchemaV1NameCodec_Encode(encoder, CCNxCodecSchemaV1Types_Link_Name, name); + + PARCBuffer *keyid = ccnxLink_GetKeyID(link); + if (keyid) { + length += ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_Link_KeyIdRestriction, keyid); + } + + PARCBuffer *hash = ccnxLink_GetContentObjectHash(link); + if (hash) { + length += ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_Link_ContentObjectHashRestriction, hash); + } + } else { + length = -1; + CCNxCodecError *error = ccnxCodecError_Create(TLV_MISSING_MANDATORY, __func__, __LINE__, ccnxCodecTlvEncoder_Position(encoder)); + ccnxCodecTlvEncoder_SetError(encoder, error); + ccnxCodecError_Release(&error); + } + + return length; +} + +typedef struct decoded_link { + CCNxName *linkName; + PARCBuffer *linkKeyId; + PARCBuffer *linkHash; +} _DecodedLink; + +static int +_decodeField(CCNxCodecTlvDecoder *decoder, _DecodedLink *decodedLink) +{ + int errorCode = TLV_ERR_NO_ERROR; + + uint16_t type = ccnxCodecTlvDecoder_GetType(decoder); + uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder); + + if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, length)) { + switch (type) { + case CCNxCodecSchemaV1Types_Link_Name: + if (decodedLink->linkName == NULL) { + decodedLink->linkName = ccnxCodecSchemaV1NameCodec_DecodeValue(decoder, length); + } else { + errorCode = TLV_ERR_DUPLICATE_FIELD; + } + break; + + case CCNxCodecSchemaV1Types_Link_KeyIdRestriction: + if (decodedLink->linkKeyId == NULL) { + decodedLink->linkKeyId = ccnxCodecTlvDecoder_GetValue(decoder, length); + } else { + errorCode = TLV_ERR_DUPLICATE_FIELD; + } + break; + + case CCNxCodecSchemaV1Types_Link_ContentObjectHashRestriction: + if (decodedLink->linkHash == NULL) { + decodedLink->linkHash = ccnxCodecTlvDecoder_GetValue(decoder, length); + } else { + errorCode = TLV_ERR_DUPLICATE_FIELD; + } + break; + + default: + // we do not support unknown TLVs + errorCode = TLV_ERR_DECODE; + break; + } + } else { + errorCode = TLV_ERR_TOO_LONG; + } + + return errorCode; +} + +static void +_decodecLinkCleanup(_DecodedLink *decodedLink) +{ + if (decodedLink->linkName) { + ccnxName_Release(&decodedLink->linkName); + } + + if (decodedLink->linkKeyId) { + parcBuffer_Release(&decodedLink->linkKeyId); + } + + if (decodedLink->linkHash) { + parcBuffer_Release(&decodedLink->linkHash); + } +} + +CCNxLink * +ccnxCodecSchemaV1LinkCodec_DecodeValue(CCNxCodecTlvDecoder *decoder, uint16_t linkLength) +{ + int errorCode = TLV_ERR_NO_ERROR; + + CCNxLink *link = NULL; + + _DecodedLink decodedLink; + memset(&decodedLink, 0, sizeof(_DecodedLink)); + + if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, linkLength)) { + while (errorCode == TLV_ERR_NO_ERROR && ccnxCodecTlvDecoder_EnsureRemaining(decoder, 4)) { + errorCode = _decodeField(decoder, &decodedLink); + } + } else { + errorCode = TLV_ERR_TOO_LONG; + } + + if (errorCode == TLV_ERR_NO_ERROR && decodedLink.linkName == NULL) { + errorCode = TLV_ERR_DECODE; + } + + if (errorCode != TLV_ERR_NO_ERROR) { + CCNxCodecError *error = ccnxCodecError_Create(errorCode, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder)); + ccnxCodecTlvDecoder_SetError(decoder, error); + ccnxCodecError_Release(&error); + } else { + link = ccnxLink_Create(decodedLink.linkName, decodedLink.linkKeyId, decodedLink.linkHash); + } + + // cleanup any partial memory allocations + _decodecLinkCleanup(&decodedLink); + + return link; +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.h new file mode 100755 index 00000000..4163aa1d --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_LinkCodec.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file ccnxCodecSchemaV1_LinkCodec.h + * @brief A Link is a well-known value, not a TLV field + * + * A Link may be the "value" of a TLV element, such as the KeyName. It can also occur + * in the payload of a ContentObject whose PayloadType is Link. + * + */ + +#ifndef __CCNx_Common__ccnxCodecSchemaV1_LinkCodec__ +#define __CCNx_Common__ccnxCodecSchemaV1_LinkCodec__ + +#include +#include +#include + +/** + * Encodes the link, but without a "TL" container + * + * Will append the Link in it's well-known TLV format, but without any + * "TL" container. + * + * If the link does not have a name, will return -1 with the error TLV_MISSING_MANDATORY. + * + * @param [in] encoder The link will be appended to the encoder + * @param [in] link The link to append + * + * @retval non-negative The number of bytes appended to the encoder + * @retval negative An error, look at the CCNxCodecError of the encoder + * + * Example: + * @code + * <#example#> + * @endcode + */ +ssize_t ccnxCodecSchemaV1LinkCodec_Encode(CCNxCodecTlvEncoder *encoder, const CCNxLink *link); + +/** + * The decoder points to the first byte of the "value" of something that is a Link + * + * For a KeyName, decoder should be pointed to the "value" of the KeyName. for a ContentObject + * of type Link, it should be the first byte of the Payload. + * + * A link is the tuple {Name, [KeyId], [Hash]}, where KeyId is the keyIdRestriction and + * Hash is the ContentObjectHash restriction to use in an Interest for Name. + * No additional fields are allowed in the Link. + * + * @param [in] decoder The Tlv Decoder pointing to the start of the Name value + * @param [in] length the length of the Link value + * + * @return non-null A parsed name + * @return null An error, check the decoder's error message + * + * Example: + * @code + * <#example#> + * @endcode + */ +CCNxLink *ccnxCodecSchemaV1LinkCodec_DecodeValue(CCNxCodecTlvDecoder *decoder, uint16_t length); + +#endif /* defined(__CCNx_Common__ccnxCodecSchemaV1_LinkCodec__) */ diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.c new file mode 100644 index 00000000..87665de1 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/** + */ + +#include + +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +static bool +_decodeHashGroupMetadata(CCNxCodecTlvDecoder *decoder, CCNxManifestHashGroup *group, size_t length) +{ + size_t offset = 0; + bool success = true; + + while (offset < length) { + uint16_t type = ccnxCodecTlvDecoder_GetType(decoder); + uint16_t value_length = ccnxCodecTlvDecoder_GetLength(decoder); + PARCBuffer *value = ccnxCodecTlvDecoder_GetValue(decoder, value_length); + + offset += (4 + value_length); + + switch (type) { + case CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_Locator: { + char *nameString = parcBuffer_ToString(value); + const CCNxName *locator = ccnxName_CreateFromCString(nameString); + ccnxManifestHashGroup_SetLocator(group, locator); + parcMemory_Deallocate(&nameString); + ccnxName_Release((CCNxName **) &locator); + break; + } + case CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_DataSize: { + uint64_t dataSize = parcBuffer_GetUint64(value); + ccnxManifestHashGroup_SetDataSize(group, dataSize); + break; + } + case CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_BlockSize: { + uint64_t blockSize = parcBuffer_GetUint64(value); + ccnxManifestHashGroup_SetBlockSize(group, blockSize); + break; + } + case CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_EntrySize: { + uint64_t entrySize = parcBuffer_GetUint64(value); + ccnxManifestHashGroup_SetEntrySize(group, entrySize); + break; + } + case CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_TreeHeight: { + uint64_t treeHeight = parcBuffer_GetUint64(value); + ccnxManifestHashGroup_SetTreeHeight(group, treeHeight); + break; + } + case CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_OverallDataSha256: { + ccnxManifestHashGroup_SetOverallDataDigest(group, value); + break; + } + } + + parcBuffer_Release(&value); + } + + return success; +} + +static bool +_decodeHashGroup(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, CCNxManifestHashGroup *group, size_t length) +{ + bool success = true; + size_t offset = 0; + + while (offset < length) { + uint16_t type = ccnxCodecTlvDecoder_GetType(decoder); + uint16_t value_length = ccnxCodecTlvDecoder_GetLength(decoder); + + offset += (4 + value_length); + + switch (type) { + case CCNxCodecSchemaV1Types_CCNxManifestHashGroup_Metadata: { + success = _decodeHashGroupMetadata(decoder, group, value_length); + if (!success) { + return false; + } + break; + } + + case CCNxCodecSchemaV1Types_CCNxManifestHashGroup_DataPointer: { + PARCBuffer *buffer = ccnxCodecTlvDecoder_GetValue(decoder, value_length); + ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, buffer); + parcBuffer_Release(&buffer); + break; + } + + case CCNxCodecSchemaV1Types_CCNxManifestHashGroup_ManifestPointer: { + PARCBuffer *buffer = ccnxCodecTlvDecoder_GetValue(decoder, value_length); + ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Manifest, buffer); + parcBuffer_Release(&buffer); + break; + } + + default: + // if we do not know the TLV type, put it in this container's unknown list + success = ccnxCodecTlvUtilities_PutAsListBuffer(decoder, packetDictionary, type, value_length, CCNxCodecSchemaV1TlvDictionary_Lists_MESSAGE_LIST); + break; + } + + if (!success) { + CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder)); + ccnxCodecTlvDecoder_SetError(decoder, error); + ccnxCodecError_Release(&error); + } + } + + CCNxManifestInterface *manifest = ccnxManifestInterface_GetInterface(packetDictionary); + manifest->addHashGroup(packetDictionary, group); + + return success; +} + +static bool +_decodeType(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length) +{ + bool success = false; + switch (type) { + case CCNxCodecSchemaV1Types_CCNxMessage_Name: { + success = ccnxCodecTlvUtilities_PutAsName(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME); + break; + } + + case CCNxCodecSchemaV1Types_CCNxMessage_HashGroup: { + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + success = _decodeHashGroup(decoder, packetDictionary, group, length); + ccnxManifestHashGroup_Release(&group); + 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_MESSAGE_LIST); + break; + } + + if (!success) { + CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder)); + ccnxCodecTlvDecoder_SetError(decoder, error); + ccnxCodecError_Release(&error); + } + return success; +} + +/* + * We are given a decoder that points to the first TLV of a list of TLVs. We keep walking the + * list until we come to the end of the decoder. + */ +bool +ccnxCodecSchemaV1ManifestDecoder_Decode(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *manifestDictionary) +{ + return ccnxCodecTlvUtilities_DecodeContainer(decoder, manifestDictionary, _decodeType); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.h new file mode 100755 index 00000000..1726e41e --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestDecoder.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/** + * @file ccnxCodecSchemaV1_ManifestDecoder.h + * @brief Decode the body of a CCNx Manifest. + * + */ + +#ifndef TransportRTA_ccnxCodecSchemaV1_ManifestDecoder_h +#define TransportRTA_ccnxCodecSchemaV1_ManifestDecoder_h + +#include + +#include +#include + +/** + * Decode a V1 Manifest. + * + * The decoder should point to byte 0 of a Manifest (message) TLV. + * The results are put in the provided dictionary. + * It is an error if the message does not extend to the end of + * the decoder. + * + * @param [in] decoder The decoder to parse + * @param [in] manifestDictionary The results go directly in to the provided dictionary. + * + * @return true Fully parsed interest, no errors + * @return false Error decoding, decoder is left pointing to the first byte of the error + * + * Example: + * @code + * <#example#> + * @endcode + */ +bool ccnxCodecSchemaV1ManifestDecoder_Decode(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *manifestDictionary); + +#endif // TransportRTA_ccnxCodecSchemaV1_ManifestDecoder_h diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.c new file mode 100644 index 00000000..0d8f52bf --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.c @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/** + */ + +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + +static size_t +_appendPointer(CCNxCodecTlvEncoder *encoder, CCNxManifestHashGroupPointer *ptr) +{ + const PARCBuffer *digest = ccnxManifestHashGroupPointer_GetDigest(ptr); + CCNxManifestHashGroupPointerType type = ccnxManifestHashGroupPointer_GetType(ptr); + + ssize_t length = -1; + switch (type) { + case CCNxManifestHashGroupPointerType_Data: + length = ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_CCNxManifestHashGroup_DataPointer, (PARCBuffer *) digest); + break; + case CCNxManifestHashGroupPointerType_Manifest: + length = ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_CCNxManifestHashGroup_ManifestPointer, (PARCBuffer *) digest); + break; + default: + assertTrue(false, "Invalid pointer type %d", type); + } + + if (length < 0) { + CCNxCodecError *error = ccnxCodecError_Create(TLV_MISSING_MANDATORY, __func__, __LINE__, ccnxCodecTlvEncoder_Position(encoder)); + ccnxCodecTlvEncoder_SetError(encoder, error); + ccnxCodecError_Release(&error); + } + + return length; +} + +ssize_t +_appendMetadata(CCNxCodecTlvEncoder *encoder, CCNxManifestHashGroup *group) +{ + ssize_t length = 0; + + // Pre-populate this field -- we'll come back and fill in the length after we're done + size_t startPosition = ccnxCodecTlvEncoder_Position(encoder); + ccnxCodecTlvEncoder_AppendContainer(encoder, CCNxCodecSchemaV1Types_CCNxManifestHashGroup_Metadata, length); + + // Now append all metadata that exists in the hash group. + const CCNxName *locator = ccnxManifestHashGroup_GetLocator(group); + if (locator != NULL) { + char *nameString = ccnxName_ToString(locator); + PARCBuffer *nameBuffer = parcBuffer_AllocateCString(nameString); + length += ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_Locator, nameBuffer); + parcBuffer_Release(&nameBuffer); + parcMemory_Deallocate(&nameString); + } + + size_t dataSize = ccnxManifestHashGroup_GetDataSize(group); + if (dataSize > 0) { + length += ccnxCodecTlvEncoder_AppendUint64(encoder, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_DataSize, dataSize); + } + + size_t blockSize = ccnxManifestHashGroup_GetBlockSize(group); + if (blockSize > 0) { + length += ccnxCodecTlvEncoder_AppendUint64(encoder, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_BlockSize, blockSize); + } + + size_t entrySize = ccnxManifestHashGroup_GetEntrySize(group); + if (entrySize > 0) { + length += ccnxCodecTlvEncoder_AppendUint64(encoder, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_EntrySize, entrySize); + } + + size_t treeSize = ccnxManifestHashGroup_GetTreeHeight(group); + if (treeSize > 0) { + length += ccnxCodecTlvEncoder_AppendUint64(encoder, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_TreeHeight, treeSize); + } + + const PARCBuffer *dataDigest = ccnxManifestHashGroup_GetOverallDataDigest(group); + if (dataDigest != NULL) { + length += ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_OverallDataSha256, (PARCBuffer *) dataDigest); + } + + // Rewind back to the container opening and fill in the length + size_t endPosition = ccnxCodecTlvEncoder_Position(encoder); + ccnxCodecTlvEncoder_PutUint16(encoder, startPosition, CCNxCodecSchemaV1Types_CCNxManifestHashGroup_Metadata); + ccnxCodecTlvEncoder_PutUint16(encoder, startPosition + 2, length); + ccnxCodecTlvEncoder_SetPosition(encoder, endPosition); + + return endPosition - startPosition; +} + +ssize_t +ccnxCodecSchemaV1ManifestEncoder_Encode(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t length = 0; + + ssize_t numHashGroups = ccnxTlvDictionary_ListSize(packetDictionary, CCNxCodecSchemaV1TlvDictionary_Lists_HASH_GROUP_LIST); + for (size_t i = 0; i < numHashGroups; i++) { + // Skip past the TL of the hash group to append the pointers inside + ssize_t groupLength = 0; + ccnxCodecTlvEncoder_AppendContainer(encoder, CCNxCodecSchemaV1Types_CCNxMessage_HashGroup, groupLength); + + CCNxManifestInterface *interface = ccnxManifestInterface_GetInterface(packetDictionary); + CCNxManifestHashGroup *group = interface->getHashGroup(packetDictionary, i); + + // Encode any metadata, if present. + if (ccnxManifestHashGroup_HasMetadata(group)) { + groupLength += _appendMetadata(encoder, group); + } + + // Append the HashGroup pointers + size_t numPointers = ccnxManifestHashGroup_GetNumberOfPointers(group); + for (size_t p = 0; p < numPointers; p++) { + CCNxManifestHashGroupPointer *ptr = ccnxManifestHashGroup_GetPointerAtIndex(group, p); + ssize_t ptrLength = _appendPointer(encoder, ptr); + if (ptrLength < 0) { + return ptrLength; + } + groupLength += ptrLength; + } + + // Now that we know the overall length, rewind back to the start and append the TL + // part of the container. + size_t endPosition = ccnxCodecTlvEncoder_Position(encoder); + ssize_t offset = endPosition - groupLength - 4; + ccnxCodecTlvEncoder_PutUint16(encoder, offset, CCNxCodecSchemaV1Types_CCNxMessage_HashGroup); + ccnxCodecTlvEncoder_PutUint16(encoder, offset + 2, groupLength); + ccnxCodecTlvEncoder_SetPosition(encoder, endPosition); + + length += groupLength + 4; + + ccnxManifestHashGroup_Release(&group); + } + + return length; +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.h new file mode 100755 index 00000000..4951cf80 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ManifestEncoder.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/** + * @file ccnxCodecSchemaV1_ManifestEncoder.h + * @brief Encode a V1 Manifest. + * + */ + +#ifndef ccnx_common_ccnxCodecSchemaV1_ManifestEncoder_h +#define ccnx_common_ccnxCodecSchemaV1_ManifestEncoder_h + +#include +#include + +ssize_t ccnxCodecSchemaV1ManifestEncoder_Encode(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary); + +#endif // ccnx_common_ccnxCodecSchemaV1_ManifestEncoder_h diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.c new file mode 100644 index 00000000..f0dea7a6 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ + +#include + +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +static bool +_translateWirePayloadTypeToCCNxPayloadType(CCNxCodecSchemaV1Types_PayloadType wireFormatType, CCNxPayloadType *payloadTypePtr) +{ + bool success = true; + switch (wireFormatType) { + case CCNxCodecSchemaV1Types_PayloadType_Data: + *payloadTypePtr = CCNxPayloadType_DATA; + break; + + case CCNxCodecSchemaV1Types_PayloadType_Key: + *payloadTypePtr = CCNxPayloadType_KEY; + break; + + case CCNxCodecSchemaV1Types_PayloadType_Link: + *payloadTypePtr = CCNxPayloadType_LINK; + break; + + default: + // unknown type + success = false; + } + return success; +} + +/** + * Translates the wire format value for the PayloadType to CCNxPayloadType + */ +static bool +_decodePayloadType(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t length) +{ + CCNxPayloadType payloadType; + + uint64_t wireFormatVarInt; + bool success = ccnxCodecTlvDecoder_GetVarInt(decoder, length, &wireFormatVarInt); + if (success) { + CCNxCodecSchemaV1Types_PayloadType wireFormatType = (CCNxCodecSchemaV1Types_PayloadType) wireFormatVarInt; + + success = _translateWirePayloadTypeToCCNxPayloadType(wireFormatType, &payloadType); + } + + if (success) { + success = ccnxTlvDictionary_PutInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE, payloadType); + } + + return success; +} + +static bool +_decodeType(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length) +{ + bool success = false; + switch (type) { + case CCNxCodecSchemaV1Types_CCNxMessage_Name: + success = ccnxCodecTlvUtilities_PutAsName(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME); + break; + + case CCNxCodecSchemaV1Types_CCNxMessage_Payload: + success = ccnxCodecTlvUtilities_PutAsBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD); + break; + + case CCNxCodecSchemaV1Types_CCNxMessage_KeyIdRestriction: + success = ccnxCodecTlvUtilities_PutAsHash(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_KEYID_RESTRICTION); + break; + + case CCNxCodecSchemaV1Types_CCNxMessage_ContentObjectHashRestriction: + success = ccnxCodecTlvUtilities_PutAsHash(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION); + break; + + case CCNxCodecSchemaV1Types_CCNxMessage_PayloadType: + success = _decodePayloadType(decoder, packetDictionary, length); + break; + + case CCNxCodecSchemaV1Types_CCNxMessage_ExpiryTime: + success = ccnxCodecTlvUtilities_PutAsInteger(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME); + break; + + case CCNxCodecSchemaV1Types_CCNxMessage_EndChunkNumber: + success = ccnxCodecTlvUtilities_PutAsInteger(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT); + 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_MESSAGE_LIST); + break; + } + + if (!success) { + CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder)); + ccnxCodecTlvDecoder_SetError(decoder, error); + ccnxCodecError_Release(&error); + } + + return success; +} + +/* + * We are given a decoder that points to the first TLV of a list of TLVs. We keep walking the + * list until we come to the end of the decoder. + */ +bool +ccnxCodecSchemaV1MessageDecoder_Decode(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary) +{ + return ccnxCodecTlvUtilities_DecodeContainer(decoder, packetDictionary, _decodeType); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.h new file mode 100755 index 00000000..30a998aa --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageDecoder.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file ccnxCodecSchemaV1_MessageDecoder.h + * @brief <#Brief Description#> + * + * Decodes the CCNx message body for an Interest or a ContentObject. + * + * The current CPI Control packet does not use the MessageDecoder or MessageEncoder. It is handled + * entirely in the Packet{De,En}coder. + * + */ + +#ifndef TransportRTA_ccnxCodecSchemaV1_MessageDecoder_h +#define TransportRTA_ccnxCodecSchemaV1_MessageDecoder_h + +#include + +#include +#include + +/** + * The decode a V1 message, maybe any message type + * + * The decoder should point to byte 0 of the message TLV + * The results are put in the provided dictionary. + * It is an error if the message does not extend to the end of + * the decoder. + * + * @param [in] decoder The decoder to parse + * @param [in] contentObjectDictionary The results go directly in to the provided dictionary. + * + * @return true Fully parsed interest, no errors + * @return false Error decoding, decoder is left pointing to the first byte of the error + * + * Example: + * @code + * <#example#> + * @endcode + */ +bool ccnxCodecSchemaV1MessageDecoder_Decode(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *contentObjectDictionary); + + +#endif // TransportRTA_ccnxCodecSchemaV1_MessageDecoder_h diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.c new file mode 100755 index 00000000..7aa14627 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.c @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ + +#include + +#include +#include + +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include + +static ssize_t +_encodeName(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t length = -1; + CCNxName *name = ccnxTlvDictionary_GetName(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME); + if (name != NULL) { + length = ccnxCodecSchemaV1NameCodec_Encode(encoder, CCNxCodecSchemaV1Types_CCNxMessage_Name, name); + } + + // required field for everything except CCNxContentObjects + if (!ccnxTlvDictionary_IsContentObject(packetDictionary) && length < 0) { + CCNxCodecError *error = ccnxCodecError_Create(TLV_MISSING_MANDATORY, __func__, __LINE__, ccnxCodecTlvEncoder_Position(encoder)); + ccnxCodecTlvEncoder_SetError(encoder, error); + ccnxCodecError_Release(&error); + } else if (ccnxTlvDictionary_IsContentObject(packetDictionary) && name == NULL) { + length = 0; + } + + return length; +} + +static ssize_t +_encodeJsonPayload(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t length = 0; + PARCJSON *json = ccnxTlvDictionary_GetJson(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD); + if (json != NULL) { + char *jsonString = parcJSON_ToCompactString(json); + size_t len = strlen(jsonString); + length = ccnxCodecTlvEncoder_AppendArray(encoder, CCNxCodecSchemaV1Types_CCNxMessage_Payload, len, (uint8_t *) jsonString); + } + return length; +} + +static ssize_t +_encodePayload(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t length = 0; + PARCBuffer *buffer = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD); + if (buffer != NULL) { + length = ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_CCNxMessage_Payload, buffer); + } + return length; +} + +static ssize_t +_encodePayloadType(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t length = 0; + if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE)) { + CCNxPayloadType payloadType = (CCNxPayloadType) ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE); + + CCNxCodecSchemaV1Types_PayloadType wireFormatType = CCNxCodecSchemaV1Types_PayloadType_Data; + + switch (payloadType) { + case CCNxPayloadType_KEY: + wireFormatType = CCNxCodecSchemaV1Types_PayloadType_Key; + break; + + case CCNxPayloadType_LINK: + wireFormatType = CCNxCodecSchemaV1Types_PayloadType_Link; + break; + + default: + // anything else is encoded as DATA + break; + } + + length = ccnxCodecTlvEncoder_AppendUint8(encoder, CCNxCodecSchemaV1Types_CCNxMessage_PayloadType, wireFormatType); + } else if (ccnxTlvDictionary_IsValueBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE)) { + PARCBuffer *buffer = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE); + length = ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_CCNxMessage_PayloadType, buffer); + } + + return length; +} + +static ssize_t +_encodeExpiryTime(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t length = 0; + if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME)) { + uint64_t millis = ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME); + length = ccnxCodecTlvEncoder_AppendUint64(encoder, CCNxCodecSchemaV1Types_CCNxMessage_ExpiryTime, millis); + } else if (ccnxTlvDictionary_IsValueBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME)) { + PARCBuffer *buffer = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME); + length = ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_CCNxMessage_ExpiryTime, buffer); + } + + return length; +} + +static ssize_t +_encodeEndChunkNumber(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t length = 0; + if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT)) { + uint64_t endChunkId = ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT); + length = ccnxCodecTlvEncoder_AppendVarInt(encoder, CCNxCodecSchemaV1Types_CCNxMessage_EndChunkNumber, endChunkId); + } else { + PARCBuffer *buffer = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT); + if (buffer != NULL) { + length = ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_CCNxMessage_EndChunkNumber, buffer); + } + } + return length; +} + +static ssize_t +_encodeKeyIdRestriction(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t length = 0; + PARCCryptoHash *hash = ccnxTlvDictionary_GetObject(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_KEYID_RESTRICTION); + if (hash != NULL) { + size_t startPosition = ccnxCodecTlvEncoder_Position(encoder); + ccnxCodecTlvEncoder_AppendContainer(encoder, CCNxCodecSchemaV1Types_CCNxMessage_KeyIdRestriction, 0); + length = ccnxCodecSchemaV1HashCodec_Encode(encoder, hash); + if (length < 0) { + return length; + } + + ccnxCodecTlvEncoder_SetContainerLength(encoder, startPosition, length); + length += 4; // this accounts for the TL fields + } + return length; +} + +static ssize_t +_encodeContentObjectHashRestriction(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t length = 0; + PARCCryptoHash *hash = ccnxTlvDictionary_GetObject(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION); + if (hash != NULL) { + size_t startPosition = ccnxCodecTlvEncoder_Position(encoder); + ccnxCodecTlvEncoder_AppendContainer(encoder, CCNxCodecSchemaV1Types_CCNxMessage_ContentObjectHashRestriction, 0); + length = ccnxCodecSchemaV1HashCodec_Encode(encoder, hash); + if (length < 0) { + return length; + } + + ccnxCodecTlvEncoder_SetContainerLength(encoder, startPosition, length); + length += 4; // this accounts for the TL fields + } + return length; +} + + +static ssize_t +_encodeContentObject(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t length = 0; + ssize_t result; + + result = _encodeName(encoder, packetDictionary); + if (result < 0) { + return result; + } + length += result; + + result = _encodePayloadType(encoder, packetDictionary); + if (result < 0) { + return result; + } + length += result; + + result = _encodeExpiryTime(encoder, packetDictionary); + if (result < 0) { + return result; + } + length += result; + + result = _encodeEndChunkNumber(encoder, packetDictionary); + if (result < 0) { + return result; + } + length += result; + + result = _encodePayload(encoder, packetDictionary); + if (result < 0) { + return result; + } + length += result; + + return length; +} + +static ssize_t +_encodeInterest(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t length = 0; + ssize_t result; + + result = _encodeName(encoder, packetDictionary); + if (result < 0) { + return result; + } + length += result; + + result = _encodeKeyIdRestriction(encoder, packetDictionary); + if (result < 0) { + return result; + } + length += result; + + result = _encodeContentObjectHashRestriction(encoder, packetDictionary); + if (result < 0) { + return result; + } + length += result; + + result = _encodePayload(encoder, packetDictionary); + if (result < 0) { + return result; + } + length += result; + + return length; +} + +static ssize_t +_encodeControl(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t length = 0; + ssize_t result; + + result = _encodeName(encoder, packetDictionary); + if (result < 0) { + return result; + } + length += result; + + result = _encodeJsonPayload(encoder, packetDictionary); + if (result < 0) { + return result; + } + length += result; + + return length; +} + +static ssize_t +_encodeManifest(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t length = 0; + ssize_t result; + + result = _encodeName(encoder, packetDictionary); + if (result < 0) { + return result; + } + length += result; + + result = ccnxCodecSchemaV1ManifestEncoder_Encode(encoder, packetDictionary); + if (result < 0) { + return result; + } + length += result; + + return length; +} + +ssize_t +ccnxCodecSchemaV1MessageEncoder_Encode(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary) +{ + assertNotNull(encoder, "Parameter encoder must be non-null"); + assertNotNull(packetDictionary, "Parameter packetDictionary must be non-null"); + + ssize_t length = -1; + + if (ccnxTlvDictionary_IsInterest(packetDictionary)) { + length = _encodeInterest(encoder, packetDictionary); + } else if (ccnxTlvDictionary_IsInterestReturn(packetDictionary)) { + length = _encodeInterest(encoder, packetDictionary); + } else if (ccnxTlvDictionary_IsContentObject(packetDictionary)) { + length = _encodeContentObject(encoder, packetDictionary); + } else if (ccnxTlvDictionary_IsControl(packetDictionary)) { + length = _encodeControl(encoder, packetDictionary); + } else if (ccnxTlvDictionary_IsManifest(packetDictionary)) { + length = _encodeManifest(encoder, packetDictionary); + } else { + CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_PACKETTYPE, __func__, __LINE__, ccnxCodecTlvEncoder_Position(encoder)); + ccnxCodecTlvEncoder_SetError(encoder, error); + ccnxCodecError_Release(&error); + length = -1; + } + + + if (length >= 0) { + // Put custom fields all last + ssize_t customLength = ccnxCodecTlvUtilities_EncodeCustomList(encoder, packetDictionary, CCNxCodecSchemaV1TlvDictionary_Lists_MESSAGE_LIST); + if (customLength < 0) { + return customLength; + } + length += customLength; + } + + return length; +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.h new file mode 100755 index 00000000..d49417fb --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_MessageEncoder.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file ccnxCodecSchemaV1_MessageEncoder.h + * @brief Encode the list of optional headers + * + */ + +#ifndef TransportRTA_ccnxCodecSchemaV1_MessageEncoder_h +#define TransportRTA_ccnxCodecSchemaV1_MessageEncoder_h + +#include +#include +#include + +/** + * Encodes the body of the CCNxMessage + * + * Encodes an Interest, ContentObject, or Control message + * + * @param [in] encoder Appends the CCNx message to the encoder + * @param [in] packetDictionary The fields to encode + * + * @return non-negative Total bytes appended to encoder + * @return -1 An error + * + * Example: + * @code + * <#example#> + * @endcode + */ +ssize_t ccnxCodecSchemaV1MessageEncoder_Encode(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary); + +#endif // TransportRTA_ccnxCodecSchemaV1_MessageEncoder_h diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.c new file mode 100755 index 00000000..a769477f --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +size_t +ccnxCodecSchemaV1NameCodec_Encode(CCNxCodecTlvEncoder *encoder, uint16_t type, const CCNxName *name) +{ + assertNotNull(encoder, "Parameter encoder must be non-null"); + assertNotNull(name, "Parameter name must be non-null"); + + size_t containerPosition = ccnxCodecTlvEncoder_Position(encoder); + size_t containerLength = ccnxCodecTlvEncoder_AppendContainer(encoder, type, 0); + + size_t segmentCount = ccnxName_GetSegmentCount(name); + size_t innerLength = 0; + for (int i = 0; i < segmentCount; i++) { + CCNxNameSegment *segment = ccnxName_GetSegment(name, i); + innerLength += ccnxCodecSchemaV1NameSegmentCodec_Encode(encoder, segment); + } + + // now go back and fixup the container's length + ccnxCodecTlvEncoder_SetContainerLength(encoder, containerPosition, innerLength); + + return containerLength + innerLength; +} + +CCNxName * +ccnxCodecSchemaV1NameCodec_Decode(CCNxCodecTlvDecoder *decoder, uint16_t type) +{ + CCNxName *name = NULL; + if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, 4)) { + uint16_t tlvtype = ccnxCodecTlvDecoder_PeekType(decoder); + if (tlvtype == type) { + // call just for the side-effect of advancing the buffer + (void) ccnxCodecTlvDecoder_GetType(decoder); + uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder); + + name = ccnxCodecSchemaV1NameCodec_DecodeValue(decoder, length); + } + } + + return name; +} + +CCNxName * +ccnxCodecSchemaV1NameCodec_DecodeValue(CCNxCodecTlvDecoder *decoder, uint16_t length) +{ + CCNxName *name = NULL; + if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, length)) { + name = ccnxName_Create(); + size_t nameEnd = ccnxCodecTlvDecoder_Position(decoder) + length; + + while (ccnxCodecTlvDecoder_Position(decoder) < nameEnd) { + CCNxNameSegment *segment = ccnxCodecSchemaV1NameSegmentCodec_Decode(decoder); + ccnxName_Append(name, segment); + ccnxNameSegment_Release(&segment); + } + } + return name; +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h new file mode 100755 index 00000000..6c3298a2 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameCodec.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file ccnxCodecSchemaV1_NameCodec.h + * @brief TLV codec for CCNx types + * + * <#Detailed Description#> + * + */ + +#ifndef CCNxCodecSchemaV1_NameCodec_h +#define CCNxCodecSchemaV1_NameCodec_h + +#include +#include +#include + +/** + * Encodes the name to the TLV Encoder + * + * Will append the Name after the current encoder location + * + * @param [in] type The TLV type to use for the Name container + * + * @return bytes The number of bytes appended to the encoder + * + * Example: + * @code + * <#example#> + * @endcode + */ +size_t ccnxCodecSchemaV1NameCodec_Encode(CCNxCodecTlvEncoder *encoder, uint16_t type, const CCNxName *name); + +/** + * Decode the buffer as a CCNxName beginning at the current position + * + * The buffer must be pointing to the beginnig of the "type". The decoder will + * verify that the type matches `type'. If it does not match, it will return NULL. + * + * @param [in] decoder The decoder + * @param [in] type The TLV type that the decoder should currently be pointing at + * + * @return non-null The CCNxName decoded + * @return null An error: either type did not match or some other error + * + * Example: + * @code + * <#example#> + * @endcode + */ +CCNxName *ccnxCodecSchemaV1NameCodec_Decode(CCNxCodecTlvDecoder *decoder, uint16_t type); + +/** + * The decoder points to the first byte of the Name "value" + * + * <#Paragraphs Of Explanation#> + * + * @param [in] decoder The Tlv Decoder pointing to the start of the Name value + * @param [in] length the length of the Name value + * + * @return non-null A parsed name + * @return null An error + * + * Example: + * @code + * <#example#> + * @endcode + */ +CCNxName *ccnxCodecSchemaV1NameCodec_DecodeValue(CCNxCodecTlvDecoder *decoder, uint16_t length); +#endif // CCNxCodecSchemaV1_NameCodec_h diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.c new file mode 100755 index 00000000..55d02bab --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ + +#include +#include +#include +#include +#include +#include + +#include + +size_t +ccnxCodecSchemaV1NameSegmentCodec_Encode(CCNxCodecTlvEncoder *encoder, CCNxNameSegment *segment) +{ + assertTrue(ccnxNameSegment_Length(segment) <= UINT16_MAX, + "Name segment too long! length %zu maximum %u", + ccnxNameSegment_Length(segment), + UINT16_MAX); + + uint16_t segment_type = ccnxNameSegment_GetType(segment); + PARCBuffer *value = ccnxNameSegment_GetValue(segment); + + return ccnxCodecTlvEncoder_AppendBuffer(encoder, segment_type, value); +} + +CCNxNameSegment * +ccnxCodecSchemaV1NameSegmentCodec_Decode(CCNxCodecTlvDecoder *decoder) +{ + CCNxNameSegment *segment = NULL; + + if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, 4)) { + uint16_t type = ccnxCodecTlvDecoder_GetType(decoder); + uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder); + + if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, length)) { + PARCBuffer *value = ccnxCodecTlvDecoder_GetValue(decoder, length); + segment = ccnxNameSegment_CreateTypeValue(type, value); + parcBuffer_Release(&value); + } + } + + return segment; +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.h new file mode 100755 index 00000000..c6797cff --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_NameSegmentCodec.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file ccnxCodecSchemaV1_NameSegmentCodec.h + * @brief TLV codec for CCNx types + * + * Encode/decode a CCNx name segment using the V1 schema + * + */ + +#ifndef CCNxCodecSchemaV1_NameSegmentCodec_h +#define CCNxCodecSchemaV1_NameSegmentCodec_h + +#include +#include +#include + +/** + * Encodes the name segment using the segment type as the TLV type + * + * Appends the name segment to the encoder. The TLV type is implicit in + * the CCNxNameSegment. + * + * @param [<#in out in,out#>] <#name#> <#description#> + * + * @return number The number of bytes appended, including the type and length. + * + * Example: + * @code + * <#example#> + * @endcode + */ +size_t ccnxCodecSchemaV1NameSegmentCodec_Encode(CCNxCodecTlvEncoder *encoder, CCNxNameSegment *segment); + +/** + * Decodes the current location of the decoder as a CCNxNameSegment + * + * <#Paragraphs Of Explanation#> + * + * @param [in] decoder The decoder object + * + * @return non-null A CCNxNameSement + * @return null An error, such as buffer underrun + * + * Example: + * @code + * <#example#> + * @endcode + */ +CCNxNameSegment *ccnxCodecSchemaV1NameSegmentCodec_Decode(CCNxCodecTlvDecoder *decoder); +#endif // CCNxCodecSchemaV1_NameSegmentCodec_h diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.c new file mode 100755 index 00000000..48554b9a --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ + +#include + +#include +#include + +#include + +#include +#include + +#include +#include +#include + +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; + case CCNxCodecSchemaV1Types_OptionalHeaders_PathLabel: + success = ccnxCodecTlvUtilities_PutAsInteger(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel); + 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; +} + +/* + * We are given a decoder that points to the first TLV of a list of TLVs. We keep walking the + * list until we come to the end of the decoder. + */ +bool +ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary) +{ + return ccnxCodecTlvUtilities_DecodeContainer(decoder, packetDictionary, _decodeType); +} + +// ==== Getters + +PARCBuffer * +ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader(CCNxTlvDictionary *packetDictionary) +{ + PARCBuffer *buffer = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG); + return buffer; +} + +PARCBuffer * +ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader(CCNxTlvDictionary *packetDictionary) +{ + PARCBuffer *buffer = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_OBJFRAG); + return buffer; +} + +uint64_t +ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader(CCNxTlvDictionary *packetDictionary) +{ + uint64_t lifetime = ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime); + return lifetime; +} + +uint64_t +ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader(CCNxTlvDictionary *packetDictionary) +{ + uint64_t cachetime = ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime); + return cachetime; +} + +uint64_t +ccnxCodecSchemaV1OptionalHeadersDecoder_GetPathLabel(CCNxTlvDictionary *packetDictionary) +{ + uint64_t pathLabel = ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel); + return pathLabel; +} + +PARCBuffer * +ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomType(CCNxTlvDictionary *packetDictionary, uint32_t key) +{ + PARCBuffer *buffer = ccnxTlvDictionary_ListGetByType(packetDictionary, CCNxCodecSchemaV1TlvDictionary_Lists_HEADERS, key); + return buffer; +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.h new file mode 100755 index 00000000..94463ad1 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersDecoder.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file ccnxCodecSchemaV1_OptionalHeadersDecoder.h + * @brief Decode the list of optional headers + * + * A reference to each optional header will be stored in the provided CCNxTlvDictionary. + * + */ + +#ifndef TransportRTA_ccnxCodecSchemaV1_OptionalHeadersDecoder_h +#define TransportRTA_ccnxCodecSchemaV1_OptionalHeadersDecoder_h + +#include + +#include + +#include +#include + +/** + * The decode a list of Version 1 optional headers + * + * The decoder should point to the first byte of the first optional header. + * The decoder will advance until the end of the buffer. + * It is an error for the last optional header to either go beyond the end of the + * decoder or for it to underrun the end of the decoder. It must exactly align. + * + * @param [in] decoder The decoder to parse + * @param [in] packetDictionary The results go directly in to the provided dictionary. + * + * @return true Fully parsed interest, no errors + * @return false Error decoding, decoder is left pointing to the first byte of the error + * + * Example: + * @code + * <#example#> + * @endcode + */ +bool ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary); + +/** + * A convenience function to return the Interest Fragment header buffer + * + * <#Paragraphs Of Explanation#> + * + * @param [in] packetDictionary The packet dictionary + * + * @return non-null The header buffer + * @return null The header does not exist + * + * Example: + * @code + * <#example#> + * @endcode + */ +PARCBuffer *ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader(CCNxTlvDictionary *packetDictionary); + +/** + * A convenience function to return the Content Object Fragment header buffer + * + * <#Paragraphs Of Explanation#> + * + * @param [in] packetDictionary The packet dictionary + * + * @return non-null The header buffer + * @return null The header does not exist + * + * Example: + * @code + * <#example#> + * @endcode + */ +PARCBuffer *ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader(CCNxTlvDictionary *packetDictionary); + +/** + * A convenience function to return the Interest Lifetime header value + * + * Returns the byte array of the Interest Lifetime, which is encoded as a uint64_t milli-seconds + * since the UTC epoch. The PARCBuffer returned wraps the underlying memory so any changes to the + * buffer will be reflected in the header. + * + * @param [in] packetDictionary The packet dictionary + * + * @return number The Interest Lifetime + * + * Example: + * @code + * <#example#> + * @endcode + */ +uint64_t ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader(CCNxTlvDictionary *packetDictionary); + +/** + * A convenience function to return the Recommended Cache Time (RCT) header + * + * Returns the byte array of the RCT, which is encoded as a uint64_t milli-seconds + * since the UTC epoch. The PARCBuffer returned wraps the underlying memory so any changes to the + * buffer will be reflected in the header. + * + * @param [in] packetDictionary The packet dictionary + * + * @return number The Recommended Cache Time + * + * Example: + * @code + * <#example#> + * @endcode + */ +uint64_t ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader(CCNxTlvDictionary *packetDictionary); + +uint64_t ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedPathLabel(CCNxTlvDictionary *packetDictionary); + +/** + * Retrieves a TLV header that is not part of the V1 schema spec + * + * <#Paragraphs Of Explanation#> + * + * @param [<#in out in,out#>] <#name#> <#description#> + * + * @return non-NULL The header + * @return NULL The header field does not exist + * + * Example: + * @code + * <#example#> + * @endcode + */ +PARCBuffer *ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomType(CCNxTlvDictionary *packetDictionary, uint32_t key); + +#endif // TransportRTA_ccnxCodecSchemaV1_OptionalHeadersDecoder_h diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.c new file mode 100755 index 00000000..f108a1c3 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ + +#include + +#include +#include + +#include + +#include +#include + +#include +#include +#include + +static ssize_t +_EncodeInterestLifetime(CCNxCodecTlvEncoder *optionalHeadersEncoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t length = 0; + + // allow either encoding as an Integer or as a Buffer + + if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime)) { + uint64_t lifetime = ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime); + length = ccnxCodecTlvEncoder_AppendVarInt(optionalHeadersEncoder, CCNxCodecSchemaV1Types_OptionalHeaders_InterestLifetime, lifetime); + } else if (ccnxTlvDictionary_IsValueBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime)) { + PARCBuffer *lifetime = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime); + length = ccnxCodecTlvEncoder_AppendBuffer(optionalHeadersEncoder, CCNxCodecSchemaV1Types_OptionalHeaders_InterestLifetime, lifetime); + } + + return length; +} + +static ssize_t +_EncodeRecommendedCacheTime(CCNxCodecTlvEncoder *optionalHeadersEncoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t length = 0; + + // allow either encoding as an Integer or as a Buffer + + if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime)) { + uint64_t cacheTime = ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime); + length = ccnxCodecTlvEncoder_AppendVarInt(optionalHeadersEncoder, CCNxCodecSchemaV1Types_OptionalHeaders_RecommendedCacheTime, cacheTime); + } else if (ccnxTlvDictionary_IsValueBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime)) { + PARCBuffer *cacheTime = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime); + length = ccnxCodecTlvEncoder_AppendBuffer(optionalHeadersEncoder, CCNxCodecSchemaV1Types_OptionalHeaders_RecommendedCacheTime, cacheTime); + } + + return length; +} + +static ssize_t +_EncodePathLabel(CCNxCodecTlvEncoder *optionalHeadersEncoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t length = 0; + + if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel)) { + uint16_t pathLabel = ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel); + length = ccnxCodecTlvEncoder_AppendVarInt(optionalHeadersEncoder, CCNxCodecSchemaV1Types_OptionalHeaders_PathLabel, pathLabel); + } else if (ccnxTlvDictionary_IsValueBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel)) { + PARCBuffer *pathLabel = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel); + length = ccnxCodecTlvEncoder_AppendBuffer(optionalHeadersEncoder, CCNxCodecSchemaV1Types_OptionalHeaders_PathLabel, pathLabel); + } + + return length; +} + +static ssize_t +_EncodeInterestFrag(CCNxCodecTlvEncoder *optionalHeadersEncoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t length = 0; + PARCBuffer *buffer = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG); + if (buffer != NULL) { + length = ccnxCodecTlvEncoder_AppendBuffer(optionalHeadersEncoder, CCNxCodecSchemaV1Types_OptionalHeaders_InterestFragment, buffer); + } + return length; +} + +static ssize_t +_EncodeContentObjectFrag(CCNxCodecTlvEncoder *optionalHeadersEncoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t length = 0; + PARCBuffer *buffer = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_OBJFRAG); + if (buffer != NULL) { + length = ccnxCodecTlvEncoder_AppendBuffer(optionalHeadersEncoder, CCNxCodecSchemaV1Types_OptionalHeaders_ContentObjectFragment, buffer); + } + return length; +} + +static ssize_t +_EncodeInterestHeaders(CCNxCodecTlvEncoder *optionalHeadersEncoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t length = 0; + ssize_t intFragLength = _EncodeInterestFrag(optionalHeadersEncoder, packetDictionary); + if (intFragLength < 0) { + return intFragLength; + } + length += intFragLength; + + ssize_t intLifeLength = _EncodeInterestLifetime(optionalHeadersEncoder, packetDictionary); + if (intLifeLength < 0) { + return intLifeLength; + } + length += intLifeLength; + + ssize_t customLength = ccnxCodecTlvUtilities_EncodeCustomList(optionalHeadersEncoder, packetDictionary, CCNxCodecSchemaV1TlvDictionary_Lists_HEADERS); + if (customLength < 0) { + return customLength; + } + length += customLength; + + return length; +} + +static ssize_t +_EncodeContentObjectHeaders(CCNxCodecTlvEncoder *optionalHeadersEncoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t length = 0; + ssize_t result; + + result = _EncodeContentObjectFrag(optionalHeadersEncoder, packetDictionary); + if (result < 0) { + return result; + } + length += result; + + result = _EncodeRecommendedCacheTime(optionalHeadersEncoder, packetDictionary); + if (result < 0) { + return result; + } + length += result; + + result = _EncodePathLabel(optionalHeadersEncoder, packetDictionary); + if (result < 0) { + return result; + } + length += result; + + result = ccnxCodecTlvUtilities_EncodeCustomList(optionalHeadersEncoder, packetDictionary, CCNxCodecSchemaV1TlvDictionary_Lists_HEADERS); + if (result < 0) { + return result; + } + length += result; + + return length; +} + + +ssize_t +ccnxCodecSchemaV1OptionalHeadersEncoder_Encode(CCNxCodecTlvEncoder *optionalHeadersEncoder, CCNxTlvDictionary *packetDictionary) +{ + assertNotNull(optionalHeadersEncoder, "Parameter optionalHeadersEncoder must be non-null"); + assertNotNull(packetDictionary, "Parameter packetDictionary must be non-null"); + + ssize_t result = 0; + if (ccnxTlvDictionary_IsInterest(packetDictionary) || ccnxTlvDictionary_IsInterestReturn(packetDictionary)) { + result = _EncodeInterestHeaders(optionalHeadersEncoder, packetDictionary); + } else if (ccnxTlvDictionary_IsContentObject(packetDictionary) || ccnxTlvDictionary_IsManifest(packetDictionary)) { + result = _EncodeContentObjectHeaders(optionalHeadersEncoder, packetDictionary); + } else if (ccnxTlvDictionary_IsControl(packetDictionary)) { + result = ccnxCodecTlvUtilities_EncodeCustomList(optionalHeadersEncoder, packetDictionary, CCNxCodecSchemaV1TlvDictionary_Lists_HEADERS); + } else { + CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_PACKETTYPE, __func__, __LINE__, ccnxCodecTlvEncoder_Position(optionalHeadersEncoder)); + ccnxCodecTlvEncoder_SetError(optionalHeadersEncoder, error); + ccnxCodecError_Release(&error); + result = -1; + } + + return result; +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.h new file mode 100755 index 00000000..3f7632ca --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_OptionalHeadersEncoder.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file ccnxCodecSchemaV1_OptionalHeadersEncoder.h + * @brief Encode the list of optional headers + * + */ + +#ifndef TransportRTA_ccnxCodecSchemaV1_OptionalHeadersEncoder_h +#define TransportRTA_ccnxCodecSchemaV1_OptionalHeadersEncoder_h + +#include +#include + +/** + * Appends the Optional Headers to the encoderder + * + * <#Paragraphs Of Explanation#> + * + * @param [in] encoder An allocated encoder to append to + * @param [in] packetDictionary The dictionary containing the optional headers + * + * @return non-negative Total bytes appended to encoder + * @return -1 An error + * + * Example: + * @code + * <#example#> + * @endcode + */ +ssize_t ccnxCodecSchemaV1OptionalHeadersEncoder_Encode(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary); + +#endif // TransportRTA_ccnxCodecSchemaV1_OptionalHeadersEncoder_h diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.c new file mode 100644 index 00000000..692b3291 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.c @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +typedef struct rta_tlv_schema_v1_data { + CCNxCodecTlvDecoder *decoder; + CCNxTlvDictionary *packetDictionary; +} _CCNxCodecSchemaV1Data; + +/** + * Decodes the per-hop optional headers + * + * @param [in] data The packet decoder state + * + * @return true successful decode + * @return false A decoding error + * + * Example: + * @code + * <#example#> + * @endcode + */ +static bool +_decodeOptionalHeaders(_CCNxCodecSchemaV1Data *data) +{ + size_t optionalHeaderLength = ccnxCodecSchemaV1FixedHeaderDecoder_GetOptionalHeaderLength(data->packetDictionary); + CCNxCodecTlvDecoder *optionalHeaderDecoder = ccnxCodecTlvDecoder_GetContainer(data->decoder, optionalHeaderLength); + + bool success = ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(optionalHeaderDecoder, data->packetDictionary); + + ccnxCodecTlvDecoder_Destroy(&optionalHeaderDecoder); + return success; +} + +/** + * Decodes the "value" of the CPI "TLV" + * + * the CPI packet is encoded as a single TLV container of type 0xBEEF (detected in _decodeMessage). + * At this point, the cpiDecoder wraps the CPI payload, which is the encapsulated JSON + * + * @param [in] cpiDecoder Decoder wrapping the value + * @param [in] packetDictionary where to place the results + * + * @retval true Good decode + * @retval false An error + * + * Example: + * @code + * <#example#> + * @endcode + */ +static bool +_decodeCPI(CCNxCodecTlvDecoder *cpiDecoder, CCNxTlvDictionary *packetDictionary) +{ + // we just take the whole contents of the decoder and put in the the PAYLOAD dictionary entry. + size_t length = ccnxCodecTlvDecoder_Remaining(cpiDecoder); + PARCBuffer *payload = ccnxCodecTlvDecoder_GetValue(cpiDecoder, length); + + PARCJSON *json = parcJSON_ParseBuffer(payload); + + bool success = ccnxTlvDictionary_PutJson(packetDictionary, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD, json); + parcJSON_Release(&json); + parcBuffer_Release(&payload); + 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 + case CCNxCodecSchemaV1Types_MessageType_Manifest: // 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 if (tlv_type == CCNxCodecSchemaV1Types_MessageType_Manifest) { + ccnxTlvDictionary_SetMessageType_Manifest(data->packetDictionary, CCNxTlvDictionary_SchemaVersion_V1); + success = ccnxCodecSchemaV1ManifestDecoder_Decode(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 +_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; +} + +static bool +_decodeValidationPayload(_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_ValidationPayload && + ccnxCodecTlvDecoder_EnsureRemaining(data->decoder, tlv_length)) { + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_GetContainer(data->decoder, tlv_length); + + success = ccnxCodecSchemaV1ValidationDecoder_DecodePayload(decoder, data->packetDictionary); + + ccnxCodecTlvDecoder_Destroy(&decoder); + } + } + + return success; +} + +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; +} + +bool +ccnxCodecSchemaV1PacketDecoder_BufferDecode(PARCBuffer *packetBuffer, CCNxTlvDictionary *packetDictionary) +{ + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, packetDictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); + return success; +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.h new file mode 100755 index 00000000..9c1defd9 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketDecoder.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file ccnxCodecSchemaV1_PacketDecoder.h + * @brief Decoder for the version 1 TLV Packet + * + * The Schema version 1 Dictionary is organized in containers: FixedHeader, OptionalHeaders, (Interest, ContentObject, Control), Verification. + * + * Each container is its own dictionary. + * + * Example: + * @code + * { + * CCNxTlvDictionary *packetDictionary = ccnxTlvDictionary_Create(); + * ccnxCodecSchemaV1PacketDecoder_Decode(packetBuffer, packetDictionary); + * // the fields in the packetDictionary are now set + * } + * @endcode + * + */ + +#ifndef CCNxCodecSchemaV1_PacketDecoder_h +#define CCNxCodecSchemaV1_PacketDecoder_h + +#include +#include +#include + + +/** + * Decode a packet in to a dictionary. + * + * The buffer should be set at the start of the fixed header. This call is equivalent + * to ccnxCodecSchemaV1PacketDecoder_Decode(), except it allocates and destroys a temporary + * CCNxCodecTlvDecoder. + * + * The dictionary will be filled in with all fields available in the packetBuffer. + * + * Caveat: there is no way to find out where the error was if returned "false" + * + * @param [in] buffer The packet buffer + * @param [in] packetDictionary The dictionary to fill in + * + * @return true Successful decode + * @return false There was an error somewhere + * + * Example: + * @code + * { + * } + * @endcode + */ +bool ccnxCodecSchemaV1PacketDecoder_BufferDecode(PARCBuffer *packetBuffer, CCNxTlvDictionary *packetDictionary); + +/** + * Decode in to in to a dictionary. + * + * The buffer should be set at the start of the fixed header. + * + * The dictionary will be filled in with all fields available in the packetDecoder. + * + * Caveat: there is no way to find out where the error was if returned "false" + * + * @param [in] buffer The packet buffer + * @param [in] packetDictionary The dictionary to fill in + * + * @return true Successful decode + * @return false There was an error somewhere + * + * Example: + * @code + * { + * } + * @endcode + */ +bool ccnxCodecSchemaV1PacketDecoder_Decode(CCNxCodecTlvDecoder *packetDecoder, CCNxTlvDictionary *packetDictionary); + +#endif // CCNxCodecSchemaV1_PacketDecoder_h diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.c new file mode 100755 index 00000000..bddd32d4 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.c @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// ===================================================== +// Private API + +static uint8_t +_getHopLimit(CCNxTlvDictionary *packetDictionary) +{ + uint8_t hoplimit = (uint8_t) CCNxInterestDefault_HopLimit; + + if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_HOPLIMIT)) { + hoplimit = (uint8_t) ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_HOPLIMIT); + } + return hoplimit; +} + +static uint8_t +_getInterestReturnCode(CCNxTlvDictionary *packetDictionary) +{ + uint8_t returnCode = (uint8_t) 0; + + if (ccnxTlvDictionary_IsValueInteger(packetDictionary, + CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestReturnCode)) { + returnCode = + (uint8_t) ccnxTlvDictionary_GetInteger(packetDictionary, + CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestReturnCode); + } + return returnCode; +} + +/** + * Creates a fixed header from the given parameters and encodes in network byte order + * + * All parameters in host byte order. + * + * @param [<#in out in,out#>] <#name#> <#description#> + * + * @return non-negative The total bytes appended to the encode buffer + * @return -1 An error + * + * Example: + * @code + * <#example#> + * @endcode + */ +static ssize_t +_encodeFixedHeader(CCNxCodecTlvEncoder *fixedHeaderEncoder, + CCNxTlvDictionary *packetDictionary, + int packetType, + ssize_t headerLength, + ssize_t packetLength) +{ + CCNxCodecSchemaV1FixedHeader fixedHeader; + memset(&fixedHeader, 0, sizeof(fixedHeader)); + + fixedHeader.version = 1; + fixedHeader.packetType = packetType; + fixedHeader.packetLength = packetLength; + fixedHeader.headerLength = headerLength; + + if ((packetType == CCNxCodecSchemaV1Types_PacketType_Interest) || + (packetType == CCNxCodecSchemaV1Types_PacketType_InterestReturn)) { + CCNxCodecSchemaV1InterestHeader *interestHeader = (CCNxCodecSchemaV1InterestHeader *) &fixedHeader; + interestHeader->hopLimit = _getHopLimit(packetDictionary); + if (packetType == CCNxCodecSchemaV1Types_PacketType_InterestReturn) { + interestHeader->returnCode = _getInterestReturnCode(packetDictionary); + } + } + + return ccnxCodecSchemaV1FixedHeaderEncoder_EncodeHeader(fixedHeaderEncoder, &fixedHeader); +} + +static ssize_t +_encodeOptionalHeaders(CCNxCodecTlvEncoder *optionalHeaderEncoder, CCNxTlvDictionary *packetDictionary) +{ + // Optional Headers do not have a container, so just append them right to the buffer + size_t optionalHeadersLength = 0; + optionalHeadersLength = ccnxCodecSchemaV1OptionalHeadersEncoder_Encode(optionalHeaderEncoder, packetDictionary); + return optionalHeadersLength; +} + +/** + * CPI payload is simply a dump of the PAYLOAD dictionary entry. + * + * There are no inner TLVs of this message, so it is not encoded like a normal message + * with a call to ccnxCodecSchemaV1MessageEncoder_Encode(). Rather it is written here. + * + * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#> + * + * @return non-negative The number of bytes appended to the buffer + * @return negative An error + * + * Example: + * @code + * { + * <#example#> + * } + * @endcode + */ +static ssize_t +_encodeCPI(CCNxCodecTlvEncoder *cpiEncoder, CCNxTlvDictionary *packetDictionary) +{ + // Optional Headers do not have a container, so just append them right to the buffer + size_t payloadLength = 0; + + if (ccnxTlvDictionary_IsValueJson(packetDictionary, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD)) { + PARCJSON *json = ccnxTlvDictionary_GetJson(packetDictionary, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD); + if (json) { + char *jsonString = parcJSON_ToCompactString(json); + + payloadLength = strlen(jsonString); + ccnxCodecTlvEncoder_AppendRawArray(cpiEncoder, payloadLength, (uint8_t * ) jsonString); + parcMemory_Deallocate((void **) &jsonString); + } + } else { + PARCBuffer *payload = ccnxTlvDictionary_GetBuffer(packetDictionary, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD); + + payloadLength = parcBuffer_Remaining(payload); + uint8_t *overlay = parcBuffer_Overlay(payload, 0); + ccnxCodecTlvEncoder_AppendRawArray(cpiEncoder, payloadLength, overlay); + } + return payloadLength; +} + +/** + * Encode the CCNx Message + * + * <#Paragraphs Of Explanation#> + * + * @param [out] packetTypePtr The type to use for the PacketType based on the message type + * + * @retval non-negative the bytes appended to the encoder + * @retval negative An error + * + * Example: + * @code + * <#example#> + * @endcode + */ +static ssize_t +_encodeMessage(CCNxCodecTlvEncoder *packetEncoder, CCNxTlvDictionary *packetDictionary, CCNxCodecSchemaV1Types_PacketType *packetTypePtr) +{ + ssize_t startPosition = ccnxCodecTlvEncoder_Position(packetEncoder); + ssize_t innerLength = -1; + + // what kind of message is it? need this to set the packetTypePtr + + if (ccnxTlvDictionary_IsInterest(packetDictionary)) { + *packetTypePtr = CCNxCodecSchemaV1Types_PacketType_Interest; + ccnxCodecTlvEncoder_AppendContainer(packetEncoder, CCNxCodecSchemaV1Types_MessageType_Interest, 0); + innerLength = ccnxCodecSchemaV1MessageEncoder_Encode(packetEncoder, packetDictionary); + } else if (ccnxTlvDictionary_IsInterestReturn(packetDictionary)) { + *packetTypePtr = CCNxCodecSchemaV1Types_PacketType_InterestReturn; + ccnxCodecTlvEncoder_AppendContainer(packetEncoder, CCNxCodecSchemaV1Types_MessageType_Interest, 0); + innerLength = ccnxCodecSchemaV1MessageEncoder_Encode(packetEncoder, packetDictionary); + } else if (ccnxTlvDictionary_IsContentObject(packetDictionary)) { + *packetTypePtr = CCNxCodecSchemaV1Types_PacketType_ContentObject; + ccnxCodecTlvEncoder_AppendContainer(packetEncoder, CCNxCodecSchemaV1Types_MessageType_ContentObject, 0); + innerLength = ccnxCodecSchemaV1MessageEncoder_Encode(packetEncoder, packetDictionary); + } else if (ccnxTlvDictionary_IsControl(packetDictionary)) { + *packetTypePtr = CCNxCodecSchemaV1Types_PacketType_Control; + ccnxCodecTlvEncoder_AppendContainer(packetEncoder, CCNxCodecSchemaV1Types_MessageType_Control, 0); + innerLength = _encodeCPI(packetEncoder, packetDictionary); + } else if (ccnxTlvDictionary_IsManifest(packetDictionary)) { + *packetTypePtr = CCNxCodecSchemaV1Types_PacketType_ContentObject; + ccnxCodecTlvEncoder_AppendContainer(packetEncoder, CCNxCodecSchemaV1Types_MessageType_Manifest, 0); + innerLength = ccnxCodecSchemaV1MessageEncoder_Encode(packetEncoder, packetDictionary); + } + + if (innerLength >= 0) { + // For a 0 length message, we do not backup and erase the TLV container. + ccnxCodecTlvEncoder_SetContainerLength(packetEncoder, startPosition, innerLength); + ssize_t endPosition = ccnxCodecTlvEncoder_Position(packetEncoder); + innerLength = endPosition - startPosition; + } else { + CCNxCodecError *error = ccnxCodecError_Create(TLV_MISSING_MANDATORY, __func__, __LINE__, ccnxCodecTlvEncoder_Position(packetEncoder)); + ccnxCodecTlvEncoder_SetError(packetEncoder, error); + ccnxCodecError_Release(&error); + } + + return innerLength; +} + +static ssize_t +_encodeValidationAlg(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t innerLength = 0; + + // There must be a CryptoSuite in the packet to sign it. + // Temporary exception for Content Objects, which are all signed if the codec has a signer. + if (ccnxValidationFacadeV1_HasCryptoSuite(packetDictionary) || ccnxTlvDictionary_IsContentObject(packetDictionary)) { + ssize_t startPosition = ccnxCodecTlvEncoder_Position(encoder); + + ccnxCodecTlvEncoder_AppendContainer(encoder, CCNxCodecSchemaV1Types_MessageType_ValidationAlg, 0); + innerLength = ccnxCodecSchemaV1ValidationEncoder_EncodeAlg(encoder, packetDictionary); + + if (innerLength == 0) { + // backup and erase the container + ccnxCodecTlvEncoder_SetPosition(encoder, startPosition); + } else if (innerLength >= 0) { + ccnxCodecTlvEncoder_SetContainerLength(encoder, startPosition, innerLength); + ssize_t endPosition = ccnxCodecTlvEncoder_Position(encoder); + return endPosition - startPosition; + } + } + + return innerLength; +} + +static ssize_t +_encodeValidationPayload(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t startPosition = ccnxCodecTlvEncoder_Position(encoder); + + ccnxCodecTlvEncoder_AppendContainer(encoder, CCNxCodecSchemaV1Types_MessageType_ValidationPayload, 0); + ssize_t innerLength = ccnxCodecSchemaV1ValidationEncoder_EncodePayload(encoder, packetDictionary); + + if (innerLength == 0) { + // backup and erase the container + ccnxCodecTlvEncoder_SetPosition(encoder, startPosition); + } else if (innerLength > 0) { + ccnxCodecTlvEncoder_SetContainerLength(encoder, startPosition, innerLength); + ssize_t endPosition = ccnxCodecTlvEncoder_Position(encoder); + return endPosition - startPosition; + } + + return innerLength; +} + +// ===================================================== +// Public API + +CCNxCodecNetworkBufferIoVec * +ccnxCodecSchemaV1PacketEncoder_DictionaryEncode(CCNxTlvDictionary *packetDictionary, PARCSigner *signer) +{ + CCNxCodecNetworkBufferIoVec *outputBuffer = NULL; + + CCNxCodecTlvEncoder *packetEncoder = ccnxCodecTlvEncoder_Create(); + + if (signer) { +// ccnxCodecTlvEncoder_SetSigner(packetEncoder, signer); + } + + ssize_t encodedLength = ccnxCodecSchemaV1PacketEncoder_Encode(packetEncoder, packetDictionary); + if (encodedLength > 0) { + ccnxCodecTlvEncoder_Finalize(packetEncoder); + outputBuffer = ccnxCodecTlvEncoder_CreateIoVec(packetEncoder); + } + + trapUnexpectedStateIf(encodedLength < 0 && !ccnxCodecTlvEncoder_HasError(packetEncoder), + "Got error length but no error set"); + + assertFalse(ccnxCodecTlvEncoder_HasError(packetEncoder), "ENCODING ERROR") + { + printf("ERROR: %s\n", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(packetEncoder))); + ccnxTlvDictionary_Display(packetDictionary, 3); + } + + ccnxCodecTlvEncoder_Destroy(&packetEncoder); + + // return a reference counted copy so it won't be destroyed by ccnxCodecTlvEncoder_Destroy + return outputBuffer; +} + +ssize_t +ccnxCodecSchemaV1PacketEncoder_Encode(CCNxCodecTlvEncoder *packetEncoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t length = -1; + + // We will need to go back and fixedup the headers + ssize_t fixedHeaderPosition = ccnxCodecTlvEncoder_Position(packetEncoder); + ssize_t fixedHeaderLength = _encodeFixedHeader(packetEncoder, packetDictionary, -1, 0, 0); + + ssize_t optionalHeadersLength = _encodeOptionalHeaders(packetEncoder, packetDictionary); + + if (optionalHeadersLength >= 0) { + ccnxCodecTlvEncoder_MarkSignatureStart(packetEncoder); + + CCNxCodecSchemaV1Types_PacketType messageType = -1; + + ssize_t messageLength = _encodeMessage(packetEncoder, packetDictionary, &messageType); + + if (messageLength >= 0) { + // validation is optional, so it's ok if its 0 length + ssize_t validationAlgLength = _encodeValidationAlg(packetEncoder, packetDictionary); + ssize_t validationPayloadLength = 0; + if (validationAlgLength > 0) { + ccnxCodecTlvEncoder_MarkSignatureEnd(packetEncoder); + + validationPayloadLength = _encodeValidationPayload(packetEncoder, packetDictionary); + } + + if (validationAlgLength >= 0 && validationPayloadLength >= 0) { + // now fix up the fixed header + size_t endPosition = ccnxCodecTlvEncoder_Position(packetEncoder); + + size_t headerLength = fixedHeaderLength + optionalHeadersLength; + size_t packetLength = headerLength + messageLength + validationAlgLength + validationPayloadLength; + + // Will this work for InterestReturn? As long as _encodeMessage returns InterestReturn it + // will be ok. + int packetType = messageType; + + ccnxCodecTlvEncoder_SetPosition(packetEncoder, fixedHeaderPosition); + _encodeFixedHeader(packetEncoder, packetDictionary, packetType, headerLength, packetLength); + ccnxCodecTlvEncoder_SetPosition(packetEncoder, endPosition); + length = endPosition - fixedHeaderPosition; + + trapUnexpectedStateIf(packetLength != length, "packet length %zu not equal to measured length %zd", packetLength, length); + } + } + } + + return length; +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.h new file mode 100755 index 00000000..c83f165f --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_PacketEncoder.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file ccnxCodecSchemaV1_PacketEncoder.h + * @brief Encoder for the version 1 TLV Packet + * + * Example: + * @code + * { + * } + * @endcode + * + */ + +#ifndef CCNxCodecSchemaV1_PacketEncoder_h +#define CCNxCodecSchemaV1_PacketEncoder_h + +#include +#include + +#include +#include +#include +#include + +/** + * Encode the packetDictionary to wire format + * + * Will only use the PacketType from FixedHeader in the dictionary, if provided. The packet Version is fixed at "1", + * the PayloadLength and HeaderLength are calculated. If the FixedHeaderDictionary is not provided, the + * PacketType is inferred from the type of CCNx message. + * + * The signer is not stored beyond the call to DictionaryEncode. + * If the dictionary already has a ValidationAlg and ValidationPayload, those are used, not the Signer. + * Otherwise, if the signer is not null, it is used to sign the wire format. + * + * @param [in] packetDictionary The dictionary representation of the packet to encode + * @param [in] signer If not NULL will be used to sign the wire format + * + * @retval non-null An IoVec that can be written to the network + * @retval null an error + * + * Example: + * @code + * <#example#> + * @endcode + */ +CCNxCodecNetworkBufferIoVec *ccnxCodecSchemaV1PacketEncoder_DictionaryEncode(CCNxTlvDictionary *packetDictionary, PARCSigner *signer); + +/** + * Encode a packetDictionary to wire format. + * + * Will only use the PacketType from FixedHeader in the dictionary, if provided. The packet Version is fixed at "1", + * the PayloadLength and HeaderLength are calculated. If the FixedHeaderDictionary is not provided, the + * PacketType is inferred from the type of CCNx message. + * + * You must use ccnxCodecTlvEncoder_SetSigner(signer) if you require a signature or MAC on the packet. + * + * @param [in] packetEncoder A TLV packet will be appended to the encoder + * @param [in] packetDictionary The dictionary representation of the packet to encode + * + * @retval non-negative The total bytes appended to the encode buffer + * @retval -1 An error + * + * Example: + * @code + * <#example#> + * @endcode + */ +ssize_t ccnxCodecSchemaV1PacketEncoder_Encode(CCNxCodecTlvEncoder *packetEncoder, CCNxTlvDictionary *packetDictionary); + +#endif // CCNxCodecSchemaV1_PacketEncoder_h diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.c new file mode 100644 index 00000000..72e1ce3e --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ + +#include +#include +#include +#include + +#include +#include +#include + +CCNxTlvDictionary * +ccnxCodecSchemaV1TlvDictionary_CreateInterest(void) +{ + CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END); + ccnxTlvDictionary_SetMessageType_Interest(dictionary, CCNxTlvDictionary_SchemaVersion_V1); + return dictionary; +} + +CCNxTlvDictionary * +ccnxCodecSchemaV1TlvDictionary_CreateContentObject(void) +{ + CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END); + ccnxTlvDictionary_SetMessageType_ContentObject(dictionary, CCNxTlvDictionary_SchemaVersion_V1); + return dictionary; +} + +CCNxTlvDictionary * +ccnxCodecSchemaV1TlvDictionary_CreateManifest(void) +{ + CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END); + ccnxTlvDictionary_SetMessageType_Manifest(dictionary, CCNxTlvDictionary_SchemaVersion_V1); + + return dictionary; +} + +CCNxTlvDictionary * +ccnxCodecSchemaV1TlvDictionary_CreateControl(void) +{ + CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END); + ccnxTlvDictionary_SetMessageType_Control(dictionary, CCNxTlvDictionary_SchemaVersion_V1); + return dictionary; +} + +CCNxTlvDictionary * +ccnxCodecSchemaV1TlvDictionary_CreateInterestReturn(void) +{ + CCNxTlvDictionary *dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END); + ccnxTlvDictionary_SetMessageType_InterestReturn(dictionary, CCNxTlvDictionary_SchemaVersion_V1); + return dictionary; +} + diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h new file mode 100755 index 00000000..e76492b6 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_TlvDictionary.h @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file ccnxCodecSchemaV1_TlvDictionary.h + * @brief <#Brief Description#> + * + * Used as keys to the CCNxTlvDictionary for the version 1 schema + * + */ + +#ifndef libccnx_ccnx_TlvDictionary_SchemaV1_h +#define libccnx_ccnx_TlvDictionary_SchemaV1_h + +#include + +/** + * @typedef CCNxCodecSchemaV1TlvDictionary_CryptoSuite + * @abstract The ValidationAlgorithm Type. + * @constant <#name#> <#description#> + * @discussion These are the wire-format values for the ValidationAlgorithm type. The values + * specified follow from the CCNx Messages RFC. + * + * It is not the same as the value stored in CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE, + * which is of type PARCCryptoSuite. + */ +typedef enum rta_tlv_schema_v1_crypto_suite { + CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C = 2, + CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256 = 4, + CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256 = 6, + CCNxCodecSchemaV1TlvDictionary_CryptoSuite_EcSecp256K1 = 7, +} CCNxCodecSchemaV1TlvDictionary_CryptoSuite; + +/** + * @typedef <#CCNBHeaderType#> + * @abstract <#Abstract#> + * @constant CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_WireFormat The off-the-wire packet or a pre-encoded packet + * @discussion + * The WireFormat header is a ficticious header for holding the off-the-wire packet received + * from the network or to send a pre-encoded packet down through the stack. + * + * The Forwarder header is a ficticious header for holding special forwarder control block. The + * forwarder control block, on ingress, contains information about where a packet arrived. On + * egress, it contains information about how the packet should be transmitted, such as restricting + * it to a specific egress interface. + * + * The protected region extent is used to determine they byte range used for verification. + */ + + +typedef enum rta_tlv_schema_v1_headers_fastarray { + CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_TransportStack = 0, /**< Array element 0 is used by RTA Transport stack */ + CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader = 1, + CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG = 2, + CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_OBJFRAG = 3, + CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_WireFormat = 4, + CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_Forwarder = 5, + CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime = 6, + CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime = 7, + CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ProtectedStart = 8, /**< Fictitious header for Protected Region Extent */ + CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ProtectedLength = 9, /**< Fictitious header for Protected Region length */ + CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ContentObjectHashRegionStart = 10, /**< Fictitious header for CO Hash Region Extent */ + CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_ContentObjectHashRegionLength = 11, /**< Fictitious header for CO Hash Region length */ + CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestReturnCode = 12, + CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel = 13, + CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END = 14 +} CCNxCodecSchemaV1TlvDictionary_HeadersFastArray; + +/** + * The ValidationFastArray are fields that may appear in the Validation Algorithm and the Validation Payload field. + * + * Note that the ValidationFastArray_CRYPTO_SUITE is always expressed in terms of PARCCryptoSuite. + */ +typedef enum rta_tlv_schema_v1_validation_fastarray { + CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 0, + CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 1, // PARCCryptoSuite value + CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEY = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 2, + CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CERT = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 3, + CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_NAME = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 4, + CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_KEYID = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 5, + CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_OBJHASH = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 6, + CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 7, + CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 8, + CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END = CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END + 9 +} CCNxCodecSchemaV1TlvDictionary_ValidationFastArray; + + +/** + * The MessageFastArray are fields that may appear in the body of a CCNx message (Interest, Content Object, Control). + * + * The Hop Limit is part of the MessageFastArray even though it appears in the FixedHeader. It is treated like a property + * of the Interest. + */ +typedef enum rta_tlv_schema_v1_message_fastarray { + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 0, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_KEYID_RESTRICTION = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 1, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 2, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 4, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_HOPLIMIT = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 5, /***< Virtual field */ + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 6, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 7, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 8, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_HASH_GROUP = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 9, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_DATA_POINTER = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 10, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_MANIFEST_POINTER = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 11, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END = CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_END + 12 +} CCNxCodecSchemaV1TlvDictionary_MessageFastArray; + +//const int CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_PathLabel = CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END + 1; + +/** + * Each TLV container can have custom types in it, so each container has a "list" + * Organization Extensions go here. + */ +typedef enum rta_tlv_schema_v1_lists { + CCNxCodecSchemaV1TlvDictionary_Lists_HEADERS = 0, + CCNxCodecSchemaV1TlvDictionary_Lists_MESSAGE_LIST = 1, + CCNxCodecSchemaV1TlvDictionary_Lists_VALIDATION_ALG_LIST = 4, + CCNxCodecSchemaV1TlvDictionary_Lists_VALIDATION_PAYLOAD_LIST = 5, + CCNxCodecSchemaV1TlvDictionary_Lists_HASH_GROUP_LIST = 6, + CCNxCodecSchemaV1TlvDictionary_Lists_END = 7 +} CCNxCodecSchemaV1TlvDictionary_Lists; + +/** + * Creates an empty Interest dictionary + * + * The dictionary schema will be V1 and the dictionary type will be Interest. No other + * fields are pre-populated. + * + * @retval non-null An allocated Dictionary of type Interest + * @retval null An error (likely no memory) + * + * Example: + * @code + * { + * // in a decoder + * if (messageType == _DecoderTlvType_Interest) { + * CCNxTlvDictionary *interest = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + * // decode the rest of the packet + * return interest; + * } + * } + * @endcode + */ +CCNxTlvDictionary *ccnxCodecSchemaV1TlvDictionary_CreateInterest(void); + +/** + * Creates an empty Content Object dictionary + * + * The dictionary schema will be V1 and the dictionary type will be Content Object. No other + * fields are pre-populated. + * + * @retval non-null An allocated Dictionary of type Content Object + * @retval null An error (likely no memory) + * + * Example: + * @code + * { + * // in a decoder + * if (messageType == _DecoderTlvType_ContentObject) { + * CCNxTlvDictionary *object = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + * // decode the rest of the packet + * return object; + * } + * } + * @endcode + */ +CCNxTlvDictionary *ccnxCodecSchemaV1TlvDictionary_CreateContentObject(void); + +/** + * Creates an empty Manifest dictionary + * + * The dictionary schema will be V1 and the dictionary type will be Content Object. The + * PayloadType will be set to CCNxPayloadType_MANIFEST. No other fields are pre-populated. + * + * @retval non-null An allocated Dictionary of type Manifest + * @retval null An error (likely no memory) + * + * Example: + * @code + * { + * // in a decoder + * if (messageType == _DecoderTlvType_Manifest) { + * CCNxTlvDictionary *object = ccnxCodecSchemaV1TlvDictionary_Manifest(); + * // decode the rest of the packet + * return object; + * } + * } + * @endcode + */ +CCNxTlvDictionary *ccnxCodecSchemaV1TlvDictionary_CreateManifest(void); + +/** + * Creates an empty Control dictionary + * + * The dictionary schema will be V1 and the dictionary type will be Control. No other + * fields are pre-populated. + * + * @retval non-null An allocated Dictionary of type Control + * @retval null An error (likely no memory) + * + * Example: + * @code + * { + * // in a decoder + * if (messageType == _DecoderTlvType_Control) { + * CCNxTlvDictionary *control = ccnxCodecSchemaV1TlvDictionary_CreateControl(); + * // decode the rest of the packet + * return control; + * } + * } + * @endcode + */ +CCNxTlvDictionary *ccnxCodecSchemaV1TlvDictionary_CreateControl(void); + +/** + * Creates an empty InterestReturn dictionary + * + * The dictionary schema will be V1 and the dictionary type will be InterestReturn. No other + * fields are pre-populated. + * + * @retval non-null An allocated Dictionary of type InterestReturn + * @retval null An error (likely no memory) + * + * Example: + * @code + * { + * // in a decoder + * if (messageType == _DecoderTlvType_InterestReturn) { + * CCNxTlvDictionary *interestReturn = ccnxCodecSchemaV1TlvDictionary_CreateInterestReturn(); + * // decode the rest of the packet + * return interestReturn; + * } + * } + * @endcode + */ +CCNxTlvDictionary *ccnxCodecSchemaV1TlvDictionary_CreateInterestReturn(void); +#endif // libccnx_ccnx_TlvDictionary_SchemaV1_h diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h new file mode 100755 index 00000000..1c50eebc --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_Types.h @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file ccnxCodecSchemaV1_Types.h + * @brief Common definitions for Schema version 1 + * + * Defines the TLV "type" values for each field + * + */ + +#ifndef TransportRTA_ccnxCodecSchemaV1_Types_h +#define TransportRTA_ccnxCodecSchemaV1_Types_h + +#include + +/** + * @typedef CCNxCodecSchemaV1Types_PacketType + * @abstract The values used in the PacketType field of the Fixed Header + * @constant <#name#> <#description#> + * @discussion <#Discussion#> + */ +typedef enum rta_tlv_schema_v1_packet_type { + CCNxCodecSchemaV1Types_PacketType_Interest = 0x00, + CCNxCodecSchemaV1Types_PacketType_ContentObject = 0x01, + CCNxCodecSchemaV1Types_PacketType_InterestReturn = 0x02, + CCNxCodecSchemaV1Types_PacketType_Control = 0xA4, +} CCNxCodecSchemaV1Types_PacketType; + +/** + * @typedef CCNxCodecSchemaV1Types_MessageType + * @abstract The values used in the MessageType field of the CCNx Message body + * @constant <#name#> <#description#> + * @discussion <#Discussion#> + */ +typedef enum rta_tlv_schema_v1_message_type { + CCNxCodecSchemaV1Types_MessageType_Interest = 0x0001, + CCNxCodecSchemaV1Types_MessageType_ContentObject = 0x0002, + CCNxCodecSchemaV1Types_MessageType_ValidationAlg = 0x0003, + CCNxCodecSchemaV1Types_MessageType_ValidationPayload = 0x0004, + CCNxCodecSchemaV1Types_MessageType_Manifest = 0x0006, + CCNxCodecSchemaV1Types_MessageType_Control = 0xBEEF, +} CCNxCodecSchemaV1Types_MessageType; + +/** + * @typedef CCNxCodecSchemaV1Types_OptionalHeadersTypes + * @abstract The well-known keys for the hop-by-hop headers + * @constant <#name#> <#description#> + * @discussion <#Discussion#> + */ +typedef enum rta_tlv_schema_v1_optional_headers_types { + CCNxCodecSchemaV1Types_OptionalHeaders_InterestLifetime = 0x0001, + CCNxCodecSchemaV1Types_OptionalHeaders_RecommendedCacheTime = 0x0002, + CCNxCodecSchemaV1Types_OptionalHeaders_PathLabel = 0x0003, + CCNxCodecSchemaV1Types_OptionalHeaders_InterestFragment = 0x0004, + CCNxCodecSchemaV1Types_OptionalHeaders_ContentObjectFragment = 0x0005, +} CCNxCodecSchemaV1Types_OptionalHeaders; + +/** + * @typedef CCNxCodecSchemaV1Types_PayloadType + * @abstract The values of the PayloadType field + * @constant <#name#> <#description#> + * @discussion <#Discussion#> + */ +typedef enum rta_tlv_schema_v1_payloadtype_types { + CCNxCodecSchemaV1Types_PayloadType_Data = 0, + CCNxCodecSchemaV1Types_PayloadType_Key = 1, + CCNxCodecSchemaV1Types_PayloadType_Link = 2, +} CCNxCodecSchemaV1Types_PayloadType; + +// ================================================== +// Fields in a Message Object + +/** + * @typedef CCNxCodecSchemaV1Types_MessageTypes + * @abstract The well-known types inside the CCNxMessage + * @constant <#name#> <#description#> + * @discussion <#Discussion#> + */ +typedef enum rta_tlv_schema_v1_ccnxmessage_types { + CCNxCodecSchemaV1Types_CCNxMessage_Name = 0x0000, + CCNxCodecSchemaV1Types_CCNxMessage_Payload = 0x0001, + CCNxCodecSchemaV1Types_CCNxMessage_KeyIdRestriction = 0x0002, + CCNxCodecSchemaV1Types_CCNxMessage_ContentObjectHashRestriction = 0x0003, + CCNxCodecSchemaV1Types_CCNxMessage_PayloadType = 0x0005, + CCNxCodecSchemaV1Types_CCNxMessage_ExpiryTime = 0x0006, + CCNxCodecSchemaV1Types_CCNxMessage_HashGroup = 0x0007, + CCNxCodecSchemaV1Types_CCNxMessage_EndChunkNumber = 0x0019, +} CCNxCodecSchemaV1Types_CCNxMessage; + +typedef enum rta_tlv_schema_v1_ccnxmanifest_hashgroup_types { + CCNxCodecSchemaV1Types_CCNxManifestHashGroup_Metadata = 0x0001, + CCNxCodecSchemaV1Types_CCNxManifestHashGroup_DataPointer = 0x0002, + CCNxCodecSchemaV1Types_CCNxManifestHashGroup_ManifestPointer = 0x0003, +} CCNxCodecSchemaV1Types_CCNxManifestHashGroup; + +typedef enum rta_tlv_schema_v1_ccnxmanifest_hashgroup_metadata_types { + CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_Locator = 0x0000, + CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_DataSize = 0x0001, + CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_BlockSize = 0x0002, + CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_EntrySize = 0x0003, + CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_TreeHeight = 0x0004, + CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_OverallDataSha256 = 0x0005, +} CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata; + +// ================================================== +// Fields in a Validation Algorithm + +/** + * @typedef CCNxCodecSchemaV1Types_ValidationAlg + * @abstract The well-known keys for the ContentObject + * @constant <#name#> <#description#> + * @discussion the CCNxCodecSchemaV1Types_ValidationAlg values for the crypto suites must be the same as CCNxCodecSchemaV1Types_CryptoSuiteType + */ +typedef enum rta_tlv_schema_v1_validation_alg { + CCNxCodecSchemaV1Types_ValidationAlg_CRC32C = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C, // 0x0002 + CCNxCodecSchemaV1Types_ValidationAlg_HMAC_SHA256 = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256, // 0x0004 + CCNxCodecSchemaV1Types_ValidationAlg_RSA_SHA256 = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256, // 0x0006 + CCNxCodecSchemaV1Types_ValidationAlg_EC_SECP_256K1 = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_EcSecp256K1, // 0x0007 + + CCNxCodecSchemaV1Types_ValidationAlg_KeyId = 0x0009, + CCNxCodecSchemaV1Types_ValidationAlg_PublicKey = 0x000B, + CCNxCodecSchemaV1Types_ValidationAlg_Cert = 0x000C, + CCNxCodecSchemaV1Types_ValidationAlg_KeyName = 0x000E, + CCNxCodecSchemaV1Types_ValidationAlg_SigTime = 0x000F, +} CCNxCodecSchemaV1Types_ValidationAlg; + +/** + * @typedef CCNxCodecSchemaV1Types_Link + * @abstract The well-known keys for the LINK body + * @constant <#name#> <#description#> + * @discussion <#Discussion#> + */ +typedef enum rta_tlv_schema_v1_link_types { + CCNxCodecSchemaV1Types_Link_Name = 0x0000, + CCNxCodecSchemaV1Types_Link_KeyIdRestriction = 0x0001, + CCNxCodecSchemaV1Types_Link_ContentObjectHashRestriction = 0x0002, +} CCNxCodecSchemaV1Types_Link; + +/** + * @typedef CCNxCodecSchemaV1Types_HashGroup + * @abstract The well-known keys for the Manifest HashGroup. + * @constant <#name#> <#description#> + * @discussion <#Discussion#> + */ +typedef enum rta_tlv_schema_v1_link_hash_group { + CCNxCodecSchemaV1Types_HashGroup_Metadata = 0x0001, + CCNxCodecSchemaV1Types_HashGroup_DataPointer = 0x0002, + CCNxCodecSchemaV1Types_HashGroup_ManifestPointer = 0x0003 +} CCNxCodecSchemaV1Types_HashGroup; + +/** + * @typedef CCNxCodecSchemaV1Types_HashGroup + * @abstract The well-known keys for the Manifest HashGroup. + * @constant <#name#> <#description#> + * @discussion <#Discussion#> + */ +typedef enum rta_tlv_schema_v1_link_hash_group_metadata { + CCNxCodecSchemaV1Types_HashGroup_Locator = 0x0000, + CCNxCodecSchemaV1Types_HashGroup_ExternalMetadata = 0x0001, + CCNxCodecSchemaV1Types_HashGroup_BlockSize = 0x0002, + CCNxCodecSchemaV1Types_HashGroup_OverallDataSize = 0x0003, + CCNxCodecSchemaV1Types_HashGroup_OverallDataSha256 = 0x0004, +} CCNxCodecSchemaV1Types_HashGroupMetadata; + +// ================================================== +// Interest Return + +/** + * @typedef CCNxCodecSchemaV1Types_InterestReturnCode + * @abstract The values of the InterestReturn ReturnCode field + * @constant <#name#> <#description#> + * @discussion <#Discussion#> + */ +typedef enum rta_tlv_schema_v1_interestreturncode_types { + CCNxCodecSchemaV1Types_InterestReturnCode_NoRoute = 0x01, + CCNxCodecSchemaV1Types_InterestReturnCode_HopLimitExceeded = 0x02, + CCNxCodecSchemaV1Types_InterestReturnCode_NoResources = 0x03, + CCNxCodecSchemaV1Types_InterestReturnCode_PathError = 0x04, + CCNxCodecSchemaV1Types_InterestReturnCode_Prohibited = 0x05, + CCNxCodecSchemaV1Types_InterestReturnCode_Congestion = 0x06, + CCNxCodecSchemaV1Types_InterestReturnCode_MTUTooLarge = 0x07, +} CCNxCodecSchemaV1Types_InterestReturnCode; + +// ================================================== +// Hash function types +/** + * @typedef CCNxCodecSchemaV1Types_HashTypes + * @abstract The values of the InterestReturn ReturnCode field + * @constant <#name#> <#description#> + * @discussion <#Discussion#> + */ +typedef enum rta_tlv_schema_v1_hash_types { + CCNxCodecSchemaV1Types_HashType_SHA256 = 0x01, + CCNxCodecSchemaV1Types_HashType_SHA512 = 0x02, + CCNxCodecSchemaV1Types_HashType_App +} CCNxCodecSchemaV1Types_HashType; + +#endif //TransportRTA_ccnxCodecSchemaV1_Types_h diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.c new file mode 100755 index 00000000..0524bcfa --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ + +#include + +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include + +static bool +_decodeKeyName(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length) +{ + // At this point, the decoder should point to the 1st byte of the "value" of the (type, length) continer. + // This is defined as a CCNxLink + + bool success = false; + + // this will set the decoder error if it fails. + CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, length); + if (link != NULL) { + const CCNxName *name = ccnxLink_GetName(link); + if (name != NULL) { + success = ccnxTlvDictionary_PutName(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_NAME, name); + + if (success) { + PARCBuffer *keyid = ccnxLink_GetKeyID(link); + if (keyid) { + ccnxTlvDictionary_PutBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_KEYID, keyid); + } + + PARCBuffer *hash = ccnxLink_GetContentObjectHash(link); + if (hash) { + ccnxTlvDictionary_PutBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_OBJHASH, hash); + } + } + } + + if (!success) { + CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder)); + ccnxCodecTlvDecoder_SetError(decoder, error); + ccnxCodecError_Release(&error); + } + + ccnxLink_Release(&link); + } + + return success; +} + +static bool +_decodeAlgParametersType(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length) +{ + bool success = false; + switch (type) { + case CCNxCodecSchemaV1Types_ValidationAlg_Cert: + success = ccnxCodecTlvUtilities_PutAsBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CERT); + break; + + case CCNxCodecSchemaV1Types_ValidationAlg_KeyId: + success = ccnxCodecTlvUtilities_PutAsBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID); + break; + + case CCNxCodecSchemaV1Types_ValidationAlg_KeyName: + // The "value" is a link + success = _decodeKeyName(decoder, packetDictionary, type, length); + break; + + case CCNxCodecSchemaV1Types_ValidationAlg_SigTime: + // This is a time, so put it as an Integer + success = ccnxCodecTlvUtilities_PutAsInteger(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME); + break; + + case CCNxCodecSchemaV1Types_ValidationAlg_PublicKey: + success = ccnxCodecTlvUtilities_PutAsBuffer(decoder, packetDictionary, type, length, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEY); + 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_VALIDATION_ALG_LIST); + } + break; + } + + if (!success) { + CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder)); + ccnxCodecTlvDecoder_SetError(decoder, error); + ccnxCodecError_Release(&error); + } + return success; +} + +/** + * Called by _decodeAlgType() via ccnxCodecTlvUtilities_DecodeSubcontainer() to decode the + * algorithm specific parameters + */ +static bool +_decodeAlgParameters(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary) +{ + return ccnxCodecTlvUtilities_DecodeContainer(decoder, packetDictionary, _decodeAlgParametersType); +} + +static bool +_decodeAlgType(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary, uint16_t type, uint16_t length) +{ + bool success = false; + + PARCCryptoSuite parcSuite; + bool match = ccnxCodecSchemaV1CryptoSuite_TlvToParc((CCNxCodecSchemaV1TlvDictionary_CryptoSuite) type, &parcSuite); + + if (match) { + success = ccnxTlvDictionary_PutInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE, parcSuite); + + if (success) { + success = ccnxCodecTlvUtilities_DecodeSubcontainer(decoder, packetDictionary, type, length, _decodeAlgParameters); + } + } else { + // 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_VALIDATION_ALG_LIST); + } + + if (!success) { + CCNxCodecError *error = ccnxCodecError_Create(TLV_ERR_DECODE, __func__, __LINE__, ccnxCodecTlvDecoder_Position(decoder)); + ccnxCodecTlvDecoder_SetError(decoder, error); + ccnxCodecError_Release(&error); + } + return success; +} + +// ================== +// Public API + +bool +ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary) +{ + return ccnxCodecTlvUtilities_DecodeContainer(decoder, packetDictionary, _decodeAlgType); +} + + +bool +ccnxCodecSchemaV1ValidationDecoder_DecodePayload(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary) +{ + bool success = false; + // A 0-length payload is treaded like an error + size_t remaining = ccnxCodecTlvDecoder_Remaining(decoder); + if (remaining > 0) { + PARCBuffer *payload = ccnxCodecTlvDecoder_GetValue(decoder, remaining); + success = ccnxTlvDictionary_PutBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD, payload); + parcBuffer_Release(&payload); + } + return success; +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.h new file mode 100755 index 00000000..c5d5a42c --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationDecoder.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file ccnxCodecSchemaV1_ValidationDecoder.h + * @brief Decode the validation algorithm and payload + * + * <#Detailed Description#> + * + */ + +#ifndef __CCNx_Common__ccnxCodecSchemaV1_ValidationDecoder__ +#define __CCNx_Common__ccnxCodecSchemaV1_ValidationDecoder__ + +#include + +#include +#include + +/** + * The decode the validation algorithm + * + * The decoder should point to byte 0 of the valdiation algorithm "value" + * + * The results are put in the provided dictionary. + * It is an error if the "value" does not extend to the end of + * the decoder. + * + * @param [in] decoder The decoder to parse + * @param [in] packetDictionary The results go directly in to the provided dictionary. + * + * @return true Fully parsed, no errors + * @return false Error decoding, decoder is left pointing to the first byte of the error + * + * Example: + * @code + * <#example#> + * @endcode + */ +bool ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary); + +/** + * The decode the validation payload + * + * The decoder should point to byte 0 of the valdiation payload "value" + * The payload is an opaque block, so this function will just put the "value" in to the proper + * dictionary location. There's no real parsing. + * + * @param [in] decoder The decoder to parse + * @param [in] packetDictionary The results go directly in to the provided dictionary. + * + * @return true Fully parsed, no errors + * @return false Error decoding, decoder is left pointing to the first byte of the error + * + * Example: + * @code + * <#example#> + * @endcode + */ +bool ccnxCodecSchemaV1ValidationDecoder_DecodePayload(CCNxCodecTlvDecoder *decoder, CCNxTlvDictionary *packetDictionary); + +#endif /* defined(__CCNx_Common__ccnxCodecSchemaV1_ValidationDecoder__) */ diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.c new file mode 100755 index 00000000..f7ad00aa --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.c @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static ssize_t +_encodeKeyId(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t length = 0; + PARCBuffer *keyid = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID); + if (keyid) { + length = ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_ValidationAlg_KeyId, keyid); + } + return length; +} + +static ssize_t +_encodePublicKey(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t length = 0; + PARCBuffer *key = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEY); + if (key) { + length = ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_ValidationAlg_PublicKey, key); + } + return length; +} + +static ssize_t +_encodeCertificate(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t length = 0; + PARCBuffer *cert = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CERT); + if (cert) { + length = ccnxCodecTlvEncoder_AppendBuffer(encoder, CCNxCodecSchemaV1Types_ValidationAlg_Cert, cert); + } + return length; +} + +/** + * If there is a CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_NAME entry in the dictionary, look up the + * optional keyid and hash restrictions, create a CCNxLink, then encode the Link. + */ +static ssize_t +_encodeKeyName(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t length = 0; + CCNxName *keyname = ccnxTlvDictionary_GetName(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_NAME); + if (keyname) { + PARCBuffer *keyid = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_KEYID); + PARCBuffer *hash = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_OBJHASH); + CCNxLink *link = ccnxLink_Create(keyname, keyid, hash); + + size_t startPosition = ccnxCodecTlvEncoder_Position(encoder); + ccnxCodecTlvEncoder_AppendContainer(encoder, CCNxCodecSchemaV1Types_ValidationAlg_KeyName, 0); + ssize_t innerLength = ccnxCodecSchemaV1LinkCodec_Encode(encoder, link); + + if (innerLength == 0) { + // backup and erase the container + ccnxCodecTlvEncoder_SetPosition(encoder, startPosition); + } else if (innerLength > 0) { + ccnxCodecTlvEncoder_SetContainerLength(encoder, startPosition, innerLength); + ssize_t endPosition = ccnxCodecTlvEncoder_Position(encoder); + length = endPosition - startPosition; + } else { + // an error signal + length = innerLength; + } + + ccnxLink_Release(&link); + } + return length; +} + +/** + * If a time is not provided, use the current time + */ +static ssize_t +_encodeSignatureTime(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t length = 0; + + bool haveSignTime = false; + uint64_t signTime = 0; + if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME)) { + haveSignTime = true; + signTime = ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME); + } else { + // if we have a signer and with a signature algorithm, create the signing time + PARCSigner *signer = ccnxCodecTlvEncoder_GetSigner(encoder); + if (signer) { + PARCSigningAlgorithm alg = parcSigner_GetSigningAlgorithm(signer); + if (alg != PARCSigningAlgortihm_NULL && alg != PARCSigningAlgorithm_UNKNOWN) { + // We will generate a signature, so generate a signing time + + struct timeval tv; + gettimeofday(&tv, NULL); + + // convert to milli-seconds + signTime = tv.tv_sec * 1000 + tv.tv_usec / 1000; + haveSignTime = true; + } + } + } + + if (haveSignTime) { + length = ccnxCodecTlvEncoder_AppendUint64(encoder, CCNxCodecSchemaV1Types_ValidationAlg_SigTime, signTime); + } + + return length; +} + +static ssize_t +_encodeAlgParameters(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t length = 0; + ssize_t result; + + result = _encodeKeyId(encoder, packetDictionary); + if (result < 0) { + return result; + } + length += result; + + result = _encodePublicKey(encoder, packetDictionary); + if (result < 0) { + return result; + } + length += result; + + result = _encodeCertificate(encoder, packetDictionary); + if (result < 0) { + return result; + } + length += result; + + result = _encodeKeyName(encoder, packetDictionary); + if (result < 0) { + return result; + } + length += result; + + result = _encodeSignatureTime(encoder, packetDictionary); + if (result < 0) { + return result; + } + length += result; + + return length; +} + +ssize_t +ccnxCodecSchemaV1ValidationEncoder_EncodeAlg(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t length = 0; + bool haveCryptoSuite = false; + CCNxCodecSchemaV1TlvDictionary_CryptoSuite suite; + + if (ccnxTlvDictionary_IsValueInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE)) { + // try from dictionary + + PARCCryptoSuite parcSuite = (PARCCryptoSuite) ccnxTlvDictionary_GetInteger(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE); + + haveCryptoSuite = ccnxCodecSchemaV1CryptoSuite_ParcToTlv(parcSuite, &suite); + } else if (ccnxTlvDictionary_IsContentObject(packetDictionary)) { + // deduce from the signer + + PARCSigner *signer = ccnxCodecTlvEncoder_GetSigner(encoder); + if (signer != NULL) { + PARCCryptoHashType hashType = parcSigner_GetCryptoHashType(signer); + PARCSigningAlgorithm signAlg = parcSigner_GetSigningAlgorithm(signer); + + if (ccnxCodecSchemaV1CryptoSuite_SignAndHashToTlv(signAlg, hashType, &suite)) { + haveCryptoSuite = true; + } + } + } + + if (haveCryptoSuite) { + // write the TL container then encode any enclosed TLVs + ssize_t startPosition = ccnxCodecTlvEncoder_Position(encoder); + + ccnxCodecTlvEncoder_AppendContainer(encoder, suite, 0); + ssize_t innerLength = _encodeAlgParameters(encoder, packetDictionary); + + // 0 inner length is acceptable + if (innerLength >= 0) { + ccnxCodecTlvEncoder_SetContainerLength(encoder, startPosition, innerLength); + ssize_t endPosition = ccnxCodecTlvEncoder_Position(encoder); + length = endPosition - startPosition; + } else { + // an error signal + length = innerLength; + } + } + return length; +} + +ssize_t +ccnxCodecSchemaV1ValidationEncoder_EncodePayload(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary) +{ + ssize_t length = 0; + + if (!ccnxTlvDictionary_IsValueBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD)) { + // try to compute a signature + + // If signer is NULL, then no signature is genearted + PARCSigner *signer = ccnxCodecTlvEncoder_GetSigner(encoder); + if (signer != NULL) { + // user did not give us one, so fill it in + PARCSignature *signature = ccnxCodecTlvEncoder_ComputeSignature(encoder); + PARCBuffer *sigbits = parcSignature_GetSignature(signature); + + // this creates its own reference to sigbits + ccnxTlvDictionary_PutBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD, sigbits); + + // this will release our hold on sigbitsElastic and sigbits. + parcSignature_Release(&signature); + } + } + + PARCBuffer *sigbits = ccnxTlvDictionary_GetBuffer(packetDictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD); + if (sigbits) { + size_t remaining = parcBuffer_Remaining(sigbits); + uint8_t *overlay = parcBuffer_Overlay(sigbits, 0); + length = ccnxCodecTlvEncoder_AppendRawArray(encoder, remaining, overlay); + } + + return length; +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.h b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.h new file mode 100755 index 00000000..3897a053 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/ccnxCodecSchemaV1_ValidationEncoder.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file ccnxCodecSchemaV1_ValidationEncoder.h + * @brief Encode the Validation Algorithm and Payload + * + * Encodes the validation algorithm and payload from the dictionary. Optionally computes + * a signature if one is not specified in the dictionary and the encoder has a signer. + * + */ + +#ifndef __CCNx_Common__ccnxCodecSchemaV1_ValidationEncoder__ +#define __CCNx_Common__ccnxCodecSchemaV1_ValidationEncoder__ + +#include +#include + +/** + * Appends the Validation Algorithm to the packet encoder + * + * If the dictionary has a CryptoSuite specified, we will create a ValidationAlgorithm section + * and fill it in as per the CryptoSuite and supplied validation algorithm arguments, such as + * a KeyId, KeyName, Cert, etc. For most signatures, only the KeyId is mandatory, the other + * fields will only be specified if the user put something in the dictionary. + * + * the caller is responsible for writing the ValidationAlgorithm TL container. + * + * @param [in] encoder An allocated encoder to append to + * @param [in] packetDictionary The dictionary containing the optional headers + * + * @return non-negative Total bytes appended to encoder + * @return -1 An error + * + * Example: + * @code + * <#example#> + * @endcode + */ +ssize_t ccnxCodecSchemaV1ValidationEncoder_EncodeAlg(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary); + +/** + * Appends the Validation Payload to the packet encoder + * + * This will append the Valdiation Payload from the dictionary, or if it is missing and the + * encoder has a signer, will create a signature. + * + * the caller is responsible for writing the ValidationPayload TL container. + * + * To create the signature, the caller must have used ccnxCodecTlvEncoder_MarkSignatureStart() and + * ccnxCodecTlvEncoder_MarkSignatureEnd() functions to specify the byte locations of the start and + * stop of the protected region. + * + * @param [in] encoder An allocated encoder to append to + * @param [in] packetDictionary The dictionary containing the optional headers + * + * @return non-negative Total bytes appended to encoder + * @return -1 An error + * + * Example: + * @code + * <#example#> + * @endcode + */ +ssize_t ccnxCodecSchemaV1ValidationEncoder_EncodePayload(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *packetDictionary); + +#endif /* defined(__CCNx_Common__ccnxCodecSchemaV1_ValidationEncoder__) */ diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/.gitignore b/libccnx-common/ccnx/common/codec/schema_v1/test/.gitignore new file mode 100644 index 00000000..ffeaadf8 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/.gitignore @@ -0,0 +1,19 @@ +*.gcno +*.log +*.trs +*.o +test_ccnxCodecSchemaV1_CryptoSuite +test_ccnxCodecSchemaV1_FixedHeaderDecoder +test_ccnxCodecSchemaV1_FixedHeaderEncoder +test_ccnxCodecSchemaV1_LinkCodec +test_ccnxCodecSchemaV1_MessageDecoder +test_ccnxCodecSchemaV1_MessageEncoder +test_ccnxCodecSchemaV1_NameCodec +test_ccnxCodecSchemaV1_NameSegmentCodec +test_ccnxCodecSchemaV1_OptionalHeadersDecoder +test_ccnxCodecSchemaV1_OptionalHeadersEncoder +test_ccnxCodecSchemaV1_PacketDecoder +test_ccnxCodecSchemaV1_PacketEncoder +test_ccnxCodecSchemaV1_TlvDictionary +test_ccnxCodecSchemaV1_ValidationDecoder +test_ccnxCodecSchemaV1_ValidationEncoder diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/CMakeLists.txt b/libccnx-common/ccnx/common/codec/schema_v1/test/CMakeLists.txt new file mode 100644 index 00000000..c827a36e --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/CMakeLists.txt @@ -0,0 +1,29 @@ +# Enable gcov output for the tests +add_definitions(--coverage) +set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage") + +set(TestsExpectedToPass + test_ccnxCodecSchemaV1_CryptoSuite + test_ccnxCodecSchemaV1_FixedHeaderDecoder + test_ccnxCodecSchemaV1_FixedHeaderEncoder + test_ccnxCodecSchemaV1_HashCodec + test_ccnxCodecSchemaV1_LinkCodec + test_ccnxCodecSchemaV1_ManifestDecoder + test_ccnxCodecSchemaV1_ManifestEncoder + test_ccnxCodecSchemaV1_MessageDecoder + test_ccnxCodecSchemaV1_MessageEncoder + test_ccnxCodecSchemaV1_NameCodec + test_ccnxCodecSchemaV1_NameSegmentCodec + test_ccnxCodecSchemaV1_OptionalHeadersDecoder + test_ccnxCodecSchemaV1_OptionalHeadersEncoder + test_ccnxCodecSchemaV1_PacketDecoder + test_ccnxCodecSchemaV1_PacketEncoder + test_ccnxCodecSchemaV1_TlvDictionary + test_ccnxCodecSchemaV1_ValidationDecoder + test_ccnxCodecSchemaV1_ValidationEncoder +) + + +foreach(test ${TestsExpectedToPass}) + AddTest(${test}) +endforeach() diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_CryptoSuite.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_CryptoSuite.c new file mode 100644 index 00000000..10bc24d2 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_CryptoSuite.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_CryptoSuite.c" +#include +#include + +#include + +LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_CryptoSuite) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_CryptoSuite) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_CryptoSuite) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1CryptoSuite_ParcToTlv); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1CryptoSuite_TlvToParc); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1CryptoSuite_SignAndHashToTlv); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) { + printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding()); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1CryptoSuite_ParcToTlv) +{ + struct test_vector { + PARCCryptoSuite input; + CCNxCodecSchemaV1TlvDictionary_CryptoSuite output; + bool success; + bool sentinel; + } vectors[] = { + { .input = PARCCryptoSuite_RSA_SHA256, .output = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256, .success = true, .sentinel = false }, + { .input = PARCCryptoSuite_HMAC_SHA256, .output = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256, .success = true, .sentinel = false }, + { .input = PARCCryptoSuite_NULL_CRC32C, .output = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C, .success = true, .sentinel = false }, + { .input = PARCCryptoSuite_DSA_SHA256, .output = 0, .success = false, .sentinel = false }, + { .input = PARCCryptoSuite_RSA_SHA512, .output = 0, .success = false, .sentinel = false }, + { .input = PARCCryptoSuite_HMAC_SHA512, .output = 0, .success = false, .sentinel = false }, + { .input = 13579, .output = 0, .success = false, .sentinel = false }, + { .input = 0, .output = 0, .success = false, .sentinel = true }, + }; + + for (int i = 0; !vectors[i].sentinel; i++) { + unsigned output; + bool success = ccnxCodecSchemaV1CryptoSuite_ParcToTlv(vectors[i].input, &output); + assertTrue(success == vectors[i].success, "Wrong return value, index %d expected %d got %d", i, vectors[i].success, success); + if (success) { + assertTrue(output == vectors[i].output, "Wrong output, index %d expected %u got %u", i, vectors[i].output, output); + } + } +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1CryptoSuite_TlvToParc) +{ + struct test_vector { + PARCCryptoSuite output; + CCNxCodecSchemaV1TlvDictionary_CryptoSuite input; + bool success; + bool sentinel; + } vectors[] = { + { .input = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256, .output = PARCCryptoSuite_RSA_SHA256, .success = true, .sentinel = false }, + { .input = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256, .output = PARCCryptoSuite_HMAC_SHA256, .success = true, .sentinel = false }, + { .input = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C, .output = PARCCryptoSuite_NULL_CRC32C, .success = true, .sentinel = false }, + { .input = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_EcSecp256K1, .output = 0, .success = false, .sentinel = false }, + { .input = 13579, .output = 0, .success = false, .sentinel = false }, + { .input = 0, .output = 0, .success = false, .sentinel = true }, + }; + + for (int i = 0; !vectors[i].sentinel; i++) { + unsigned output; + bool success = ccnxCodecSchemaV1CryptoSuite_TlvToParc(vectors[i].input, &output); + assertTrue(success == vectors[i].success, "Wrong return value, index %d expected %d got %d", i, vectors[i].success, success); + if (success) { + assertTrue(output == vectors[i].output, "Wrong output, index %d expected %u got %u", i, vectors[i].output, output); + } + } +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1CryptoSuite_SignAndHashToTlv) +{ + struct test_vector { + PARCSigningAlgorithm signAlg; + PARCCryptoHashType hashType; + CCNxCodecSchemaV1TlvDictionary_CryptoSuite output; + bool success; + bool sentinel; + } vectors[] = { + { .signAlg = PARCSigningAlgorithm_RSA, .hashType = PARCCryptoHashType_SHA256, .output = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256, .success = true, .sentinel = false }, + { .signAlg = PARCSigningAlgorithm_HMAC, .hashType = PARCCryptoHashType_SHA256, .output = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256, .success = true, .sentinel = false }, + { .signAlg = PARCSigningAlgortihm_NULL, .hashType = PARCCryptoHashType_CRC32C, .output = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C, .success = true, .sentinel = false }, + { .signAlg = PARCSigningAlgorithm_RSA, .hashType = 12345, .output = 0, .success = false, .sentinel = false }, + { .signAlg = PARCSigningAlgorithm_HMAC, .hashType = 12345, .output = 0, .success = false, .sentinel = false }, + { .signAlg = PARCSigningAlgortihm_NULL, .hashType = 12345, .output = 0, .success = false, .sentinel = false }, + { .signAlg = 12345, .hashType = 12345, .output = 0, .success = false, .sentinel = false }, + { .signAlg = 0, .hashType = 0, .output = 0, .success = false, .sentinel = true }, + }; + + for (int i = 0; !vectors[i].sentinel; i++) { + unsigned output; + bool success = ccnxCodecSchemaV1CryptoSuite_SignAndHashToTlv(vectors[i].signAlg, vectors[i].hashType, &output); + assertTrue(success == vectors[i].success, "Wrong return value, index %d expected %d got %d", i, vectors[i].success, success); + if (success) { + assertTrue(output == vectors[i].output, "Wrong output, index %d expected %u got %u", i, vectors[i].output, output); + } + } +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_CryptoSuite); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderDecoder.c new file mode 100644 index 00000000..7a889b58 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderDecoder.c @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_FixedHeaderDecoder.c" +#include + +#include + +typedef struct test_data { + uint8_t *packet; + PARCBuffer *fixedHeader; + CCNxCodecTlvDecoder *decoder; + CCNxTlvDictionary *dictionary; + + // truth table + uint8_t version; + uint8_t packetType; + uint16_t packetLength; + uint8_t hopLimit; + uint8_t returnCode; + uint8_t flags; + uint8_t headerLength; +} TestData; + +static TestData * +_commonSetup(void) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + + data->packet = parcMemory_Allocate(8); + assertNotNull(data->packet, "parcMemory_Allocate(%d) returned NULL", 8); + memcpy(data->packet, &((uint8_t[]) { 0x00, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x08 }), 8); + + data->fixedHeader = parcBuffer_Wrap(data->packet, 8, 0, 8); + data->version = 0; + data->packetType = 1; + data->packetLength = 0x0102; + data->hopLimit = 3; + data->returnCode = 4; + data->flags = 5; + data->headerLength = 8; + data->decoder = ccnxCodecTlvDecoder_Create(data->fixedHeader); + data->dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, + CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_END); + + return data; +} + +static void +_commonTeardown(TestData *data) +{ +// TestData *data = longBowTestCase_GetClipBoardData(testCase); + + ccnxTlvDictionary_Release(&data->dictionary); + ccnxCodecTlvDecoder_Destroy(&data->decoder); + parcBuffer_Release(&data->fixedHeader); + parcMemory_Deallocate((void **) &(data->packet)); + parcMemory_Deallocate((void **) &data); +} + +LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_FixedHeaderDecoder) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_FixedHeaderDecoder) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_FixedHeaderDecoder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_Decode_Underrun); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetHopLimit); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetReturnCode); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetFlags); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength_Missing); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType_Missing); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength_Missing); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion_Missing); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_PacketLengthTooShort); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_HeaderLengthTooShort); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_PacketLengthLessHeaderLength); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + longBowTestCase_SetClipBoardData(testCase, _commonSetup()); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + _commonTeardown(longBowTestCase_GetClipBoardData(testCase)); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +/** + * Successful decode is tested in all the _GetX functions. We only test + * when the buffer is too small here + */ +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_Decode_Underrun) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + // advance the buffer so its too small + ccnxCodecTlvDecoder_Advance(data->decoder, 1); + + size_t beforePosition = ccnxCodecTlvDecoder_Position(data->decoder); + bool success = ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary); + size_t afterPosition = ccnxCodecTlvDecoder_Position(data->decoder); + + assertFalse(success, "Should have failed with too small a buffer"); + assertTrue(beforePosition == afterPosition, "Wrong postion, got %zu expected %zu", afterPosition, beforePosition); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary); + int headerLength = ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength(data->dictionary); + assertTrue(headerLength == data->headerLength, "Wrong headerLength, got %d expected %d", headerLength, + data->headerLength); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary); + int packetType = ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType(data->dictionary); + assertTrue(packetType == data->packetType, "Wrong packetType, got %d expected %d", packetType, data->packetType); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary); + int packetLength = ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength(data->dictionary); + assertTrue(packetLength == data->packetLength, "Wrong payloadLength, got %d expected %d", packetLength, + data->packetLength); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary); + int version = ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion(data->dictionary); + assertTrue(version == data->version, "Wrong version, got %d expected %d", version, data->version); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetHopLimit) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary); + int hopLimit = ccnxCodecSchemaV1FixedHeaderDecoder_GetHopLimit(data->dictionary); + assertTrue(hopLimit == data->hopLimit, "Wrong hopLimit, got %d expected %d", hopLimit, data->hopLimit); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetReturnCode) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary); + int returnCode = ccnxCodecSchemaV1FixedHeaderDecoder_GetReturnCode(data->dictionary); + assertTrue(returnCode == data->returnCode, "Wrong returnCode, got %d expected %d", returnCode, data->returnCode); + + // Check that the InterestReturnCode was set in the fast array, too. + uint8_t test = + ccnxTlvDictionary_GetInteger(data->dictionary, + CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestReturnCode); + assertTrue(test == data->returnCode, "Expected the dictionary to have the return code set"); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetFlags) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1FixedHeaderDecoder_Decode(data->decoder, data->dictionary); + int flags = ccnxCodecSchemaV1FixedHeaderDecoder_GetFlags(data->dictionary); + assertTrue(flags == data->flags, "Wrong flags, got %d expected %d", flags, data->flags); +} + + +// ============================== +// Tests for missing values + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength_Missing) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + // don't decode the buffer, so we're operating with an empty dictionary + int version = ccnxCodecSchemaV1FixedHeaderDecoder_GetHeaderLength(data->dictionary); + assertTrue(version == -1, "Wrong HeaderLength, got %d expected %d", version, -1); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType_Missing) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + // don't decode the buffer, so we're operating with an empty dictionary + int version = ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketType(data->dictionary); + assertTrue(version == -1, "Wrong PacketType, got %d expected %d", version, -1); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength_Missing) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + // don't decode the buffer, so we're operating with an empty dictionary + int version = ccnxCodecSchemaV1FixedHeaderDecoder_GetPacketLength(data->dictionary); + assertTrue(version == -1, "Wrong payloadLength, got %d expected %d", version, -1); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion_Missing) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + // don't decode the buffer, so we're operating with an empty dictionary + int version = ccnxCodecSchemaV1FixedHeaderDecoder_GetVersion(data->dictionary); + assertTrue(version == -1, "Wrong version, got %d expected %d", version, -1); +} + + +/** + * Packet length must be at least 8 bytes + */ +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_PacketLengthTooShort) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + CCNxCodecSchemaV1InterestHeader header = { + .version = 1, + .packetType = CCNxCodecSchemaV1Types_PacketType_Interest, + .packetLength = htons(3), + .hopLimit = 4, + .returnCode = 7, + .flags = 8, + .headerLength = 9, + }; + + PARCBuffer *fixedHeader = parcBuffer_Wrap(&header, 8, 0, 8); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(fixedHeader); + + bool success = ccnxCodecSchemaV1FixedHeaderDecoder_Decode(decoder, data->dictionary); + assertFalse(success, "Did not fail on packet length too short"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&fixedHeader); +} + +/** + * Header length must be at least 8 bytes + */ +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_HeaderLengthTooShort) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + CCNxCodecSchemaV1InterestHeader header = { + .version = 1, + .packetType = CCNxCodecSchemaV1Types_PacketType_Interest, + .packetLength = htons(12), + .hopLimit = 4, + .returnCode = 7, + .flags = 8, + .headerLength = 6, + }; + + PARCBuffer *fixedHeader = parcBuffer_Wrap(&header, 8, 0, 8); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(fixedHeader); + + bool success = ccnxCodecSchemaV1FixedHeaderDecoder_Decode(decoder, data->dictionary); + assertFalse(success, "Did not fail on header length too short"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&fixedHeader); +} + +/** + * Packet length must be no less than Header Length + */ +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderDecoder_PacketLengthLessHeaderLength) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + CCNxCodecSchemaV1InterestHeader header = { + .version = 1, + .packetType = CCNxCodecSchemaV1Types_PacketType_Interest, + .packetLength = htons(12), + .hopLimit = 4, + .returnCode = 7, + .flags = 8, + .headerLength = 18, + }; + + PARCBuffer *fixedHeader = parcBuffer_Wrap(&header, 8, 0, 8); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(fixedHeader); + + bool success = ccnxCodecSchemaV1FixedHeaderDecoder_Decode(decoder, data->dictionary); + assertFalse(success, "Did not fail on packet length less than header length"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&fixedHeader); +} + +// ====================== + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_FixedHeaderDecoder); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderEncoder.c new file mode 100755 index 00000000..4f479090 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_FixedHeaderEncoder.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_FixedHeaderEncoder.c" +#include +#include + +#include + +LONGBOW_TEST_RUNNER(ccnxCodecSchemaV0_FixedHeaderEncoder) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV0_FixedHeaderEncoder) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV0_FixedHeaderEncoder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderEncoder_EncodeInterest); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderEncoder_EncodeContentObject); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderEncoder_EncodeInterestReturn); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderEncoder_EncodeInterest) +{ + uint16_t packetLength = 0x0102; + + CCNxCodecSchemaV1InterestHeader header = { + .version = 1, + .packetType = CCNxCodecSchemaV1Types_PacketType_Interest, + .packetLength = packetLength, + .hopLimit = 4, + .returnCode = 7, // will be set to 0 + .flags = 8, + .headerLength = 9, + }; + + CCNxCodecSchemaV1InterestHeader truth = { + .version = 1, + .packetType = CCNxCodecSchemaV1Types_PacketType_Interest, + .packetLength = htons(packetLength), + .hopLimit = 4, + .returnCode = 0, + .flags = 8, + .headerLength = 9, + }; + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + ssize_t length = ccnxCodecSchemaV1FixedHeaderEncoder_EncodeHeader(encoder, (CCNxCodecSchemaV1FixedHeader *) &header); + assertTrue(length == 8, "Wrong length, got %zd expected %d", length, 8); + + testCompareEncoderToLinearMemory(encoder, length, (uint8_t *) &truth); + + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderEncoder_EncodeContentObject) +{ + uint16_t packetLength = 0x0102; + + CCNxCodecSchemaV1InterestHeader header = { + .version = 1, + .packetType = CCNxCodecSchemaV1Types_PacketType_ContentObject, + .packetLength = packetLength, + .hopLimit = 4, // will be set to 0 + .returnCode = 7, // will be set to 0 + .flags = 8, // will be set to 0 + .headerLength = 9, + }; + + CCNxCodecSchemaV1InterestHeader truth = { + .version = 1, + .packetType = CCNxCodecSchemaV1Types_PacketType_ContentObject, + .packetLength = htons(packetLength), + .hopLimit = 0, + .returnCode = 0, + .flags = 0, + .headerLength = 9, + }; + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + ssize_t length = ccnxCodecSchemaV1FixedHeaderEncoder_EncodeHeader(encoder, (CCNxCodecSchemaV1FixedHeader *) &header); + assertTrue(length == 8, "Wrong length, got %zd expected %d", length, 8); + + testCompareEncoderToLinearMemory(encoder, length, (uint8_t *) &truth); + + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1FixedHeaderEncoder_EncodeInterestReturn) +{ + uint16_t packetLength = 0x0102; + + CCNxCodecSchemaV1InterestHeader header = { + .version = 1, + .packetType = CCNxCodecSchemaV1Types_PacketType_InterestReturn, + .packetLength = packetLength, + .hopLimit = 4, + .returnCode = 7, + .flags = 8, + .headerLength = 9, + }; + + CCNxCodecSchemaV1InterestHeader truth = { + .version = 1, + .packetType = CCNxCodecSchemaV1Types_PacketType_InterestReturn, + .packetLength = htons(packetLength), + .hopLimit = 4, + .returnCode = 7, + .flags = 8, + .headerLength = 9, + }; + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + ssize_t length = ccnxCodecSchemaV1FixedHeaderEncoder_EncodeHeader(encoder, (CCNxCodecSchemaV1FixedHeader *) &header); + assertTrue(length == 8, "Wrong length, got %zd expected %d", length, 8); + + testCompareEncoderToLinearMemory(encoder, length, (uint8_t *) &truth); + + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV0_FixedHeaderEncoder); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_HashCodec.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_HashCodec.c new file mode 100644 index 00000000..9d03ca2e --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_HashCodec.c @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_HashCodec.c" + +#include + +#include +#include + +#include + +LONGBOW_TEST_RUNNER(ccnxTlvCodec_Hash) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxTlvCodec_Hash) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxTlvCodec_Hash) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidHash); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidLength_SHA256); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidLength_SHA512); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidLength_App); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1HashCodec_Encode); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1HashCodec_Encode_InvalidLength); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) { + printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding()); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue) +{ + // -- 32-byte hash + uint8_t encoded[] = { + 0x00, CCNxCodecSchemaV1Types_HashType_SHA256, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + }; + + PARCBuffer *tlvBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + PARCBuffer *payloadBuffer = parcBuffer_Wrap(encoded + 4, sizeof(encoded) - 4, 0, sizeof(encoded) - 4); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(tlvBuffer); + PARCCryptoHash *hash = ccnxCodecSchemaV1HashCodec_DecodeValue(decoder, sizeof(encoded)); + assertNotNull(hash, "got non-NULL hash when it should have been an error (null)"); + + assertTrue(parcCryptoHash_GetDigestType(hash) == PARCCryptoHashType_SHA256, "Expected to decode the correct hash type."); + assertTrue(parcBuffer_Equals(payloadBuffer, parcCryptoHash_GetDigest(hash)), "Expected the digest to match."); + + CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder); + assertNull(error, "Got null error when it should have been set"); + + parcCryptoHash_Release(&hash); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&tlvBuffer); + parcBuffer_Release(&payloadBuffer); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidHash) +{ + // -- 32-byte hash + uint8_t encoded[] = { + 0x00, 0xFF, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + }; + + PARCBuffer *tlvBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(tlvBuffer); + PARCCryptoHash *hash = ccnxCodecSchemaV1HashCodec_DecodeValue(decoder, sizeof(encoded)); + assertNull(hash, "Should not have decoded an incorrect hash digest"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&tlvBuffer); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidLength_SHA256) +{ + // -- 32-byte hash + uint8_t encoded[] = { + 0x00, CCNxCodecSchemaV1Types_HashType_SHA256, 0x00, 0x18, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + }; + + PARCBuffer *tlvBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(tlvBuffer); + PARCCryptoHash *hash = ccnxCodecSchemaV1HashCodec_DecodeValue(decoder, sizeof(encoded)); + assertNull(hash, "Should not have decoded a SHA256 hash digest with an incorrect length"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&tlvBuffer); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidLength_SHA512) +{ + // -- 32-byte hash + uint8_t encoded[] = { + 0x00, CCNxCodecSchemaV1Types_HashType_SHA512, 0x00, 0x18, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + }; + + PARCBuffer *tlvBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(tlvBuffer); + PARCCryptoHash *hash = ccnxCodecSchemaV1HashCodec_DecodeValue(decoder, sizeof(encoded)); + assertNull(hash, "Should not have decoded a SHA512 hash digest with an incorrect length"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&tlvBuffer); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecHash_DecodeValue_InvalidLength_App) +{ + // -- 32-byte hash + uint8_t encoded[] = { + 0x00, CCNxCodecSchemaV1Types_HashType_App, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00,0x00,0x00, 0x00, 0x00 + }; + + PARCBuffer *tlvBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(tlvBuffer); + PARCCryptoHash *hash = ccnxCodecSchemaV1HashCodec_DecodeValue(decoder, sizeof(encoded)); + assertNotNull(hash, "Should have decoded an application hash digest with an arbitrary length"); + + parcCryptoHash_Release(&hash); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&tlvBuffer); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1HashCodec_Encode) +{ + uint8_t encoded[] = { + 0x00, CCNxCodecSchemaV1Types_HashType_SHA256, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + }; + + PARCBuffer *trueEncoding = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + // Create the hash + PARCBuffer *payloadBuffer = parcBuffer_Allocate(0x20); + PARCCryptoHash *expectedHash = parcCryptoHash_Create(PARCCryptoHashType_SHA256, payloadBuffer); + + // Encode it + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ssize_t length = ccnxCodecSchemaV1HashCodec_Encode(encoder, expectedHash); + assertFalse(length < 0, "Got error on encode: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + assertTrue(length == sizeof(encoded), "Wrong length, expected %zd got %zd", sizeof(encoded), length); + + // Check for equality + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *testEncoding = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(trueEncoding, testEncoding), "The hash was encoded incorrectly.") + { + printf("Expected\n"); + parcBuffer_Display(trueEncoding, 3); + printf("Got\n"); + parcBuffer_Display(testEncoding, 3); + } + + parcBuffer_Release(&testEncoding); + parcBuffer_Release(&trueEncoding); + + parcCryptoHash_Release(&expectedHash); + parcBuffer_Release(&payloadBuffer); + + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1HashCodec_Encode_InvalidLength) +{ +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxTlvCodec_Hash); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_LinkCodec.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_LinkCodec.c new file mode 100755 index 00000000..599e3a5a --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_LinkCodec.c @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_LinkCodec.c" +#include +#include + +#include + +LONGBOW_TEST_RUNNER(ccnxTlvCodec_Name) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxTlvCodec_Name) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxTlvCodec_Name) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_NameOnly); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_AllFields); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_NoName); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_ExtraField); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_DupName); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_DupKeyId); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_DupHash); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_FieldOverrun); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_Underrun); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1LinkCodec_Encode); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) { + printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding()); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_NameOnly) +{ + CCNxName *truth = ccnxName_CreateFromCString("lci:/3=rope"); + + uint8_t encoded[] = { + 0x00, 0x00, 0x00, 8, + 0x00, 0x03, 0x00, 4, + 'r', 'o', 'p', 'e' + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded)); + assertNotNull(link, "got null link: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + const CCNxName *test = ccnxLink_GetName(link); + assertTrue(ccnxName_Equals(truth, test), "Wrong name") + { + printf("Expected\n"); + ccnxName_Display(truth, 3); + printf("Got\n"); + ccnxName_Display(test, 3); + } + + PARCBuffer *testKeyid = ccnxLink_GetKeyID(link); + assertNull(testKeyid, "Got a keyid without the wire encoding for it"); + + PARCBuffer *testHash = ccnxLink_GetContentObjectHash(link); + assertNull(testHash, "got a hash without the wire encoding for it"); + + ccnxLink_Release(&link); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); + ccnxName_Release(&truth); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_AllFields) +{ + CCNxName *truth = ccnxName_CreateFromCString("lci:/3=rope"); + + uint8_t encoded[] = { + // -- name + 0x00, 0x00, 0x00, 8, + 0x00, 0x03, 0x00, 4, + 'r', 'o', 'p', 'e', + // -- keyid + 0x00, 0x01, 0x00, 8, + 0xa0, 0xa1, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa6, 0xa7, + // -- hash + 0x00, 0x02, 0x00, 16, + 0xb0, 0xb1, 0xb2, 0xb3, + 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, + 0xbc, 0xbd, 0xbe, 0xbf, + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded)); + assertNotNull(link, "got null link: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + const CCNxName *test = ccnxLink_GetName(link); + assertTrue(ccnxName_Equals(truth, test), "Wrong name") + { + printf("Expected\n"); + ccnxName_Display(truth, 3); + printf("Got\n"); + ccnxName_Display(test, 3); + } + + PARCBuffer *keyid = parcBuffer_Wrap(encoded, sizeof(encoded), 16, 24); + PARCBuffer *testKeyid = ccnxLink_GetKeyID(link); + assertTrue(parcBuffer_Equals(keyid, testKeyid), "Wrong keyid") + { + printf("Expected\n"); + parcBuffer_Display(keyid, 3); + printf("Got\n"); + parcBuffer_Display(testKeyid, 3); + } + + PARCBuffer *hash = parcBuffer_Wrap(encoded, sizeof(encoded), 28, 44); + PARCBuffer *testHash = ccnxLink_GetContentObjectHash(link); + assertTrue(parcBuffer_Equals(hash, testHash), "Wrong hash") + { + printf("Expected\n"); + parcBuffer_Display(hash, 3); + printf("Got\n"); + parcBuffer_Display(testHash, 3); + } + + parcBuffer_Release(&hash); + parcBuffer_Release(&keyid); + + ccnxLink_Release(&link); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); + ccnxName_Release(&truth); +} + +/* + * wire format missing name + */ +LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_NoName) +{ + uint8_t encoded[] = { + // -- keyid + 0x00, 0x01, 0x00, 8, + 0xa0, 0xa1, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa6, 0xa7, + // -- hash + 0x00, 0x02, 0x00, 16, + 0xb0, 0xb1, 0xb2, 0xb3, + 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, + 0xbc, 0xbd, 0xbe, 0xbf, + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded)); + assertNull(link, "got non-null link when it should have been an error (null)"); + + CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder); + assertNotNull(error, "Got null error when it should have been set"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +/* + * Wire format has an extra TLV in it that's not part of the spec + */ +LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_ExtraField) +{ + uint8_t encoded[] = { + // -- name + 0x00, 0x00, 0x00, 8, + 0x00, 0x03, 0x00, 4, + 'r', 'o', 'p', 'e', + // -- keyid + 0x00, 0x01, 0x00, 8, + 0xa0, 0xa1, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa6, 0xa7, + // -- hash + 0x00, 0x02, 0x00, 16, + 0xb0, 0xb1, 0xb2, 0xb3, + 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, + 0xbc, 0xbd, 0xbe, 0xbf, + // -- extra + 0x00, 0xFF, 0x00, 4, + 0xc0, 0xc1, 0xc2, 0xc3, + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded)); + assertNull(link, "got non-null link when it should have been an error (null)"); + + CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder); + assertNotNull(error, "Got null error when it should have been set"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_DupName) +{ + uint8_t encoded[] = { + // -- name + 0x00, 0x00, 0x00, 8, + 0x00, 0x03, 0x00, 4, + 'r', 'o', 'p', 'e', + // -- keyid + 0x00, 0x01, 0x00, 8, + 0xa0, 0xa1, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa6, 0xa7, + // -- hash + 0x00, 0x02, 0x00, 16, + 0xb0, 0xb1, 0xb2, 0xb3, + 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, + 0xbc, 0xbd, 0xbe, 0xbf, + // -- name + 0x00, 0x00, 0x00, 8, + 0x00, 0x03, 0x00, 4, + 'r', 'o', 'p', 'e', + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded)); + assertNull(link, "got non-null link when it should have been an error (null)"); + + CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder); + assertNotNull(error, "Got null error when it should have been set"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_DupKeyId) +{ + uint8_t encoded[] = { + // -- name + 0x00, 0x00, 0x00, 8, + 0x00, 0x03, 0x00, 4, + 'r', 'o', 'p', 'e', + // -- keyid + 0x00, 0x01, 0x00, 8, + 0xa0, 0xa1, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa6, 0xa7, + // -- hash + 0x00, 0x02, 0x00, 16, + 0xb0, 0xb1, 0xb2, 0xb3, + 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, + 0xbc, 0xbd, 0xbe, 0xbf, + // -- keyid + 0x00, 0x01, 0x00, 8, + 0xa0, 0xa1, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa6, 0xa7, + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded)); + assertNull(link, "got non-null link when it should have been an error (null)"); + + CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder); + assertNotNull(error, "Got null error when it should have been set"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_DupHash) +{ + uint8_t encoded[] = { + // -- name + 0x00, 0x00, 0x00, 8, + 0x00, 0x03, 0x00, 4, + 'r', 'o', 'p', 'e', + // -- keyid + 0x00, 0x01, 0x00, 8, + 0xa0, 0xa1, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa6, 0xa7, + // -- hash + 0x00, 0x02, 0x00, 16, + 0xb0, 0xb1, 0xb2, 0xb3, + 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, + 0xbc, 0xbd, 0xbe, 0xbf, + // -- hash + 0x00, 0x02, 0x00, 16, + 0xb0, 0xb1, 0xb2, 0xb3, + 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, + 0xbc, 0xbd, 0xbe, 0xbf, + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded)); + assertNull(link, "got non-null link when it should have been an error (null)"); + + CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder); + assertNotNull(error, "Got null error when it should have been set"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_FieldOverrun) +{ + // name length is beyond end of fragment + uint8_t encoded[] = { + 0x00, 0x00, 0x00, 30, + 0x00, 0x03, 0x00, 4, + 'r', 'o', 'p', 'e' + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded)); + assertNull(link, "got non-null link when it should have been an error (null)"); + + CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder); + assertNotNull(error, "Got null error when it should have been set"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecLink_DecodeValue_Underrun) +{ + // buffer is too short to even parse the T and L + uint8_t encoded[] = { + 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + // the "2" makes it too short to parse + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, 2); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxLink *link = ccnxCodecSchemaV1LinkCodec_DecodeValue(decoder, sizeof(encoded)); + assertNull(link, "got non-null link when it should have been an error (null)"); + + CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder); + assertNotNull(error, "Got null error when it should have been set"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +// ============ + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1LinkCodec_Encode) +{ + uint8_t encoded[] = { + // -- name + 0x00, 0x00, 0x00, 8, + 0x00, 0x03, 0x00, 4, + 'r', 'o', 'p', 'e', + // -- keyid + 0x00, 0x01, 0x00, 8, + 0xa0, 0xa1, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa6, 0xa7, + // -- hash + 0x00, 0x02, 0x00, 16, + 0xb0, 0xb1, 0xb2, 0xb3, + 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, + 0xbc, 0xbd, 0xbe, 0xbf, + }; + + CCNxName *trueName = ccnxName_CreateFromCString("lci:/3=rope"); + PARCBuffer *trueKeyId = parcBuffer_Wrap(encoded, sizeof(encoded), 16, 24); + PARCBuffer *trueHash = parcBuffer_Wrap(encoded, sizeof(encoded), 28, 44); + PARCBuffer *trueEncoding = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxLink *link = ccnxLink_Create(trueName, trueKeyId, trueHash); + + // now encode it and compare the the trueEncoding + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + ssize_t length = ccnxCodecSchemaV1LinkCodec_Encode(encoder, link); + assertFalse(length < 0, "Got error on encode: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + assertTrue(length == sizeof(encoded), "Wrong length, expected %zd got %zd", sizeof(encoded), length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *testEncoding = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(trueEncoding, testEncoding), "Wrong hash") + { + printf("Expected\n"); + parcBuffer_Display(trueEncoding, 3); + printf("Got\n"); + parcBuffer_Display(testEncoding, 3); + } + + parcBuffer_Release(&testEncoding); + parcBuffer_Release(&trueEncoding); + parcBuffer_Release(&trueHash); + parcBuffer_Release(&trueKeyId); + ccnxName_Release(&trueName); + + ccnxLink_Release(&link); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxTlvCodec_Name); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestDecoder.c new file mode 100755 index 00000000..3c1609ab --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestDecoder.c @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_ManifestDecoder.c" +#include +#include + +#include "testrig_encoder.c" + +#include + +// ========================================================================= + +LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_ManifestDecoder) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_ManifestDecoder) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_ManifestDecoder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_Decode); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_DecodeType); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_DecodeHashGroup); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_DecodeHashGroupMetadata); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_Decode) +{ + uint8_t rawManifest[40] = { 0x00, 0x07, 0x00, 0x24, + 0x00, 0x02, 0x00, 0x20, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46 }; + PARCBuffer *wireFormat = parcBuffer_Flip(parcBuffer_CreateFromArray(rawManifest, 40)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(wireFormat); + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateManifest(); + + bool result = ccnxCodecSchemaV1ManifestDecoder_Decode(decoder, dict); + assertTrue(result, "Expected the manifest to be decoded correctly"); + + ccnxTlvDictionary_Release(&dict); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&wireFormat); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_DecodeType) +{ + uint8_t rawManifest[40] = { 0x00, 0x07, 0x00, 0x24, + 0x00, 0x02, 0x00, 0x20, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46 }; + PARCBuffer *wireFormat = parcBuffer_Flip(parcBuffer_CreateFromArray(rawManifest, 40)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(wireFormat); + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateManifest(); + + uint16_t type = ccnxCodecTlvDecoder_GetType(decoder); + uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder); + + bool result = _decodeType(decoder, dict, type, length); + assertTrue(result, "Expected the manifest type to be correctly decoded at the top level"); + + ccnxManifest_Release(&dict); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&wireFormat); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_DecodeHashGroup) +{ + uint8_t rawManifest[40] = { 0x00, 0x07, 0x00, 0x24, + 0x00, 0x02, 0x00, 0x20, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46 }; + PARCBuffer *wireFormat = parcBuffer_Flip(parcBuffer_CreateFromArray(rawManifest, 40)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(wireFormat); + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateManifest(); + + ccnxCodecTlvDecoder_GetType(decoder); // swallow type + uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder); + + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + bool result = _decodeHashGroup(decoder, dict, group, length); + assertTrue(result, "Expected hash group to be decoded correctly."); + + PARCBuffer *expectedPointer = parcBuffer_AllocateCString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); + CCNxManifestHashGroupPointer *pointer = ccnxManifestHashGroup_GetPointerAtIndex(group, 0); + const PARCBuffer *actualPointer = ccnxManifestHashGroupPointer_GetDigest(pointer); + assertTrue(parcBuffer_Equals(expectedPointer, actualPointer), "Expected decoded pointer to equal %s, got %s", parcBuffer_ToHexString(expectedPointer), parcBuffer_ToHexString(actualPointer)); + + parcBuffer_Release(&expectedPointer); + + ccnxManifestHashGroup_Release(&group); + ccnxManifest_Release(&dict); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&wireFormat); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestDecoder_DecodeHashGroupMetadata) +{ + // Re-build the expected metadata from the manifest + CCNxName *groupLocator = ccnxName_CreateFromCString("ccnx:/locator"); + PARCBuffer *digest = parcBuffer_Allocate(16); + for (size_t i = 0; i < parcBuffer_Limit(digest); i++) { + parcBuffer_PutUint8(digest, 0); + } + parcBuffer_Flip(digest); + size_t entrySize = 1; + size_t dataSize = 2; + size_t blockSize = 3; + size_t treeHeight = 4; + + // Compute the expected size of this metadata group. + size_t metadataSize = 4 * (4 + 8) + 4 + parcBuffer_Limit(digest) + 4 + strlen("ccnx:/locator"); + + // See test_ccnxCodecSchemaV1_ManifestEncoder.c for the packet construction details. + uint8_t rawMetadata[89] = { 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroup_Metadata, + 0x00, metadataSize, + 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_Locator, + 0x00, strlen("ccnx:/locator"), + 'c', 'c', + 'n', 'x', + ':', '/', + 'l', 'o', + 'c', 'a', + 't', 'o', + 'r', + 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_DataSize, + 0x00, 0x08, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, dataSize, + 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_BlockSize, + 0x00, 0x08, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, blockSize, + 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_EntrySize, + 0x00, 0x08, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, entrySize, + 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_TreeHeight, + 0x00, 0x08, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, treeHeight, + 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_OverallDataSha256, + 0x00, parcBuffer_Remaining(digest), + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00 }; + PARCBuffer *wireFormat = parcBuffer_Flip(parcBuffer_CreateFromArray(rawMetadata, sizeof(rawMetadata))); + + // Create the encoder and swallow the top level container + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(wireFormat); + ccnxCodecTlvDecoder_GetType(decoder); // swallow type + uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder); + + // Decode the metadata + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + bool result = _decodeHashGroupMetadata(decoder, group, length); + assertTrue(result, "Expected hash group metadata to be decoded correctly."); + + const CCNxName *actualLocator = ccnxManifestHashGroup_GetLocator(group); + size_t actualEntrySize = ccnxManifestHashGroup_GetEntrySize(group); + size_t actualDataSize = ccnxManifestHashGroup_GetDataSize(group); + size_t actualBlockSize = ccnxManifestHashGroup_GetBlockSize(group); + size_t actualTreeHeight = ccnxManifestHashGroup_GetTreeHeight(group); + const PARCBuffer *actualDigest = ccnxManifestHashGroup_GetOverallDataDigest(group); + + assertTrue(ccnxName_Equals(groupLocator, actualLocator), "Expected decoded locator to equal %s, got %s", ccnxName_ToString(groupLocator), ccnxName_ToString(actualLocator)); + assertTrue(entrySize == actualEntrySize, "Expected %zu entry size, got %zu", entrySize, actualEntrySize); + assertTrue(dataSize == actualDataSize, "Expected %zu data size, got %zu", dataSize, actualDataSize); + assertTrue(blockSize == actualBlockSize, "Expected %zu block size, got %zu", blockSize, actualBlockSize); + assertTrue(treeHeight == actualTreeHeight, "Expected %zu tree height, got %zu", treeHeight, actualTreeHeight); + assertTrue(parcBuffer_Equals(digest, actualDigest), "Expected %s digest, got %s", parcBuffer_ToHexString(digest), parcBuffer_ToHexString(actualDigest)); + + parcBuffer_Release(&digest); + ccnxName_Release(&groupLocator); + + ccnxManifestHashGroup_Release(&group); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&wireFormat); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_ManifestDecoder); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestEncoder.c new file mode 100755 index 00000000..a0e36abf --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ManifestEncoder.c @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_ManifestEncoder.c" +#include +#include + +#include "testrig_encoder.c" + +#include + +// ========================================================================= + +LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_ManifestEncoder) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_ManifestEncoder) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_ManifestEncoder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_EncodeEmpty); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_EncodeSingleHashGroup); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_EncodeSingleHashGroup_WithMetadata); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_AddPointer); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_EncodeEmpty) +{ + CCNxName *locator = ccnxName_CreateFromCString("lci:/name"); + CCNxManifest *manifest = ccnxManifest_Create(locator); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + size_t result = ccnxCodecSchemaV1ManifestEncoder_Encode(encoder, manifest); + + assertTrue(result == 0, "Expected an empty Manifest to be encoded to size 0, got %zu", result); + + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxManifest_Release(&manifest); + ccnxName_Release(&locator); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_AddPointer) +{ + CCNxName *locator = ccnxName_CreateFromCString("ccnx:/name"); + CCNxManifest *manifest = ccnxManifest_Create(locator); + + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + PARCBuffer *pointer = parcBuffer_Flip(parcBuffer_ParseHexString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")); + ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, pointer); + + ccnxManifest_AddHashGroup(manifest, group); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + size_t result = ccnxCodecSchemaV1ManifestEncoder_Encode(encoder, manifest); + size_t expected = 4 + 4 + parcBuffer_Remaining(pointer); // hash group TL, pointer TL, pointer V + + assertTrue(result == expected, "Expected an empty Manifest to be encoded to size %zu, got %zu", expected, result); + + CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecTlvEncoder_CreateIoVec(encoder); + const struct iovec *vector = ccnxCodecNetworkBufferIoVec_GetArray(iovec); + + assertTrue(vector->iov_len == expected, "Expected the IO vector to contain the encoded manifest"); + assertTrue(memcmp(vector->iov_base + 8, parcBuffer_Overlay(pointer, parcBuffer_Remaining(pointer)), vector->iov_len - 8) == 0, "Expected the same pointer to be encoded"); + + uint16_t expectedType = CCNxCodecSchemaV1Types_CCNxManifestHashGroup_DataPointer; + uint8_t *base = (uint8_t *) vector->iov_base; + uint16_t actualType = (base[4] << 8) | base[5]; + assertTrue(expectedType == actualType, "Expected the type to be written correctly as CCNxCodecSchemaV1Types_CCNxManifestHashGroup_DataPointer"); + + ccnxCodecNetworkBufferIoVec_Release(&iovec); + + // Cleanup + parcBuffer_Release(&pointer); + ccnxManifestHashGroup_Release(&group); + + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxManifest_Release(&manifest); + ccnxName_Release(&locator); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_EncodeSingleHashGroup) +{ + CCNxName *locator = ccnxName_CreateFromCString("ccnx:/name"); + CCNxManifest *manifest = ccnxManifest_Create(locator); + + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + PARCBuffer *pointer = parcBuffer_Flip(parcBuffer_ParseHexString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")); + ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, pointer); + + ccnxManifest_AddHashGroup(manifest, group); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + size_t result = ccnxCodecSchemaV1ManifestEncoder_Encode(encoder, manifest); + size_t expected = 4 + 4 + parcBuffer_Remaining(pointer); // hash group TL, pointer TL, pointer V + + assertTrue(result == expected, "Expected an empty Manifest to be encoded to size %zu, got %zu", expected, result); + + CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecTlvEncoder_CreateIoVec(encoder); + const struct iovec *vector = ccnxCodecNetworkBufferIoVec_GetArray(iovec); + + uint8_t expectedVector[24] = { 0x00, 0x07, 0x00, 0x14, + 0x00, 0x02, 0x00, 0x10, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF }; + assertTrue(vector->iov_len == expected, "Expected the IO vector to contain the encoded manifest"); + assertTrue(memcmp(vector->iov_base, expectedVector, vector->iov_len) == 0, "Expected the same pointer to be encoded"); + + ccnxCodecNetworkBufferIoVec_Release(&iovec); + + // Cleanup + parcBuffer_Release(&pointer); + ccnxManifestHashGroup_Release(&group); + + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxManifest_Release(&manifest); + ccnxName_Release(&locator); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1ManifestEncoder_EncodeSingleHashGroup_WithMetadata) +{ + CCNxName *locator = ccnxName_CreateFromCString("ccnx:/name"); + CCNxManifest *manifest = ccnxManifest_Create(locator); + + CCNxManifestHashGroup *group = ccnxManifestHashGroup_Create(); + PARCBuffer *pointer = parcBuffer_Flip(parcBuffer_ParseHexString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")); + ccnxManifestHashGroup_AppendPointer(group, CCNxManifestHashGroupPointerType_Data, pointer); + + // Set the metadata now + CCNxName *groupLocator = ccnxName_CreateFromCString("ccnx:/locator"); + ccnxManifestHashGroup_SetLocator(group, groupLocator); + + PARCBuffer *digest = parcBuffer_Allocate(16); + for (size_t i = 0; i < parcBuffer_Limit(digest); i++) { + parcBuffer_PutUint8(digest, 0); + } + parcBuffer_Flip(digest); + ccnxManifestHashGroup_SetOverallDataDigest(group, digest); + + size_t entrySize = 1; + ccnxManifestHashGroup_SetEntrySize(group, entrySize); + + size_t dataSize = 2; + ccnxManifestHashGroup_SetDataSize(group, dataSize); + + size_t blockSize = 3; + ccnxManifestHashGroup_SetBlockSize(group, blockSize); + + size_t treeHeight = 4; + ccnxManifestHashGroup_SetTreeHeight(group, treeHeight); + + // Add the hash group to the manifest + ccnxManifest_AddHashGroup(manifest, group); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + size_t result = ccnxCodecSchemaV1ManifestEncoder_Encode(encoder, manifest); + + // Compute the expected size with all of the metadata. + // This packet was crafted by hand. + size_t expected = 4; // hash group TL + expected += 4 + parcBuffer_Remaining(pointer); // pointer TL, pointer V + expected += 4; // metadata TL + expected += 4 * (4 + 8); // 64-bit integer property TLs, Vs + expected += 4 + parcBuffer_Remaining(digest); // digest T and V + expected += 4 + strlen("ccnx:/locator"); // name TL, segment TL, and segment V + + // Compute only the size of the metadata + size_t metadataSize = expected; + metadataSize -= 4; // top-level TL container + metadataSize -= (4 + parcBuffer_Remaining(pointer)); // pointer TLV + metadataSize -= 4; // metadata TL container + + assertTrue(result == expected, "Expected an empty Manifest to be encoded to size %zu, got %zu", expected, result); + + // Now do the encoding + CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecTlvEncoder_CreateIoVec(encoder); + const struct iovec *vector = ccnxCodecNetworkBufferIoVec_GetArray(iovec); + + uint8_t expectedVector[129] = { 0x00, 0x07, + 0x00, expected - 4, + 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroup_Metadata, + 0x00, metadataSize, + 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_Locator, + 0x00, strlen("ccnx:/locator"), + 'c', 'c', + 'n', 'x', + ':', '/', + 'l', 'o', + 'c', 'a', + 't', 'o', + 'r', + 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_DataSize, + 0x00, 0x08, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, dataSize, + 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_BlockSize, + 0x00, 0x08, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, blockSize, + 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_EntrySize, + 0x00, 0x08, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, entrySize, + 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_TreeHeight, + 0x00, 0x08, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, treeHeight, + 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroupMetadata_OverallDataSha256, + 0x00, parcBuffer_Remaining(digest), + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, CCNxCodecSchemaV1Types_CCNxManifestHashGroup_DataPointer, + 0x00, parcBuffer_Remaining(pointer), + 0xFF, 0xFF, + 0xFF, 0xFF, + 0xFF, 0xFF, + 0xFF, 0xFF, + 0xFF, 0xFF, + 0xFF, 0xFF, + 0xFF, 0xFF, + 0xFF, 0xFF }; + assertTrue(vector->iov_len == expected, "Expected the IO vector to contain the encoded manifest"); + assertTrue(memcmp(vector->iov_base, expectedVector, vector->iov_len) == 0, "Expected the same HashGroup to be encoded"); + + ccnxCodecNetworkBufferIoVec_Release(&iovec); + + // Cleanup + parcBuffer_Release(&pointer); + parcBuffer_Release(&digest); + ccnxManifestHashGroup_Release(&group); + ccnxName_Release(&groupLocator); + + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxManifest_Release(&manifest); + ccnxName_Release(&locator); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_ManifestEncoder); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageDecoder.c new file mode 100644 index 00000000..ab339fc1 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageDecoder.c @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_MessageDecoder.c" +#include +#include +#include +#include + +#include "testrig_packetwrapper.c" + + +// ========================================================================= + +LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_MessageDecoder) +{ + LONGBOW_RUN_TEST_FIXTURE(ContentObject); + LONGBOW_RUN_TEST_FIXTURE(Interest); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_MessageDecoder) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_MessageDecoder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ========================================================================= +// Utility functions to get a field in the format we expect for the testrig. +// We cannot use the facades because those try to assert a type on the dictionary which +// is not part of the MessageDecoder. + +static CCNxName * +_getName(CCNxTlvDictionary *contentObjectDictionary) +{ + return ccnxTlvDictionary_GetName(contentObjectDictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME); +} + +static PARCBuffer * +_getPayload(const CCNxTlvDictionary *contentObjectDictionary) +{ + return ccnxTlvDictionary_GetBuffer(contentObjectDictionary, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD); +} + +static int64_t +_getPayloadType(CCNxTlvDictionary *contentObjectDictionary) +{ + return (int64_t) ccnxTlvDictionary_GetInteger(contentObjectDictionary, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE); +} + +static int64_t +_getExpiryTime(CCNxTlvDictionary *contentObjectDictionary) +{ + return (int64_t) ccnxTlvDictionary_GetInteger(contentObjectDictionary, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME); +} + +static int64_t +_getEndChunkNumber(CCNxTlvDictionary *contentObjectDictionary) +{ + return (int64_t) ccnxTlvDictionary_GetInteger(contentObjectDictionary, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT); +} + +static PARCCryptoHash * +_getKeyIdRestriction(CCNxTlvDictionary *messageDictionary) +{ + return (PARCCryptoHash *) ccnxTlvDictionary_GetObject(messageDictionary, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_KEYID_RESTRICTION); +} + +static PARCCryptoHash * +_getHashRestriction(CCNxTlvDictionary *messageDictionary) +{ + return (PARCCryptoHash *) ccnxTlvDictionary_GetObject(messageDictionary, + CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION); +} + + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(ContentObject) +{ + LONGBOW_RUN_TEST_CASE(ContentObject, Name); + LONGBOW_RUN_TEST_CASE(ContentObject, Payload); + LONGBOW_RUN_TEST_CASE(ContentObject, PayloadType); + LONGBOW_RUN_TEST_CASE(ContentObject, ExpiryTime); + LONGBOW_RUN_TEST_CASE(ContentObject, EndChunkNumber); +} + +LONGBOW_TEST_FIXTURE_SETUP(ContentObject) +{ + longBowTestCase_SetClipBoardData(testCase, + commonSetup(v1_content_nameA_keyid1_rsasha256, + sizeof(v1_content_nameA_keyid1_rsasha256), + v1_content_nameA_keyid1_rsasha256_truthTableEntries, + V1_MANIFEST_OBJ_CONTENTOBJECT)); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(ContentObject) +{ + commonTeardown(longBowTestCase_GetClipBoardData(testCase)); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(ContentObject, Name) +{ +// TestData *data = longBowTestCase_GetClipBoardData(testCase); +// testNameGetter(data, V1_MANIFEST_OBJ_NAME, ccnxCodecSchemaV1MessageDecoder_Decode, _getName); +} + +LONGBOW_TEST_CASE(ContentObject, Payload) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + testBufferGetter(data, V1_MANIFEST_OBJ_PAYLOAD, ccnxCodecSchemaV1MessageDecoder_Decode, _getPayload); +} + +LONGBOW_TEST_CASE(ContentObject, PayloadType) +{ + // The payload type is translated from the wire format value to the CCNxPayloadType value, + // so this test cannot use the automated framework as the value in the dictionary will not + // be the same as the value in the wire format + + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + bool decodeSuccess = ccnxCodecSchemaV1MessageDecoder_Decode(data->decoder, data->dictionary); + assertTrue(decodeSuccess, "failure on ccnxCodecSchemaV1MessageDecoder_Decode"); + + CCNxPayloadType testPayloadType = (CCNxPayloadType) _getPayloadType(data->dictionary); + + // look up the true name buffer from the truth table + TlvExtent extent = getTruthTableExtent(data->truthTable, V1_MANIFEST_OBJ_PAYLOADTYPE); + + PARCBuffer + *truthbuffer = parcBuffer_Wrap(data->packet, data->packetLength, extent.offset, extent.offset + extent.length); + uint64_t truthvalue = -2; + ccnxCodecTlvUtilities_GetVarInt(truthbuffer, parcBuffer_Remaining(truthbuffer), &truthvalue); + + CCNxPayloadType truthPayloadType = -1; + bool success = + _translateWirePayloadTypeToCCNxPayloadType((CCNxCodecSchemaV1Types_PayloadType) truthvalue, &truthPayloadType); + assertTrue(success, "failure in _translateWirePayloadTypeToCCNxPayloadType for wireFormatValue %" + PRId64, truthvalue); + + parcBuffer_Release(&truthbuffer); + + assertTrue(truthPayloadType == testPayloadType, "Wrong value, got %d expected %d", testPayloadType, + truthPayloadType); +} + +LONGBOW_TEST_CASE(ContentObject, ExpiryTime) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + testInt64Getter(data, V1_MANIFEST_OBJ_EXPIRY_TIME, ccnxCodecSchemaV1MessageDecoder_Decode, _getExpiryTime); +} + +LONGBOW_TEST_CASE(ContentObject, EndChunkNumber) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + testInt64Getter(data, V1_MANIFEST_OBJ_ENDSEGMENT, ccnxCodecSchemaV1MessageDecoder_Decode, _getEndChunkNumber); +} + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(Interest) +{ + LONGBOW_RUN_TEST_CASE(Interest, Name); + LONGBOW_RUN_TEST_CASE(Interest, Payload); + LONGBOW_RUN_TEST_CASE(Interest, KeyIdRestriction); + LONGBOW_RUN_TEST_CASE(Interest, HashRestriction); +} + +LONGBOW_TEST_FIXTURE_SETUP(Interest) +{ + longBowTestCase_SetClipBoardData(testCase, + commonSetup(v1_interest_all_fields, + sizeof(v1_interest_all_fields), + TRUTHTABLENAME(v1_interest_all_fields), + V1_MANIFEST_INT_INTEREST)); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Interest) +{ + commonTeardown(longBowTestCase_GetClipBoardData(testCase)); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Interest, Name) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + testNameGetter(data, V1_MANIFEST_INT_NAME, ccnxCodecSchemaV1MessageDecoder_Decode, _getName); +} + +LONGBOW_TEST_CASE(Interest, Payload) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + testBufferGetter(data, V1_MANIFEST_INT_PAYLOAD, ccnxCodecSchemaV1MessageDecoder_Decode, _getPayload); +} + +LONGBOW_TEST_CASE(Interest, KeyIdRestriction) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + testHashGetter(data, V1_MANIFEST_INT_KEYID, ccnxCodecSchemaV1MessageDecoder_Decode, _getKeyIdRestriction); +} + +LONGBOW_TEST_CASE(Interest, HashRestriction) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + testHashGetter(data, V1_MANIFEST_INT_OBJHASH, ccnxCodecSchemaV1MessageDecoder_Decode, _getHashRestriction); +} + + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, _translateWirePayloadTypeToCCNxPayloadType); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, _translateWirePayloadTypeToCCNxPayloadType) +{ + uint32_t sentinel = 0xFFFF; + + struct { + CCNxCodecSchemaV1Types_PayloadType wire; + CCNxPayloadType payloadType; + bool success; + } vectors[] = { + { .wire = CCNxCodecSchemaV1Types_PayloadType_Data, .payloadType = CCNxPayloadType_DATA, .success = true }, + { .wire = CCNxCodecSchemaV1Types_PayloadType_Key, .payloadType = CCNxPayloadType_KEY, .success = true }, + { .wire = CCNxCodecSchemaV1Types_PayloadType_Link, .payloadType = CCNxPayloadType_LINK, .success = true }, + { .wire = -2, .payloadType = -2, .success = false }, + { .wire = sentinel, .payloadType = sentinel } + }; + + for (int i = 0; vectors[i].wire != sentinel; i++) { + CCNxPayloadType payloadType = -1; + bool success = _translateWirePayloadTypeToCCNxPayloadType(vectors[i].wire, &payloadType); + assertTrue(success == vectors[i].success, "Incorrect return index %d, expected %d got %d", i, + vectors[i].success, success); + + if (success) { + assertTrue(payloadType == vectors[i].payloadType, "Wrong payloadType index %d, expected %d got %d", i, + vectors[i].payloadType, payloadType); + } + } +} + +// ========================================================================= + + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_MessageDecoder); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageEncoder.c new file mode 100644 index 00000000..49452626 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_MessageEncoder.c @@ -0,0 +1,644 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_MessageEncoder.c" +#include +#include +#include +#include +#include + +#include "testrig_encoder.c" + +#include +#include + +#include + +// ========================================================================= + +LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_MessageEncoder) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); + LONGBOW_RUN_TEST_FIXTURE(UnknownType); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_MessageEncoder) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_MessageEncoder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(ContentObject, Interest); + LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject); + LONGBOW_RUN_TEST_CASE(ContentObject, ContentObjectNameless); + LONGBOW_RUN_TEST_CASE(InterestReturn, InterestReturn); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(ContentObject, Interest) +{ + // create an Interest that replicates v1_interest_all_fields + TlvExtent keyidExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_KEYID); + TlvExtent hashExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_OBJHASH); + TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_PAYLOAD); + TlvExtent interestExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_INTEREST); + + CCNxName *name = ccnxName_CreateFromCString("lci:/3=cool"); + uint32_t lifetime = CCNxInterestDefault_LifetimeMilliseconds; + uint32_t hoplimit = CCNxInterestDefault_HopLimit; + + printf("%d %d\n", keyidExtent.offset + 4, keyidExtent.offset + keyidExtent.length - 4); + PARCBuffer *keyid = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), keyidExtent.offset + 4, keyidExtent.offset + keyidExtent.length); + PARCBuffer *hash = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), hashExtent.offset + 4, hashExtent.offset + hashExtent.length); + PARCBuffer *payload = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), payloadExtent.offset, payloadExtent.offset + payloadExtent.length); + + CCNxTlvDictionary *interest = + ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation, + name, lifetime, keyid, hash, hoplimit); + + ccnxInterest_SetPayloadAndId(interest, payload); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecSchemaV1MessageEncoder_Encode(encoder, interest); + + PARCBuffer *truth = parcBuffer_Wrap(v1_interest_all_fields, + sizeof(v1_interest_all_fields), + interestExtent.offset, + interestExtent.offset + interestExtent.length); + + testCompareEncoderToBuffer(encoder, truth); + + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&truth); + parcBuffer_Release(&payload); + parcBuffer_Release(&hash); + parcBuffer_Release(&keyid); + ccnxName_Release(&name); + ccnxTlvDictionary_Release(&interest); +} + +LONGBOW_TEST_CASE(InterestReturn, InterestReturn) +{ + // create an Interest that replicates v1_interest_all_fields + TlvExtent keyidExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_KEYID); + TlvExtent hashExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_OBJHASH); + TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_PAYLOAD); + TlvExtent interestExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_INTEREST); + + CCNxName *name = ccnxName_CreateFromCString("lci:/3=cool"); + uint32_t lifetime = CCNxInterestDefault_LifetimeMilliseconds; + uint32_t hoplimit = CCNxInterestDefault_HopLimit; + + PARCBuffer *keyid = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), keyidExtent.offset + 4, keyidExtent.offset + keyidExtent.length); + PARCBuffer *hash = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), hashExtent.offset + 4, hashExtent.offset + hashExtent.length); + PARCBuffer *payload = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), payloadExtent.offset, payloadExtent.offset + payloadExtent.length); + + CCNxTlvDictionary *interest = + ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation, + name, lifetime, keyid, hash, hoplimit); + parcBuffer_Release(&hash); + parcBuffer_Release(&keyid); + ccnxName_Release(&name); + + ccnxInterest_SetPayloadAndId(interest, payload); + parcBuffer_Release(&payload); + + CCNxInterestReturn *interestReturn = + ccnxInterestReturn_Create(interest, CCNxInterestReturn_ReturnCode_HopLimitExceeded); + ccnxTlvDictionary_Release(&interest); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecSchemaV1MessageEncoder_Encode(encoder, interestReturn); + + size_t packetSize = sizeof(v1_interest_all_fields); + uint8_t *testPacket = (uint8_t *) parcSafeMemory_Allocate(packetSize); + memcpy(testPacket, v1_interest_all_fields, packetSize); + testPacket[1] = 0x02; //InterestReturn + testPacket[5] = CCNxInterestReturn_ReturnCode_HopLimitExceeded; + + PARCBuffer *truth = parcBuffer_Wrap(testPacket, packetSize, + interestExtent.offset, + interestExtent.offset + interestExtent.length); + + testCompareEncoderToBuffer(encoder, truth); + + parcSafeMemory_Deallocate((void **) &testPacket); + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&truth); + ccnxInterestReturn_Release(&interestReturn); +} + +LONGBOW_TEST_CASE(ContentObject, ContentObjectNameless) +{ + // create a Content Object that replicates v1_content_nameA_keyid1_rsasha256 + TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameless_nosig), V1_MANIFEST_OBJ_PAYLOAD); + TlvExtent contentObjectExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameless_nosig), V1_MANIFEST_OBJ_CONTENTOBJECT); + + PARCBuffer *payload = parcBuffer_Wrap(v1_content_nameless_nosig, sizeof(v1_content_nameless_nosig), payloadExtent.offset, payloadExtent.offset + payloadExtent.length); + + CCNxTlvDictionary *contentobject = + ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation, + NULL, CCNxPayloadType_KEY, payload); + + ccnxContentObject_SetExpiryTime(contentobject, 0x01434B198400ULL); + ccnxContentObject_SetFinalChunkNumber(contentobject, 0x06050403); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecSchemaV1MessageEncoder_Encode(encoder, contentobject); + + PARCBuffer *truth = parcBuffer_Wrap(v1_content_nameless_nosig, sizeof(v1_content_nameless_nosig), contentObjectExtent.offset, contentObjectExtent.offset + contentObjectExtent.length); + + testCompareEncoderToBuffer(encoder, truth); + + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&truth); + parcBuffer_Release(&payload); + ccnxTlvDictionary_Release(&contentobject); +} + +LONGBOW_TEST_CASE(ContentObject, ContentObject) +{ + // create a Content Object that replicates v1_content_nameA_keyid1_rsasha256 + TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_PAYLOAD); + TlvExtent contentObjectExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_CONTENTOBJECT); + + CCNxName *name = ccnxName_CreateFromCString("lci:/3=hello/0xf000=ouch"); + + PARCBuffer *payload = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), payloadExtent.offset, payloadExtent.offset + payloadExtent.length); + + CCNxTlvDictionary *contentobject = + ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation, + name, CCNxPayloadType_KEY, payload); + + ccnxContentObject_SetExpiryTime(contentobject, 0x01434B198400ULL); + ccnxContentObject_SetFinalChunkNumber(contentobject, 0x06050403); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecSchemaV1MessageEncoder_Encode(encoder, contentobject); + + PARCBuffer *truth = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), contentObjectExtent.offset, contentObjectExtent.offset + contentObjectExtent.length); + + testCompareEncoderToBuffer(encoder, truth); + + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&truth); + parcBuffer_Release(&payload); + ccnxName_Release(&name); + ccnxTlvDictionary_Release(&contentobject); +} + + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(Interest) +{ + LONGBOW_RUN_TEST_CASE(Interest, ccnxCodecSchemaV1MessageEncoder_Encode); +} + +LONGBOW_TEST_FIXTURE_SETUP(Interest) +{ + longBowTestCase_SetClipBoardData(testCase, + commonSetup(v1_interest_all_fields, + sizeof(v1_interest_all_fields), + TRUTHTABLENAME(v1_interest_all_fields), + V1_MANIFEST_INT_INTEREST)); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Interest) +{ + testrigencoder_CommonTeardown(longBowTestCase_GetClipBoardData(testCase)); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Interest, ccnxCodecSchemaV1MessageEncoder_Encode) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1MessageEncoder_Encode(data->encoder, data->dictionary); + + testCompareEncoderToBuffer(data->encoder, data->memoryRegion); +} + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(InterestReturn) +{ + LONGBOW_RUN_TEST_CASE(InterestReturn, ccnxCodecSchemaV1MessageEncoder_Encode); +} + +LONGBOW_TEST_FIXTURE_SETUP(InterestReturn) +{ + size_t packetSize = sizeof(v1_interest_all_fields); + uint8_t *testPacket = (uint8_t *) parcSafeMemory_Allocate(packetSize); + memcpy(testPacket, v1_interest_all_fields, packetSize); + testPacket[1] = 0x02; //InterestReturn + testPacket[5] = CCNxInterestReturn_ReturnCode_HopLimitExceeded; + + longBowTestCase_SetClipBoardData(testCase, + commonSetup(v1_interest_all_fields, + sizeof(v1_interest_all_fields), + TRUTHTABLENAME(v1_interest_all_fields), + V1_MANIFEST_INT_INTEREST)); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(InterestReturn) +{ + testrigencoder_CommonTeardown(longBowTestCase_GetClipBoardData(testCase)); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(InterestReturn, ccnxCodecSchemaV1MessageEncoder_Encode) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1MessageEncoder_Encode(data->encoder, data->dictionary); + + testCompareEncoderToBuffer(data->encoder, data->memoryRegion); +} + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, _encodeName); + LONGBOW_RUN_TEST_CASE(Local, _encodePayload); + LONGBOW_RUN_TEST_CASE(Local, _encodePayloadType); + LONGBOW_RUN_TEST_CASE(Local, _encodeExpiryTime); + LONGBOW_RUN_TEST_CASE(Local, _encodeEndChunkNumber); + LONGBOW_RUN_TEST_CASE(Local, _encodeKeyIdRestriction); + LONGBOW_RUN_TEST_CASE(Local, _encodeContentObjectHashRestriction); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +#include +#include + +LONGBOW_TEST_CASE(Local, _encodeName) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/0xf001=foot/0xf002=toe/0xf003=nail"); + uint8_t encoded[] = { + 0x00, 0x00, 0x00, 23, + 0xF0, 0x01, 0x00, 4, + 'f', 'o', 'o', 't', + 0xF0, 0x02, 0x00, 3, + 't', 'o', 'e', + 0xF0, 0x03, 0x00, 4, + 'n', 'a', 'i', 'l' + }; + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + + ccnxTlvDictionary_PutName(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME, name); + + _encodeName(encoder, dictionary); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + assertTrue(parcBuffer_Equals(truth, test), "buffers do not match") + { + printf("Expected:\n"); + parcBuffer_Display(truth, 3); + printf("Got:\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxName_Release(&name); + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Local, _encodePayload) +{ + uint8_t payload[] = { 0xf1, 0xf2, 0xf3 }; + uint8_t encoded[] = { + 0x00, 0x01, 0x00, 3, + 0xf1, 0xf2, 0xf3 + }; + + PARCBuffer *buffer = parcBuffer_Wrap(payload, sizeof(payload), 0, sizeof(payload)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + + ccnxTlvDictionary_PutBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD, buffer); + + _encodePayload(encoder, dictionary); + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(truth, test), "buffers do not match") + { + printf("Expected:\n"); + parcBuffer_Display(truth, 3); + printf("Got:\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + parcBuffer_Release(&buffer); + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Local, _encodePayloadType) +{ + CCNxPayloadType type = CCNxPayloadType_LINK; + + uint8_t encoded[] = { + 0x00, 0x05, 0x00, 1, + CCNxCodecSchemaV1Types_PayloadType_Link + }; + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + + ccnxTlvDictionary_PutInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE, type); + + _encodePayloadType(encoder, dictionary); + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(truth, test), "buffers do not match") + { + printf("Expected:\n"); + parcBuffer_Display(truth, 3); + printf("Got:\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Local, _encodeExpiryTime) +{ + uint64_t expiry = 0x123456789ABCDEF0ULL; + uint8_t encoded[] = { + 0x00, 0x06, 0x00, 8, + 0x12, 0x34, 0x56, 0x78, + 0x9A, 0xBC, 0xDE, 0xF0 + }; + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + + ccnxTlvDictionary_PutInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME, expiry); + + _encodeExpiryTime(encoder, dictionary); + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(truth, test), "buffers do not match") + { + printf("Expected:\n"); + parcBuffer_Display(truth, 3); + printf("Got:\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Local, _encodeEndChunkNumber) +{ + uint64_t endChunkNumber = 0x818283ULL; + uint8_t encoded[] = { + 0x00, 0x19, 0x00, 3, + 0x81, 0x82, 0x83 + }; + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + + ccnxTlvDictionary_PutInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT, endChunkNumber); + + _encodeEndChunkNumber(encoder, dictionary); + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(truth, test), "buffers do not match") + { + printf("Expected:\n"); + parcBuffer_Display(truth, 3); + printf("Got:\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Local, _encodeKeyIdRestriction) +{ + uint8_t encoded[] = { + 0x00, 0x02, 0x00, 0x24, + 0x00, 0x01, 0x00, 0x20, + 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0, + 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0, + 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0, + 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0, + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 8, sizeof(encoded)); + PARCCryptoHash *hash = parcCryptoHash_Create(PARCCryptoHashType_SHA256, buffer); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + + ccnxTlvDictionary_PutObject(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_KEYID_RESTRICTION, hash); + + _encodeKeyIdRestriction(encoder, dictionary); + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(truth, test), "buffers do not match") + { + printf("Expected:\n"); + parcBuffer_Display(truth, 3); + printf("Got:\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + parcBuffer_Release(&buffer); + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&dictionary); + parcCryptoHash_Release(&hash); +} + +LONGBOW_TEST_CASE(Local, _encodeContentObjectHashRestriction) +{ + uint8_t encoded[] = { + 0x00, 0x03, 0x00, 0x24, + 0x00, 0x01, 0x00, 0x20, + 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0, + 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0, + 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0, + 0x12, 0x34, 0x56, 0x78,0x9A, 0xBC, 0xDE, 0xF0, + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 8, sizeof(encoded)); + PARCCryptoHash *hash = parcCryptoHash_Create(PARCCryptoHashType_SHA256, buffer); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + + ccnxTlvDictionary_PutObject(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION, hash); + + _encodeContentObjectHashRestriction(encoder, dictionary); + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(truth, test), "buffers do not match") + { + printf("Expected:\n"); + parcBuffer_Display(truth, 3); + printf("Got:\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + parcBuffer_Release(&buffer); + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&dictionary); + parcCryptoHash_Release(&hash); +} + + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(UnknownType) +{ + LONGBOW_RUN_TEST_CASE(UnknownType, Unknown); +} + +LONGBOW_TEST_FIXTURE_SETUP(UnknownType) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(UnknownType) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(UnknownType, Unknown) +{ + CCNxTlvDictionary *unknown = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, 1); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ssize_t length = ccnxCodecSchemaV1MessageEncoder_Encode(encoder, unknown); + assertTrue(length < 0, "Did not get error return when encoding unknown type"); + + CCNxCodecError *error = ccnxCodecTlvEncoder_GetError(encoder); + assertNotNull(error, "encoder did not set the error"); + + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&unknown); +} + +// ================================================================================== + + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_MessageEncoder); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameCodec.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameCodec.c new file mode 100755 index 00000000..8a33a0e2 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameCodec.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_NameCodec.c" +#include +#include + +LONGBOW_TEST_RUNNER(ccnxTlvCodec_Name) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxTlvCodec_Name) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxTlvCodec_Name) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecName_Decode_RightType); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecName_Decode_WrongType); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecName_Encode); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) { + printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding()); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecName_Decode_RightType) +{ + PARCBuffer *buffer = parcBuffer_WrapCString("brandywine"); + CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buffer); + CCNxName *truth = ccnxName_Append(ccnxName_Create(), segment); + ccnxNameSegment_Release(&segment); + parcBuffer_Release(&buffer); + + 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, 0x1020); + + assertTrue(ccnxName_Equals(truth, test), "Name segments do not match"); + + ccnxName_Release(&test); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&decodeBuffer); + ccnxName_Release(&truth); +} + +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); +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecName_Encode) +{ + uint8_t truthBytes[] = { 0x10, 0x20, 0x00, 0x0E, 0x00, CCNxNameLabelType_NAME, 0x00, 0x0A, 'b', 'r', 'a', 'n', 'd', 'y', 'w', 'i', 'n', 'e' }; + PARCBuffer *truth = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecTlvEncoder_Initialize(encoder); + + PARCBuffer *buffer = parcBuffer_WrapCString("brandywine"); + CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buffer); + + CCNxName *name = ccnxName_Append(ccnxName_Create(), segment); + ccnxNameSegment_Release(&segment); + parcBuffer_Release(&buffer); + + ccnxCodecSchemaV1NameCodec_Encode(encoder, 0x1020, name); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + + if (!parcBuffer_Equals(truth, test)) { + printf("Buffers do not match\n"); + printf("Excpected:\n"); + parcBuffer_Display(truth, 3); + printf("Got:\n"); + parcBuffer_Display(test, 3); + assertTrue(parcBuffer_Equals(truth, test), "Buffers do not match"); + } + + ccnxName_Release(&name); + parcBuffer_Release(&test); + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&truth); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxTlvCodec_Name); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameSegmentCodec.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameSegmentCodec.c new file mode 100755 index 00000000..77800055 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_NameSegmentCodec.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_NameSegmentCodec.c" +#include +#include + +#include + +LONGBOW_TEST_RUNNER(ccnxTlvCodec_Name) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxTlvCodec_Name) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxTlvCodec_Name) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecNameSegment_Decode); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecNameSegment_Decode_TLShort); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecNameSegment_Decode_VShort); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecNameSegment_Decode); + LONGBOW_RUN_TEST_CASE(Global, ccnxTlvCodecNameSegment_Encode); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) { + printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding()); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecNameSegment_Decode) +{ + PARCBuffer *buffer = parcBuffer_WrapCString("brandywine"); + CCNxNameSegment *truth = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buffer); + parcBuffer_Release(&buffer); + + uint8_t decodeBytes[] = { 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); + CCNxNameSegment *test = ccnxCodecSchemaV1NameSegmentCodec_Decode(decoder); + + assertTrue(ccnxNameSegment_Equals(truth, test), "Name segments do not match"); + + ccnxNameSegment_Release(&test); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&decodeBuffer); + ccnxNameSegment_Release(&truth); +} + +/** + * In this case, there are not enough bytes in the buffer to decode the T and L + */ +LONGBOW_TEST_CASE(Global, ccnxTlvCodecNameSegment_Decode_TLShort) +{ + uint8_t decodeBytes[] = { 0x00, CCNxNameLabelType_NAME, 0x00, 0x0A, 'b', 'r', 'a' }; + PARCBuffer *decodeBuffer = parcBuffer_Wrap(decodeBytes, sizeof(decodeBytes), 0, sizeof(decodeBytes)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(decodeBuffer); + CCNxNameSegment *test = ccnxCodecSchemaV1NameSegmentCodec_Decode(decoder); + + assertNull(test, "Name segments should have been null because there are not enough bytes in buffer"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&decodeBuffer); +} + +/** + * In this case, we decode the T and L, but there are not enough bytes for the V + */ +LONGBOW_TEST_CASE(Global, ccnxTlvCodecNameSegment_Decode_VShort) +{ + uint8_t decodeBytes[] = { 0x00, CCNxNameLabelType_NAME, 0x00 }; + PARCBuffer *decodeBuffer = parcBuffer_Wrap(decodeBytes, sizeof(decodeBytes), 0, sizeof(decodeBytes)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(decodeBuffer); + CCNxNameSegment *test = ccnxCodecSchemaV1NameSegmentCodec_Decode(decoder); + + assertNull(test, "Name segments should have been null because there are not enough bytes in buffer"); + + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&decodeBuffer); +} + + +LONGBOW_TEST_CASE(Global, ccnxTlvCodecNameSegment_Encode) +{ + uint8_t truthBytes[] = { 0x00, CCNxNameLabelType_NAME, 0x00, 0x0A, 'b', 'r', 'a', 'n', 'd', 'y', 'w', 'i', 'n', 'e' }; + PARCBuffer *truth = parcBuffer_Wrap(truthBytes, sizeof(truthBytes), 0, sizeof(truthBytes)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecTlvEncoder_Initialize(encoder); + + PARCBuffer *buffer = parcBuffer_WrapCString("brandywine"); + CCNxNameSegment *segment = ccnxNameSegment_CreateTypeValue(CCNxNameLabelType_NAME, buffer); + parcBuffer_Release(&buffer); + + ccnxCodecSchemaV1NameSegmentCodec_Encode(encoder, segment); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(truth, test), "Buffers do not match"); + + parcBuffer_Release(&test); + ccnxNameSegment_Release(&segment); + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&truth); +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxTlvCodec_Name); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersDecoder.c new file mode 100644 index 00000000..abe47608 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersDecoder.c @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_OptionalHeadersDecoder.c" +#include + +#include + +#include + +typedef struct test_data { + PARCBuffer *optionalHeader; + CCNxCodecTlvDecoder *decoder; + CCNxTlvDictionary *dictionary; + + // truth table + PARCBuffer *interestLifetime; + PARCBuffer *cacheTime; + PARCBuffer *interestFrag; + PARCBuffer *objectFrag; + PARCBuffer *customHeader; + + // the key for the customHeader + uint16_t customHeaderType; +} TestData; + +/** + * A packet with all the defined optional headers plus one custom header + * This is not actually a packet one would see in real life as it has + * headers from both an Interest and a Content Object + */ +static uint8_t packet_with_headers[] = { + 0x01, 0x01, 0x00, 120, // ver = 1, type = interest, length = 120 + 0x01, 0x00, 0x00, 88, // hopLimit = 1, reserved = 0, header length = 88 + // ------------------------ + // byte 8 + 0x00, 0x01, 0x00, 0x08, // Interest Lifetime (type 1) + 0x20, 0x30, 0x40, 0x50, // 0x2030405060708090 + 0x60, 0x70, 0x80, 0x90, + // ------------------------ + // byte 20 + 0x00, 0x02, 0x00, 0x08, // Recommended Cache Time (type 2) + 0x21, 0x31, 0x41, 0x51, // 0x2030405060708090 + 0x61, 0x71, 0x81, 0x91, + // ------------------------ + // byte 32 + 0x00, 0x03, 0x00, 0x0C, // Interest Fragment (type 3) + 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, // fragment 0x0102030405060708 + 0x05, 0xDC, 0x04, 0x00, // MTU 1500, fragcnt 4, fragnum 0 + // ------------------------ + // byte 48 + 0x00, 0x04, 0x00, 20, // ContentObject Fragment (type 4) + 0xC1, 0xC2, 0xC3, 0xC4, + 0xC5, 0xC6, 0xC7, 0xC8, // fragment 0xC1C2C3C4C5C6C7C8 + 0x05, 0xDC, 0x04, 0x00, // MTU 1500, fragcnt 4, fragnum 0 + 0xD1, 0xD2, 0xD3, 0xD4, + 0xD5, 0xD6, 0xD7, 0xD8, // fragment 0xD1D2D3D4D5D6D7D8 + // ------------------------ + // byte 72 + 0x01, 0x00, 0x00, 12, // Custom header (type 256), length 12 + 0xA0, 0xA1, 0xA2, 0xA3, + 0xA4, 0xA5, 0xA6, 0xA7, + 0xA8, 0xA9, 0xAA, 0xAB, + // ------------------------ + // byte 88 + 0x00, 0x01, 0x00, 29, // type = interest, length = 29 + // ------------------------ + 0x00, 0x00, 0x00, 0x10, // type = name, length = 16 + 0x00, 0x02, 0x00, 0x04, // type = binary, length = 5 + 'h', 'e', 'l', 'l', // "hello" + 0xF0, 0x00, 0x00, 0x04, // type = app, length = 4 + 'o', 'u', 'c', 'h', // "ouch" + // ------------------------ + 0x00, 0x01, 0x00, 0x04, // type = keyid, length = 4 + 0xA0, 0xB0, 0xC0, 0xD0, // 0xA0B0C0D0 + // ------------------------ + // byte 120 +}; + +static TestData * +_commonSetup(void) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + + // setup the decoder and decode the optional headers + data->optionalHeader = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 8, 88); + data->decoder = ccnxCodecTlvDecoder_Create(data->optionalHeader); + data->dictionary = ccnxTlvDictionary_Create(10, 5); + + // setup the truth values + data->interestLifetime = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 12, 20); + data->cacheTime = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 24, 32); + + data->interestFrag = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 36, 48); + data->objectFrag = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 52, 72); + + data->customHeader = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 76, 88); + data->customHeaderType = 0x0100; + + return data; +} + +static void +_commonTeardown(TestData *data) +{ + ccnxTlvDictionary_Release(&data->dictionary); + ccnxCodecTlvDecoder_Destroy(&data->decoder); + parcBuffer_Release(&data->optionalHeader); + + parcBuffer_Release(&data->interestLifetime); + parcBuffer_Release(&data->cacheTime); + parcBuffer_Release(&data->interestFrag); + parcBuffer_Release(&data->objectFrag); + parcBuffer_Release(&data->customHeader); + + parcMemory_Deallocate((void **) &data); +} + +LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_OptionalHeadersDecoder) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_OptionalHeadersDecoder) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_OptionalHeadersDecoder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_Decode_TooLong); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomHeader); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader_Missing); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader_Missing); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader_Missing); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader_Missing); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomHeader_Missing); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + longBowTestCase_SetClipBoardData(testCase, _commonSetup()); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + _commonTeardown(longBowTestCase_GetClipBoardData(testCase)); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +/** + * One of the TLVs will extend beyond the end of the buffer. Should fail. + */ +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_Decode_TooLong) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + // Make one of the fields 255 bytes + uint8_t original = packet_with_headers[10]; + packet_with_headers[10] = 0xFF; + bool success = ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary); + + // now set it back + packet_with_headers[10] = original; + + assertFalse(success, "Should have failed to parse when a TLV exceeds bounary"); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary); + PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader(data->dictionary); + assertTrue(parcBuffer_Equals(test, data->objectFrag), "Wrong value") + { + printf("Expected: \n"); + parcBuffer_Display(data->objectFrag, 3); + printf("Got:\n"); + parcBuffer_Display(test, 3); + } +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary); + PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader(data->dictionary); + assertTrue(parcBuffer_Equals(test, data->interestFrag), "Wrong value") + { + printf("Expected: \n"); + parcBuffer_Display(data->interestFrag, 3); + printf("Got:\n"); + parcBuffer_Display(test, 3); + } +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary); + uint64_t lifetime = ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader(data->dictionary); + + uint64_t trueLifetime = 0; + ccnxCodecTlvUtilities_GetVarInt(data->interestLifetime, parcBuffer_Remaining(data->interestLifetime), &trueLifetime); + + assertTrue(trueLifetime == lifetime, "wrong value, expected %" PRIx64 " got %" PRIx64, trueLifetime, lifetime); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary); + uint64_t cachetime = ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader(data->dictionary); + + uint64_t trueCachetime = 0; + ccnxCodecTlvUtilities_GetVarInt(data->cacheTime, parcBuffer_Remaining(data->cacheTime), &trueCachetime); + + assertTrue(trueCachetime == cachetime, "wrong value, expected %" PRIx64 " got %" PRIx64, trueCachetime, cachetime); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomHeader) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary); + PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomType(data->dictionary, data->customHeaderType); + assertTrue(parcBuffer_Equals(test, data->customHeader), "Wrong value for header type %02X", data->customHeaderType) + { + printf("Expected: \n"); + parcBuffer_Display(data->customHeader, 3); + printf("Got:\n"); + parcBuffer_Display(test, 3); + } +} + +// ======== +// test for missing values + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader_Missing) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader(data->dictionary); + assertNull(test, "Did not get null buffer for missing field, got %p", (void *) test); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader_Missing) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader(data->dictionary); + assertNull(test, "Did not get null buffer for missing field, got %p", (void *) test); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader_Missing) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + bool exists = ccnxTlvDictionary_IsValueInteger(data->dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime); + assertFalse(exists, "Dictionary reports it has a missing field"); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader_Missing) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + bool exists = ccnxTlvDictionary_IsValueInteger(data->dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime); + assertFalse(exists, "Dictionary reports it has a missing field"); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomHeader_Missing) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomType(data->dictionary, data->customHeaderType); + assertNull(test, "Did not get null buffer for missing field, got %p", (void *) test); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_OptionalHeadersDecoder); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersEncoder.c new file mode 100644 index 00000000..1950eef2 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersEncoder.c @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_OptionalHeadersEncoder.c" +#include +#include + +#include +#include + +#include "testrig_encoder.c" + +static TruthTableEntry +TRUTHTABLENAME(interest_optional_headers)[] = +{ + { .wellKnownType = false, .indexOrKey = V1_MANIFEST_INT_OPTHEAD, .bodyManifest = true, .extent = { 8, 28 } }, // index = 0 + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_E2EFRAG, .bodyManifest = false, .extent = { 12, 12 } }, // index = 1 + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_LIFETIME, .bodyManifest = false, .extent = { 28, 8 } }, // index = 2 + { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } }, +}; + +static TruthTableEntry +TRUTHTABLENAME(contentobject_optional_headers)[] = +{ + { .wellKnownType = false, .indexOrKey = V1_MANIFEST_OBJ_OPTHEAD, .bodyManifest = true, .extent = { 8, 36 } }, // 0 + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_E2EFRAG, .bodyManifest = false, .extent = { 12, 20 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_RecommendedCacheTime, .bodyManifest = false, .extent = { 36, 8 } }, + { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } }, +}; + + +LONGBOW_TEST_RUNNER(ccnxCodecSchemaV0_OptionalHeadersEncoder) +{ + LONGBOW_RUN_TEST_FIXTURE(Interest); + LONGBOW_RUN_TEST_FIXTURE(ContentObject); + LONGBOW_RUN_TEST_FIXTURE(UnknownType); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV0_OptionalHeadersEncoder) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV0_OptionalHeadersEncoder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ================================================================================== + +LONGBOW_TEST_FIXTURE(Interest) +{ + LONGBOW_RUN_TEST_CASE(Interest, ccnxCodecSchemaV1OptionalHeadersEncoder_Encode); +} + +LONGBOW_TEST_FIXTURE_SETUP(Interest) +{ + longBowTestCase_SetClipBoardData(testCase, + commonSetup(v1_interest_nameA, + sizeof(v1_interest_nameA), + TRUTHTABLENAME(interest_optional_headers), + V1_MANIFEST_INT_OPTHEAD)); + + // commonSetup will not add headers... + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + addBuffer(data, data->dictionary, TRUTHTABLENAME(interest_optional_headers)[1].extent.offset, TRUTHTABLENAME(interest_optional_headers)[1].extent.offset + TRUTHTABLENAME(interest_optional_headers)[1].extent.length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG); + + addBuffer(data, data->dictionary, TRUTHTABLENAME(interest_optional_headers)[2].extent.offset, TRUTHTABLENAME(interest_optional_headers)[2].extent.offset + TRUTHTABLENAME(interest_optional_headers)[2].extent.length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Interest) +{ + testrigencoder_CommonTeardown(longBowTestCase_GetClipBoardData(testCase)); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Interest, ccnxCodecSchemaV1OptionalHeadersEncoder_Encode) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ssize_t length = ccnxCodecSchemaV1OptionalHeadersEncoder_Encode(data->encoder, data->dictionary); + assertTrue(length >= 0, "Error on Encode: length %zd", length); + testCompareEncoderToBuffer(data->encoder, data->memoryRegion); +} + +// ================================================================================== + +LONGBOW_TEST_FIXTURE(ContentObject) +{ + LONGBOW_RUN_TEST_CASE(ContentObject, ccnxCodecSchemaV1OptionalHeadersEncoder_Encode); +} + +LONGBOW_TEST_FIXTURE_SETUP(ContentObject) +{ + longBowTestCase_SetClipBoardData(testCase, + commonSetup(v1_content_nameA_crc32c, + sizeof(v1_content_nameA_crc32c), + TRUTHTABLENAME(contentobject_optional_headers), + V1_MANIFEST_OBJ_OPTHEAD)); + + // commonSetup will not add headers... + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + addBuffer(data, data->dictionary, TRUTHTABLENAME(contentobject_optional_headers)[1].extent.offset, TRUTHTABLENAME(contentobject_optional_headers)[1].extent.offset + TRUTHTABLENAME(contentobject_optional_headers)[1].extent.length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_OBJFRAG); + + addBuffer(data, data->dictionary, TRUTHTABLENAME(contentobject_optional_headers)[2].extent.offset, TRUTHTABLENAME(contentobject_optional_headers)[2].extent.offset + TRUTHTABLENAME(contentobject_optional_headers)[2].extent.length, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime); + + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(ContentObject) +{ + testrigencoder_CommonTeardown(longBowTestCase_GetClipBoardData(testCase)); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(ContentObject, ccnxCodecSchemaV1OptionalHeadersEncoder_Encode) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ssize_t length = ccnxCodecSchemaV1OptionalHeadersEncoder_Encode(data->encoder, data->dictionary); + assertTrue(length >= 0, "Error on Encode: length %zd", length); + testCompareEncoderToBuffer(data->encoder, data->memoryRegion); +} + +// ================================================================================== + +LONGBOW_TEST_FIXTURE(UnknownType) +{ + LONGBOW_RUN_TEST_CASE(UnknownType, Unknown); +} + +LONGBOW_TEST_FIXTURE_SETUP(UnknownType) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(UnknownType) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(UnknownType, Unknown) +{ + CCNxTlvDictionary *unknown = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, 1); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ssize_t length = ccnxCodecSchemaV1OptionalHeadersEncoder_Encode(encoder, unknown); + assertTrue(length < 0, "Did not get error return when encoding unknown type"); + + CCNxCodecError *error = ccnxCodecTlvEncoder_GetError(encoder); + assertNotNull(error, "encoder did not set the error"); + + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&unknown); +} + +// ================================================================================== + + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV0_OptionalHeadersEncoder); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketDecoder.c new file mode 100755 index 00000000..42d5be41 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketDecoder.c @@ -0,0 +1,684 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Decode whole packets then spot-check that fields from each section appear. We don't need + * to exhastively test here, as the individual decoders are exhaustively tested. + * + */ +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_PacketDecoder.c" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "testrig_packetwrapper.c" + +#include +#include + +// ========================================================================= + +LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_PacketDecoder) +{ + LONGBOW_RUN_TEST_FIXTURE(ContentObject); + LONGBOW_RUN_TEST_FIXTURE(Control); + LONGBOW_RUN_TEST_FIXTURE(Interest); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_PacketDecoder) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_PacketDecoder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(ContentObject) +{ + LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject_RsaSha256_FixedHeader); + LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject_RsaSha256_Name); + LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject_RsaSha256_ExpiryTime); + LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject_RsaSha256_ValidationAlg_KeyId); + LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject_RsaSha256_ValidationPayload); + LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject_zero_payload); + LONGBOW_RUN_TEST_CASE(ContentObject, ContentObject_no_payload); +} + +LONGBOW_TEST_FIXTURE_SETUP(ContentObject) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(ContentObject) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(ContentObject, ContentObject_RsaSha256_FixedHeader) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), 0, sizeof(v1_content_nameA_keyid1_rsasha256)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader); + + // leave the FixedHeader buffer at position 0 + parcBuffer_Rewind(fixedHeader); + + PARCBuffer *trueFixedHeader = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, 8, 0, 8); + assertTrue(parcBuffer_Equals(fixedHeader, trueFixedHeader), "Buffers not equal") + { + printf("Expected\n"); + parcBuffer_Display(trueFixedHeader, 3); + printf("Got\n"); + parcBuffer_Display(fixedHeader, 3); + } + + parcBuffer_Release(&trueFixedHeader); + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(ContentObject, ContentObject_RsaSha256_Name) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, + sizeof(v1_content_nameA_keyid1_rsasha256), + 0, + sizeof(v1_content_nameA_keyid1_rsasha256)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + CCNxName *name = ccnxTlvDictionary_GetName(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME); + CCNxName *trueName = ccnxName_CreateFromCString(v1_content_nameA_keyid1_rsasha256_URI); + + assertTrue(ccnxName_Equals(name, trueName), "Buffers not equal") + { + printf("Expected\n"); + ccnxName_Display(trueName, 3); + printf("Got\n"); + ccnxName_Display(name, 3); + } + + ccnxName_Release(&trueName); + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(ContentObject, ContentObject_RsaSha256_ExpiryTime) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), 0, sizeof(v1_content_nameA_keyid1_rsasha256)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + uint64_t expiryTime = ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_EXPIRY_TIME); + + TlvExtent expiryExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_EXPIRY_TIME); + + parcBuffer_SetPosition(packetBuffer, expiryExtent.offset); + uint64_t trueTime; + ccnxCodecTlvUtilities_GetVarInt(packetBuffer, expiryExtent.length, &trueTime); + + assertTrue(expiryTime == trueTime, "Wrong time, expected %" PRIx64 " got %" PRIx64, trueTime, expiryTime); + + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(ContentObject, ContentObject_RsaSha256_ValidationAlg_KeyId) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), 0, sizeof(v1_content_nameA_keyid1_rsasha256)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCBuffer *keyid = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID); + + TlvExtent keyidExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_KEYID); + PARCBuffer *trueKeyid = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), keyidExtent.offset, keyidExtent.offset + keyidExtent.length); + + assertTrue(parcBuffer_Equals(keyid, trueKeyid), "Buffers not equal") + { + printf("Expected\n"); + parcBuffer_Display(trueKeyid, 3); + printf("Got\n"); + parcBuffer_Display(keyid, 3); + } + + parcBuffer_Release(&trueKeyid); + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(ContentObject, ContentObject_RsaSha256_ValidationPayload) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), 0, sizeof(v1_content_nameA_keyid1_rsasha256)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCBuffer *validationPayload = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD); + + TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_SIGBITS); + PARCBuffer *truePayload = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), payloadExtent.offset, payloadExtent.offset + payloadExtent.length); + + assertTrue(parcBuffer_Equals(validationPayload, truePayload), "Buffers not equal") + { + printf("Expected\n"); + parcBuffer_Display(truePayload, 3); + printf("Got\n"); + parcBuffer_Display(validationPayload, 3); + } + + parcBuffer_Release(&truePayload); + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(ContentObject, ContentObject_zero_payload) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_zero_payload, sizeof(v1_content_zero_payload), 0, sizeof(v1_content_zero_payload)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + CCNxName *testName = CCNxContentObjectFacadeV1_Implementation.getName(dictionary); + assertNotNull(testName, "Got null name on decode"); + + PARCBuffer *testPayload = CCNxContentObjectFacadeV1_Implementation.getPayload(dictionary); + assertNotNull(testPayload, "got null payload") + assertTrue(parcBuffer_Remaining(testPayload) == 0, "Wrong length, expected 0 got %zu", parcBuffer_Remaining(testPayload)); + + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(ContentObject, ContentObject_no_payload) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_no_payload, sizeof(v1_content_no_payload), 0, sizeof(v1_content_no_payload)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + CCNxName *test = CCNxContentObjectFacadeV1_Implementation.getName(dictionary); + assertNotNull(test, "Got null name on decode"); + + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(Control) +{ + LONGBOW_RUN_TEST_CASE(Control, CPIAddRoute_Crc32c_FixedHeader); + LONGBOW_RUN_TEST_CASE(Control, CPIAddRoute_Crc32c_Payload); + LONGBOW_RUN_TEST_CASE(Control, CPIAddRoute_Crc32c_ValidationAlg_CryptoSuite); + LONGBOW_RUN_TEST_CASE(Control, CPIAddRoute_Crc32c_ValidationPayload); +} + +LONGBOW_TEST_FIXTURE_SETUP(Control) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Control) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Control, CPIAddRoute_Crc32c_FixedHeader) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_cpi_add_route_crc32c, sizeof(v1_cpi_add_route_crc32c), 0, sizeof(v1_cpi_add_route_crc32c)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader); + + // leave the FixedHeader buffer at position 0 + parcBuffer_Rewind(fixedHeader); + + PARCBuffer *trueFixedHeader = parcBuffer_Wrap(v1_cpi_add_route_crc32c, 8, 0, 8); + assertTrue(parcBuffer_Equals(fixedHeader, trueFixedHeader), "Buffers not equal") + { + printf("Expected\n"); + parcBuffer_Display(trueFixedHeader, 3); + printf("Got\n"); + parcBuffer_Display(fixedHeader, 3); + } + + parcBuffer_Release(&trueFixedHeader); + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(Control, CPIAddRoute_Crc32c_Payload) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_cpi_add_route_crc32c, sizeof(v1_cpi_add_route_crc32c), 0, sizeof(v1_cpi_add_route_crc32c)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCBuffer *test = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD); + + TlvExtent validationPayloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_cpi_add_route_crc32c), V1_MANIFEST_CPI_SIGBITS); + PARCBuffer *trueValidationPayload = parcBuffer_Wrap(v1_cpi_add_route_crc32c, sizeof(v1_cpi_add_route_crc32c), validationPayloadExtent.offset, validationPayloadExtent.offset + validationPayloadExtent.length); + + assertTrue(parcBuffer_Equals(test, trueValidationPayload), "Buffers not equal") + { + printf("Expected\n"); + parcBuffer_Display(trueValidationPayload, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&trueValidationPayload); + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(Control, CPIAddRoute_Crc32c_ValidationAlg_CryptoSuite) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_cpi_add_route_crc32c, sizeof(v1_cpi_add_route_crc32c), 0, sizeof(v1_cpi_add_route_crc32c)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCCryptoSuite test = (PARCCryptoSuite) ccnxValidationFacadeV1_GetCryptoSuite(dictionary); + PARCCryptoSuite trueCryptoSuite = PARCCryptoSuite_NULL_CRC32C; + + assertTrue(test == trueCryptoSuite, "Wrong crypto suite, expected %d got %d", trueCryptoSuite, test); + + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(Control, CPIAddRoute_Crc32c_ValidationPayload) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_cpi_add_route_crc32c, sizeof(v1_cpi_add_route_crc32c), 0, sizeof(v1_cpi_add_route_crc32c)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCBuffer *validationPayload = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD); + + TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_cpi_add_route_crc32c), V1_MANIFEST_CPI_SIGBITS); + PARCBuffer *truePayload = parcBuffer_Wrap(v1_cpi_add_route_crc32c, sizeof(v1_cpi_add_route_crc32c), payloadExtent.offset, payloadExtent.offset + payloadExtent.length); + + assertTrue(parcBuffer_Equals(validationPayload, truePayload), "Buffers not equal") + { + printf("Expected\n"); + parcBuffer_Display(truePayload, 3); + printf("Got\n"); + parcBuffer_Display(validationPayload, 3); + } + + parcBuffer_Release(&truePayload); + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(Interest) +{ + LONGBOW_RUN_TEST_CASE(Interest, interest_bad_message_length); + LONGBOW_RUN_TEST_CASE(Interest, interest_all_fields_FixedHeader); + LONGBOW_RUN_TEST_CASE(Interest, interest_all_fields_Lifetime); + LONGBOW_RUN_TEST_CASE(Interest, interest_all_fields_Name); + LONGBOW_RUN_TEST_CASE(Interest, interest_all_fields_ValidationAlg_KeyId); + LONGBOW_RUN_TEST_CASE(Interest, interest_all_fields_ValidationPayload); + LONGBOW_RUN_TEST_CASE(Interest, interest_nameA_crc32c_ValidationAlg_CryptoSuite); + LONGBOW_RUN_TEST_CASE(Interest, interest_nameA_crc32c_ValidationPayload); + LONGBOW_RUN_TEST_CASE(Interest, ccnxCodecSchemaV1PacketDecoder_BufferDecode); + LONGBOW_RUN_TEST_CASE(Interest, interest_bad_validation_alg); + LONGBOW_RUN_TEST_CASE(Interest, interest_validation_alg_overrun); +} + +LONGBOW_TEST_FIXTURE_SETUP(Interest) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Interest) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Interest, interest_bad_message_length) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_bad_message_length, sizeof(v1_interest_bad_message_length), 0, sizeof(v1_interest_bad_message_length)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertFalse(success, "Should have seen and error on decode"); + + CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder); + assertNotNull(error, "Error not set when bad decode"); + + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(Interest, interest_all_fields_FixedHeader) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCBuffer *fixedHeader = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_FixedHeader); + + // leave the FixedHeader buffer at position 0 + parcBuffer_Rewind(fixedHeader); + + PARCBuffer *trueFixedHeader = parcBuffer_Wrap(v1_interest_all_fields, 8, 0, 8); + assertTrue(parcBuffer_Equals(fixedHeader, trueFixedHeader), "Buffers not equal") + { + printf("Expected\n"); + parcBuffer_Display(trueFixedHeader, 3); + printf("Got\n"); + parcBuffer_Display(fixedHeader, 3); + } + + parcBuffer_Release(&trueFixedHeader); + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(Interest, interest_all_fields_Lifetime) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + uint64_t lifetime = ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime); + + TlvExtent lifetimeExtent = getTruthTableHeaderExtent(TRUTHTABLENAME(v1_interest_all_fields), V1_MANIFEST_INT_LIFETIME); + + parcBuffer_SetPosition(packetBuffer, lifetimeExtent.offset); + uint64_t trueTime; + ccnxCodecTlvUtilities_GetVarInt(packetBuffer, lifetimeExtent.length, &trueTime); + + assertTrue(lifetime == trueTime, "Wrong time, expected %" PRIx64 " got %" PRIx64, trueTime, lifetime); + + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(Interest, interest_all_fields_Name) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + CCNxName *name = ccnxTlvDictionary_GetName(dictionary, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME); + CCNxName *trueName = ccnxName_CreateFromCString(v1_interest_all_fields_URI); + + assertTrue(ccnxName_Equals(name, trueName), "Buffers not equal") + { + printf("Expected\n"); + ccnxName_Display(trueName, 3); + printf("Got\n"); + ccnxName_Display(name, 3); + } + + ccnxName_Release(&trueName); + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +/* + * This packet does not have a validation section, so the test is that its missing + */ +LONGBOW_TEST_CASE(Interest, interest_all_fields_ValidationAlg_KeyId) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCBuffer *keyid = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID); + assertNull(keyid, "Got a non-null keyid from a packet without one"); + + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +/* + * Packet does not have validation, test for missing + */ +LONGBOW_TEST_CASE(Interest, interest_all_fields_ValidationPayload) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCBuffer *payload = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD); + assertNull(payload, "Got a non-null validation payload from a packet without one"); + + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(Interest, interest_nameA_crc32c_ValidationAlg_CryptoSuite) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), 0, sizeof(v1_interest_nameA_crc32c)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCCryptoSuite suite = (PARCCryptoSuite) ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE); + PARCCryptoSuite trueSuite = PARCCryptoSuite_NULL_CRC32C; + + assertTrue(suite == trueSuite, "Wrong crypto suite, expected %d got %d", trueSuite, suite); + + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(Interest, interest_nameA_crc32c_ValidationPayload) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), 0, sizeof(v1_interest_nameA_crc32c)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertTrue(success, "Error on decode: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCBuffer *validationPayload = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD); + + TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_ValidationPayload); + PARCBuffer *truePayload = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), payloadExtent.offset, payloadExtent.offset + payloadExtent.length); + + assertTrue(parcBuffer_Equals(validationPayload, truePayload), "Buffers not equal") + { + printf("Expected\n"); + parcBuffer_Display(truePayload, 3); + printf("Got\n"); + parcBuffer_Display(validationPayload, 3); + } + + parcBuffer_Release(&truePayload); + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(Interest, ccnxCodecSchemaV1PacketDecoder_BufferDecode) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), 0, sizeof(v1_interest_nameA_crc32c)); + + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + bool success = ccnxCodecSchemaV1PacketDecoder_BufferDecode(packetBuffer, dictionary); + assertTrue(success, "Error on decode"); + + PARCBuffer *validationPayload = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD); + + TlvExtent payloadExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_ValidationPayload); + PARCBuffer *truePayload = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), payloadExtent.offset, payloadExtent.offset + payloadExtent.length); + + assertTrue(parcBuffer_Equals(validationPayload, truePayload), "Buffers not equal") + { + printf("Expected\n"); + parcBuffer_Display(truePayload, 3); + printf("Got\n"); + parcBuffer_Display(validationPayload, 3); + } + + parcBuffer_Release(&truePayload); + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); +} + +LONGBOW_TEST_CASE(Interest, interest_bad_validation_alg) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_bad_validation_alg, sizeof(v1_interest_bad_validation_alg), 0, sizeof(v1_interest_bad_validation_alg)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertFalse(success, "Should have seen and error on decode"); + + CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder); + assertNotNull(error, "Error not set when bad decode"); + + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +LONGBOW_TEST_CASE(Interest, interest_validation_alg_overrun) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_validation_alg_overrun, sizeof(v1_interest_validation_alg_overrun), 0, sizeof(v1_interest_validation_alg_overrun)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(packetBuffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + bool success = ccnxCodecSchemaV1PacketDecoder_Decode(decoder, dictionary); + assertFalse(success, "Should have seen and error on decode"); + + CCNxCodecError *error = ccnxCodecTlvDecoder_GetError(decoder); + assertNotNull(error, "Error not set when bad decode"); + + parcBuffer_Release(&packetBuffer); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); +} + +// ========================================================================= + + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_PacketDecoder); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketEncoder.c new file mode 100755 index 00000000..eb79502e --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_PacketEncoder.c @@ -0,0 +1,1054 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_PacketEncoder.c" +#include +#include +#include +#include +#include + +#include "testrig_encoder.c" + +#include +#include +#include + +#include + + +// ========================================================================= + +LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_PacketEncoder) +{ + LONGBOW_RUN_TEST_FIXTURE(ContentObject); + LONGBOW_RUN_TEST_FIXTURE(Interest); + LONGBOW_RUN_TEST_FIXTURE(InterestReturn); + LONGBOW_RUN_TEST_FIXTURE(Control); + LONGBOW_RUN_TEST_FIXTURE(UnknownType); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_PacketEncoder) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_PacketEncoder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(ContentObject) +{ + LONGBOW_RUN_TEST_CASE(ContentObject, v1_content_nameA_keyid1_rsasha256); + LONGBOW_RUN_TEST_CASE(ContentObject, zero_length_payload); + LONGBOW_RUN_TEST_CASE(ContentObject, null_payload); + LONGBOW_RUN_TEST_CASE(ContentObject, no_cryptosuite); +} + +LONGBOW_TEST_FIXTURE_SETUP(ContentObject) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(ContentObject) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +/* + * Make a dictionary equivalent to v1_content_nameA_keyid1_rsasha256 and encode it then compare + */ +LONGBOW_TEST_CASE(ContentObject, v1_content_nameA_keyid1_rsasha256) +{ + CCNxName *name = ccnxName_CreateFromCString(v1_content_nameA_keyid1_rsasha256_URI); + + TlvExtent payloadExtent = + getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_PAYLOAD); + PARCBuffer *payload = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, + sizeof(v1_content_nameA_keyid1_rsasha256), + payloadExtent.offset, + payloadExtent.offset + payloadExtent.length); + + CCNxTlvDictionary *message = + ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation, + name, CCNxPayloadType_KEY, payload); + + TlvExtent fragmentExtent = + getTruthTableHeaderExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_E2EFRAG); + PARCBuffer *fragment = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, + sizeof(v1_content_nameA_keyid1_rsasha256), + fragmentExtent.offset, + fragmentExtent.offset + fragmentExtent.length); + ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_OBJFRAG, fragment); + + uint64_t expiryTime = 1388534400000ULL; + ccnxContentObject_SetExpiryTime(message, expiryTime); + + uint64_t endChunkNumber = 0x06050403; + ccnxContentObject_SetFinalChunkNumber(message, endChunkNumber); + + TlvExtent keyIdExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_KEYID); + PARCBuffer *keyid = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, + sizeof(v1_content_nameA_keyid1_rsasha256), + keyIdExtent.offset, + keyIdExtent.offset + keyIdExtent.length); + + TlvExtent keyExtent = getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_PUBKEY); + PARCBuffer *key = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, + sizeof(v1_content_nameA_keyid1_rsasha256), + keyExtent.offset, + keyExtent.offset + keyExtent.length); + + ccnxValidationFacadeV1_SetCryptoSuite(message, PARCCryptoSuite_RSA_SHA256); + ccnxValidationFacadeV1_SetKeyId(message, keyid); + ccnxValidationFacadeV1_SetPublicKey(message, key); + + TlvExtent sigExtent = + getTruthTableExtent(TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256), V1_MANIFEST_OBJ_SIGBITS); + PARCBuffer *sig = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, + sizeof(v1_content_nameA_keyid1_rsasha256), + sigExtent.offset, + sigExtent.offset + sigExtent.length); + + ccnxValidationFacadeV1_SetPayload(message, sig); + + // encode + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message); + assertFalse(length < 0, "Got encoding error: %s", + ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + assertTrue(length == sizeof(v1_content_nameA_keyid1_rsasha256), + "Wrong length, expected %zu got %zd", sizeof(v1_content_nameA_keyid1_rsasha256), length); + + // verify + PARCBuffer *truth = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, + sizeof(v1_content_nameA_keyid1_rsasha256), + 0, + sizeof(v1_content_nameA_keyid1_rsasha256)); + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + + uint8_t *truthOverlay = parcBuffer_Overlay(truth, 0); + uint8_t *testOverlay = parcBuffer_Overlay(test, 0); + + for (ssize_t i = 0; i < length; i++) { + if (truthOverlay[i] != testOverlay[i]) { + printf("Buffers differ at byte %zd, expected 0x%02x got 0x%02x\n", i, truthOverlay[i], testOverlay[i]); + break; + } + } + } + + // cleanup + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&sig); + parcBuffer_Release(&key); + parcBuffer_Release(&keyid); + parcBuffer_Release(&payload); + parcBuffer_Release(&fragment); + ccnxName_Release(&name); + ccnxTlvDictionary_Release(&message); +} + + +LONGBOW_TEST_CASE(ContentObject, zero_length_payload) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/no/payload"); + PARCBuffer *payload = parcBuffer_Allocate(0); + + CCNxTlvDictionary *message = + ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation, + name, CCNxPayloadType_DATA, payload); + + // encode + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message); + assertFalse(length < 0, "Got encoding error: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *encoded = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertNotNull(encoded, "got null output buffer"); + + parcBuffer_Display(encoded, 3); + + parcBuffer_Release(&encoded); + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&message); + parcBuffer_Release(&payload); + ccnxName_Release(&name); +} + +LONGBOW_TEST_CASE(ContentObject, null_payload) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/no/payload"); + + CCNxTlvDictionary *message = + ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation, + name, CCNxPayloadType_DATA, NULL); + // encode + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message); + assertFalse(length < 0, "Got encoding error: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *encoded = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertNotNull(encoded, "got null output buffer"); + + parcBuffer_Release(&encoded); + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&message); + ccnxName_Release(&name); +} + +/* + * A content object without a cryptosuite should not be signed + */ +LONGBOW_TEST_CASE(ContentObject, no_cryptosuite) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/no/payload"); + + CCNxTlvDictionary *message = + ccnxContentObject_CreateWithImplAndPayload(&CCNxContentObjectFacadeV1_Implementation, + name, CCNxPayloadType_DATA, NULL); + // encode + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message); + assertFalse(length < 0, "Got encoding error: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *encoded = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertNotNull(encoded, "got null output buffer"); + + // it should be 33 bytes without a signature + assertTrue(parcBuffer_Remaining(encoded) == 33, "Wrong length exepcted 33 got %zu", parcBuffer_Remaining(encoded)); + + parcBuffer_Release(&encoded); + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&message); + ccnxName_Release(&name); +} + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(Interest) +{ + LONGBOW_RUN_TEST_CASE(Interest, v1_interest_nameA_crc32c); + LONGBOW_RUN_TEST_CASE(Interest, v1_interest_nameA_crc32c_IoVec); +} + +LONGBOW_TEST_FIXTURE_SETUP(Interest) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Interest) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +/* + * Make an interest equivalent to v1_interest_nameA_crc32c and encode it + */ +LONGBOW_TEST_CASE(Interest, v1_interest_nameA_crc32c) +{ + CCNxName *name = ccnxName_CreateFromCString(v1_interest_nameA_crc32c_URI); + + CCNxTlvDictionary *message = + ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation, + name, CCNxInterestDefault_LifetimeMilliseconds, NULL, NULL, 32); + + TlvExtent fragmentExtent = getTruthTableHeaderExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_E2EFRAG); + PARCBuffer *fragment = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), fragmentExtent.offset, fragmentExtent.offset + fragmentExtent.length); + ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG, fragment); + + ccnxValidationFacadeV1_SetCryptoSuite(message, PARCCryptoSuite_NULL_CRC32C); + + TlvExtent sigExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_ValidationPayload); + PARCBuffer *sig = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), sigExtent.offset, sigExtent.offset + sigExtent.length); + + ccnxValidationFacadeV1_SetPayload(message, sig); + + // encode + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message); + assertFalse(length < 0, "Got encoding error: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + assertTrue(length == sizeof(v1_interest_nameA_crc32c), "Wrong length, expected %zu got %zd", sizeof(v1_interest_nameA_crc32c), length); + + // verify + PARCBuffer *truth = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), 0, sizeof(v1_interest_nameA_crc32c)); + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + + uint8_t *truthOverlay = parcBuffer_Overlay(truth, 0); + uint8_t *testOverlay = parcBuffer_Overlay(test, 0); + + for (ssize_t i = 0; i < length; i++) { + if (truthOverlay[i] != testOverlay[i]) { + printf("Buffers differ at byte %zd, expected 0x%02x got 0x%02x", i, truthOverlay[i], testOverlay[i]); + break; + } + } + } + + // cleanup + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&sig); + parcBuffer_Release(&fragment); + ccnxName_Release(&name); + ccnxTlvDictionary_Release(&message); +} + +/* + * Make an interest equivalent to v1_interest_nameA_crc32c and encode it + */ +LONGBOW_TEST_CASE(Interest, v1_interest_nameA_crc32c_IoVec) +{ + CCNxName *name = ccnxName_CreateFromCString(v1_interest_nameA_crc32c_URI); + + CCNxTlvDictionary *message = + ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation, + name, CCNxInterestDefault_LifetimeMilliseconds, NULL, NULL, 32); + + TlvExtent fragmentExtent = getTruthTableHeaderExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_E2EFRAG); + PARCBuffer *fragment = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), fragmentExtent.offset, fragmentExtent.offset + fragmentExtent.length); + ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG, fragment); + + ccnxValidationFacadeV1_SetCryptoSuite(message, PARCCryptoSuite_NULL_CRC32C); + + TlvExtent sigExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_ValidationPayload); + PARCBuffer *sig = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), sigExtent.offset, sigExtent.offset + sigExtent.length); + + ccnxValidationFacadeV1_SetPayload(message, sig); + + // encode + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecSchemaV1PacketEncoder_DictionaryEncode(message, NULL); + assertNotNull(iovec, "Got null iovec from ccnxCodecSchemaV1PacketEncoder_DictionaryEncode"); + + size_t length = ccnxCodecNetworkBufferIoVec_Length(iovec); + assertTrue(length == sizeof(v1_interest_nameA_crc32c), "Wrong length, expected %zu got %zd", sizeof(v1_interest_nameA_crc32c), length); + + // verify + PARCBuffer *truth = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), 0, sizeof(v1_interest_nameA_crc32c)); + + int iovecCount = ccnxCodecNetworkBufferIoVec_GetCount(iovec); + PARCBuffer *test = parcBuffer_Allocate(length); + const struct iovec *array = ccnxCodecNetworkBufferIoVec_GetArray(iovec); + for (int i = 0; i < iovecCount; i++) { + parcBuffer_PutArray(test, array[i].iov_len, array[i].iov_base); + } + parcBuffer_Flip(test); + + assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + + uint8_t *truthOverlay = parcBuffer_Overlay(truth, 0); + uint8_t *testOverlay = parcBuffer_Overlay(test, 0); + + for (ssize_t i = 0; i < length; i++) { + if (truthOverlay[i] != testOverlay[i]) { + printf("Buffers differ at byte %zd, expected 0x%02x got 0x%02x", i, truthOverlay[i], testOverlay[i]); + break; + } + } + } + + // cleanup + ccnxCodecNetworkBufferIoVec_Release(&iovec); + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&sig); + parcBuffer_Release(&fragment); + ccnxName_Release(&name); + ccnxTlvDictionary_Release(&message); +} + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(InterestReturn) +{ + LONGBOW_RUN_TEST_CASE(InterestReturn, v1_interest_return); +} + +LONGBOW_TEST_FIXTURE_SETUP(InterestReturn) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(InterestReturn) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +/* + * Make an interest return and encode it + */ +LONGBOW_TEST_CASE(InterestReturn, v1_interest_return) +{ + CCNxName *name = ccnxName_CreateFromCString(v1_interest_nameA_crc32c_URI); + + CCNxInterest *interest = + ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation, + name, CCNxInterestDefault_LifetimeMilliseconds, NULL, NULL, 32); + ccnxName_Release(&name); + + TlvExtent fragmentExtent = getTruthTableHeaderExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_E2EFRAG); + PARCBuffer *fragment = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), fragmentExtent.offset, fragmentExtent.offset + fragmentExtent.length); + ccnxTlvDictionary_PutBuffer(interest, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG, fragment); + parcBuffer_Release(&fragment); + + ccnxValidationFacadeV1_SetCryptoSuite(interest, PARCCryptoSuite_NULL_CRC32C); + + TlvExtent sigExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_ValidationPayload); + PARCBuffer *sig = parcBuffer_Wrap(v1_interest_nameA_crc32c, sizeof(v1_interest_nameA_crc32c), sigExtent.offset, sigExtent.offset + sigExtent.length); + + ccnxValidationFacadeV1_SetPayload(interest, sig); + parcBuffer_Release(&sig); + + CCNxTlvDictionary *message = + ccnxInterestReturn_Create(interest, CCNxInterestReturn_ReturnCode_NoResources); + ccnxInterest_Release(&interest); + + // encode + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message); + ssize_t expectedLength = sizeof(v1_interest_nameA_crc32c); + assertFalse(length < 0, "Got encoding error: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + assertTrue(length == expectedLength, "Wrong length, expected %zu got %zd", expectedLength, length); + + // verify + PARCBuffer *truth = parcBuffer_Wrap(v1_interest_nameA_crc32c_returned, sizeof(v1_interest_nameA_crc32c_returned), 0, sizeof(v1_interest_nameA_crc32c_returned)); + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + + uint8_t *truthOverlay = parcBuffer_Overlay(truth, 0); + uint8_t *testOverlay = parcBuffer_Overlay(test, 0); + + for (ssize_t i = 0; i < length; i++) { + if (truthOverlay[i] != testOverlay[i]) { + printf("Buffers differ at byte %zd, expected 0x%02x got 0x%02x\n", i, truthOverlay[i], testOverlay[i]); + } + } + } + + // cleanup + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&message); +} + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(Control) +{ + LONGBOW_RUN_TEST_CASE(Control, payload); + LONGBOW_RUN_TEST_CASE(Control, cryptosuite); +} + +LONGBOW_TEST_FIXTURE_SETUP(Control) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Control) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Control, payload) +{ + uint8_t encoded[] = { + 0x01, 0xa4, 0x00, 0x22, + 0x00, 0x00, 0x00, 0x08, + + 0xbe, 0xef, 0x00, 0x16, // control message + + 0x7b, 0x22, 0x74, 0x68, // {"th + 0x69, 0x73, 0x20, 0x69, // is i + 0x73, 0x22, 0x3a, 0x22, // s":" + 0x61, 0x6e, 0x6e, 0x6f, // anno + 0x79, 0x69, 0x6e, 0x67, // ying + 0x22, 0x7d // "} + }; + + + CCNxTlvDictionary *message = ccnxCodecSchemaV1TlvDictionary_CreateControl(); + + PARCJSON *json = parcJSON_Create(); + parcJSON_AddString(json, "this is", "annoying"); + + ccnxTlvDictionary_PutJson(message, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD, json); + parcJSON_Release(&json); + + // encode + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message); + + assertFalse(length < 0, "Got encoding error: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + assertTrue(length == sizeof(encoded), "Wrong length, expected %zu got %zd", sizeof(encoded), length); + + // verify + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + + uint8_t *truthOverlay = parcBuffer_Overlay(truth, 0); + uint8_t *testOverlay = parcBuffer_Overlay(test, 0); + + for (ssize_t i = 0; i < length; i++) { + if (truthOverlay[i] != testOverlay[i]) { + printf("Buffers differ at byte %zd, expected 0x%02x got 0x%02x", i, truthOverlay[i], testOverlay[i]); + break; + } + } + } + + parcBuffer_Release(&test); + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&message); + parcBuffer_Release(&truth); +} + +LONGBOW_TEST_CASE(Control, cryptosuite) +{ + uint8_t encoded[] = { + 0x01, 0xA4, 0x00, 16, + 0x00, 0x00, 0x00, 8, + 0xBE, 0xEF, 0x00, 4, + 'a', 'b', 'c', 'd', + 0x00, 0x03, 0x00, 4, + 0x00, 0x02, 0x00, 0 + }; + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + PARCBuffer *payload = parcBuffer_Wrap(encoded, sizeof(encoded), 12, 16); + + CCNxTlvDictionary *message = ccnxCodecSchemaV1TlvDictionary_CreateControl(); + ccnxTlvDictionary_PutBuffer(message, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD, payload); + ccnxValidationCRC32C_Set(message); + + ccnxValidationCRC32C_Set(message); + + // encode + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + PARCSigner *signer = ccnxValidationCRC32C_CreateSigner(); + ccnxCodecTlvEncoder_SetSigner(encoder, signer); + + ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message); + assertFalse(length < 0, "Got encoding error: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertNotNull(test, "Got null buffer from encoder"); + uint8_t testSuite = parcBuffer_GetAtIndex(test, 21); + assertTrue(testSuite == 2, "Wrong cryptosuite, expected 2 got %u", testSuite); + + parcSigner_Release(&signer); + parcBuffer_Release(&test); + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&message); + parcBuffer_Release(&payload); + parcBuffer_Release(&truth); +} + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(UnknownType) +{ + LONGBOW_RUN_TEST_CASE(UnknownType, unknown); +} + +LONGBOW_TEST_FIXTURE_SETUP(UnknownType) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(UnknownType) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +/* + * try to encode a message with unknown message type + */ +LONGBOW_TEST_CASE(UnknownType, unknown) +{ + // this initializes the dictionary to unknown type + CCNxTlvDictionary *message = ccnxTlvDictionary_Create(20, 20); + + // encode + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ssize_t length = ccnxCodecSchemaV1PacketEncoder_Encode(encoder, message); + assertTrue(length < 0, "Did not get error condition for unknown type"); + + CCNxCodecError *error = ccnxCodecTlvEncoder_GetError(encoder); + assertNotNull(error, "Did not get an error for invalid encoding"); + + ccnxCodecTlvEncoder_Destroy(&encoder); + ccnxTlvDictionary_Release(&message); +} + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, _getHopLimit_Present); + LONGBOW_RUN_TEST_CASE(Local, _getHopLimit_Missing); + LONGBOW_RUN_TEST_CASE(Local, _encodeFixedHeader_ContentObject); + LONGBOW_RUN_TEST_CASE(Local, _encodeFixedHeader_Interest); + LONGBOW_RUN_TEST_CASE(Local, _encodeOptionalHeaders); + LONGBOW_RUN_TEST_CASE(Local, _encodeMessage_Interest); + LONGBOW_RUN_TEST_CASE(Local, _encodeMessage_ContentObject); + LONGBOW_RUN_TEST_CASE(Local, _encodeCPI); + LONGBOW_RUN_TEST_CASE(Local, _encodeMessage_Unknown); + LONGBOW_RUN_TEST_CASE(Local, _encodeValidationAlg_Present); + LONGBOW_RUN_TEST_CASE(Local, _encodeValidationAlg_Missing); + LONGBOW_RUN_TEST_CASE(Local, _encodeValidationPayload_Present); + LONGBOW_RUN_TEST_CASE(Local, _encodeValidationPayload_Missing); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, _getHopLimit_Present) +{ + uint8_t hoplimit = 77; + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + ccnxTlvDictionary_PutInteger(dict, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_HOPLIMIT, hoplimit); + + uint8_t test = _getHopLimit(dict); + assertTrue(test == hoplimit, "Got wrong hoplimit, expected %u got %u", hoplimit, test); + ccnxTlvDictionary_Release(&dict); +} + +LONGBOW_TEST_CASE(Local, _getHopLimit_Missing) +{ + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + + uint8_t test = _getHopLimit(dict); + assertTrue(test == CCNxInterestDefault_HopLimit, "Got wrong hoplimit, expected %u got %u", CCNxInterestDefault_HopLimit, test); + ccnxTlvDictionary_Release(&dict); +} + +LONGBOW_TEST_CASE(Local, _encodeFixedHeader_ContentObject) +{ + uint8_t encoded[] = { + 0x01, 0x01, 0x00, 100, // ver = 1, type = content object, length = 100 + 0x00, 0x00, 0x00, 14, // reserved = 0x0000000, header length = 14 + }; + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ssize_t length = _encodeFixedHeader(encoder, dict, CCNxCodecSchemaV1Types_PacketType_ContentObject, 14, 100); + assertTrue(length == 8, "wrong length, expected %d got %zd", 8, length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxTlvDictionary_Release(&dict); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Local, _encodeFixedHeader_Interest) +{ + uint8_t encoded[] = { + 0x01, 0x00, 0x00, 100, // ver = 1, type = interest, length = 100 + 0x1f, 0x00, 0x00, 14, // hoplimit = 31, reserved = 0x0000, header length = 14 + }; + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + ccnxTlvDictionary_PutInteger(dict, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_HOPLIMIT, 31); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ssize_t length = _encodeFixedHeader(encoder, dict, CCNxCodecSchemaV1Types_PacketType_Interest, 14, 100); + assertTrue(length == 8, "wrong length, expected %d got %zd", 8, length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxTlvDictionary_Release(&dict); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Local, _encodeOptionalHeaders) +{ + uint8_t encoded[] = { + 0x00, 0x01, 0x00, 2, // Interest Lifetime (2 bytes) + 0xEA, 0xEB, + }; + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + ccnxTlvDictionary_PutInteger(dict, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime, 0xEAEB); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ssize_t length = _encodeOptionalHeaders(encoder, dict); + assertTrue(length == sizeof(encoded), "wrong length, expected %zu got %zd", sizeof(encoded), length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxTlvDictionary_Release(&dict); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Local, _encodeMessage_Interest) +{ + uint8_t encoded[] = { + 0x00, 0x01, 0x00, 13, + 0x00, 0x00, 0x00, 9, + 0x00, CCNxNameLabelType_NAME, 0x00, 5, + 'p', 'o', 'p', 'p', 'y' + }; + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxName *name = ccnxName_CreateFromCString("lci:/poppy"); + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + ccnxTlvDictionary_PutName(dict, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME, name); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + CCNxCodecSchemaV1Types_PacketType packetType; + ssize_t length = _encodeMessage(encoder, dict, &packetType); + assertTrue(length == sizeof(encoded), "wrong length, expected %zu got %zd", sizeof(encoded), length); + assertTrue(packetType == CCNxCodecSchemaV1Types_PacketType_Interest, "Wrong packet type, expected %d got %d", + CCNxCodecSchemaV1Types_PacketType_Interest, packetType); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxName_Release(&name); + ccnxTlvDictionary_Release(&dict); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Local, _encodeMessage_ContentObject) +{ + uint8_t encoded[] = { + 0x00, 0x02, 0x00, 13, + 0x00, 0x00, 0x00, 9, + 0x00, CCNxNameLabelType_NAME, 0x00, 5, + 'p', 'o', 'p', 'p', 'y' + }; + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxName *name = ccnxName_CreateFromCString("lci:/poppy"); + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + ccnxTlvDictionary_PutName(dict, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME, name); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + CCNxCodecSchemaV1Types_PacketType packetType; + ssize_t length = _encodeMessage(encoder, dict, &packetType); + assertTrue(length == sizeof(encoded), "wrong length, expected %zu got %zd", sizeof(encoded), length); + assertTrue(packetType == CCNxCodecSchemaV1Types_PacketType_ContentObject, "Wrong packet type, expected %d got %d", + CCNxCodecSchemaV1Types_PacketType_ContentObject, packetType); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxName_Release(&name); + ccnxTlvDictionary_Release(&dict); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Local, _encodeCPI) +{ + uint8_t encoded [] = { + 0x00, 0x02, 0x03, 0x99, // + }; + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + ccnxValidationCRC32C_Set(dict); + ccnxTlvDictionary_PutBuffer(dict, CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD, truth); + + ssize_t length = _encodeCPI(encoder, dict); + assertTrue(length == sizeof(encoded), "wrong length, expected %zu got %zd", sizeof(encoded), length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&test); + ccnxTlvDictionary_Release(&dict); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +/* + * This test requires that we set the message type to some unknown value, which we get if + * we create a dictionary with ccnxTlvDictionary_Create() and dont call anything to set + * the message type. It will be "CCNxTlvDictionary_Unknown". + */ +LONGBOW_TEST_CASE(Local, _encodeMessage_Unknown) +{ + CCNxTlvDictionary *dict = ccnxTlvDictionary_Create(20, 20); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + CCNxCodecSchemaV1Types_PacketType packetType; + ssize_t length = _encodeMessage(encoder, dict, &packetType); + assertTrue(length < 0, "wrong length, expected negative got %zd", length); + + CCNxCodecError *error = ccnxCodecTlvEncoder_GetError(encoder); + assertNotNull(error, "Got null error when an error condition should have been set"); + + ccnxTlvDictionary_Release(&dict); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Local, _encodeValidationAlg_Present) +{ + uint8_t encoded [] = { + 0x00, 0x03, 0x00, 4, // validation alg, length = 4 + 0x00, 0x02, 0x00, 0x00, // CRC32C + }; + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + PARCBuffer *truePayload = parcBuffer_Wrap(encoded, sizeof(encoded), 4, sizeof(encoded)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + ccnxValidationCRC32C_Set(dict); + ccnxTlvDictionary_PutBuffer(dict, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD, truePayload); + + ssize_t length = _encodeValidationAlg(encoder, dict); + assertTrue(length == sizeof(encoded), "wrong length, expected %zu got %zd", sizeof(encoded), length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&truePayload); + parcBuffer_Release(&test); + ccnxTlvDictionary_Release(&dict); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Local, _encodeValidationAlg_Missing) +{ + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + + ssize_t length = _encodeValidationAlg(encoder, dict); + assertTrue(length == 0, "wrong length, expected %d got %zd", 0, length); + + ccnxTlvDictionary_Release(&dict); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Local, _encodeValidationPayload_Present) +{ + uint8_t encoded [] = { + 0x00, 0x04, 0x00, 4, // validation payload, length = 4 + 0x00, 0x02, 0x03, 0x99, // + }; + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + PARCBuffer *truePayload = parcBuffer_Wrap(encoded, sizeof(encoded), 4, sizeof(encoded)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + ccnxValidationCRC32C_Set(dict); + ccnxTlvDictionary_PutBuffer(dict, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD, truePayload); + + ssize_t length = _encodeValidationPayload(encoder, dict); + assertTrue(length == sizeof(encoded), "wrong length, expected %zu got %zd", sizeof(encoded), length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(test, truth), "Buffers mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + parcBuffer_Release(&truePayload); + parcBuffer_Release(&test); + ccnxTlvDictionary_Release(&dict); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(Local, _encodeValidationPayload_Missing) +{ + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + + ssize_t length = _encodeValidationPayload(encoder, dict); + assertTrue(length == 0, "wrong length, expected %d got %zd", 0, length); + + ccnxTlvDictionary_Release(&dict); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + + +// ================================================================================== + + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_PacketEncoder); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_TlvDictionary.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_TlvDictionary.c new file mode 100755 index 00000000..ccaa8b13 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_TlvDictionary.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_TlvDictionary.c" +#include +#include + +LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_TlvDictionary) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_TlvDictionary) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_TlvDictionary) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateInterest); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateInterestReturn); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateContentObject); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateControl); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) { + printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding()); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateInterest) +{ + CCNxTlvDictionary *test = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + assertNotNull(test, "Got null return from ccnxCodecSchemaV1TlvDictionary_CreateInterest"); + assertTrue(ccnxTlvDictionary_IsInterest(test), "Dictionary is not an interest"); + assertTrue(ccnxTlvDictionary_GetSchemaVersion(test) == CCNxTlvDictionary_SchemaVersion_V1, + "Wrong schema version, expected %d got %d", + CCNxTlvDictionary_SchemaVersion_V1, + ccnxTlvDictionary_GetSchemaVersion(test)); + ccnxTlvDictionary_Release(&test); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateInterestReturn) +{ + CCNxTlvDictionary *test = ccnxCodecSchemaV1TlvDictionary_CreateInterestReturn(); + assertNotNull(test, "Got null return from ccnxCodecSchemaV1TlvDictionary_CreateInterest"); + assertTrue(ccnxTlvDictionary_IsInterestReturn(test), "Dictionary is not an interest"); + assertTrue(ccnxTlvDictionary_GetSchemaVersion(test) == CCNxTlvDictionary_SchemaVersion_V1, + "Wrong schema version, expected %d got %d", + CCNxTlvDictionary_SchemaVersion_V1, + ccnxTlvDictionary_GetSchemaVersion(test)); + ccnxTlvDictionary_Release(&test); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateContentObject) +{ + CCNxTlvDictionary *test = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + assertNotNull(test, "Got null return from ccnxCodecSchemaV1TlvDictionary_CreateContentObject"); + assertTrue(ccnxTlvDictionary_IsContentObject(test), "Dictionary is not a content object"); + assertTrue(ccnxTlvDictionary_GetSchemaVersion(test) == CCNxTlvDictionary_SchemaVersion_V1, + "Wrong schema version, expected %d got %d", + CCNxTlvDictionary_SchemaVersion_V1, + ccnxTlvDictionary_GetSchemaVersion(test)); + ccnxTlvDictionary_Release(&test); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1TlvDictionary_CreateControl) +{ + CCNxTlvDictionary *test = ccnxCodecSchemaV1TlvDictionary_CreateControl(); + assertNotNull(test, "Got null return from ccnxCodecSchemaV1TlvDictionary_CreateControl"); + assertTrue(ccnxTlvDictionary_IsControl(test), "Dictionary is not a control"); + assertTrue(ccnxTlvDictionary_GetSchemaVersion(test) == CCNxTlvDictionary_SchemaVersion_V1, + "Wrong schema version, expected %d got %d", + CCNxTlvDictionary_SchemaVersion_V1, + ccnxTlvDictionary_GetSchemaVersion(test)); + ccnxTlvDictionary_Release(&test); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_TlvDictionary); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationDecoder.c new file mode 100755 index 00000000..82cf69d1 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationDecoder.c @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_ValidationDecoder.c" +#include +#include +#include +#include + +#include "testrig_packetwrapper.c" + +// ========================================================================= + +LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_ValidationDecoder) +{ + LONGBOW_RUN_TEST_FIXTURE(DecodeAlg); + LONGBOW_RUN_TEST_FIXTURE(DecodePayload); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_ValidationDecoder) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_ValidationDecoder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(DecodeAlg) +{ + LONGBOW_RUN_TEST_CASE(DecodeAlg, CRC32C); + LONGBOW_RUN_TEST_CASE(DecodeAlg, HMAC_SHA256); + LONGBOW_RUN_TEST_CASE(DecodeAlg, RSA_SHA256); + + LONGBOW_RUN_TEST_CASE(DecodeAlg, Cert); + LONGBOW_RUN_TEST_CASE(DecodeAlg, PublicKey); + LONGBOW_RUN_TEST_CASE(DecodeAlg, KeyId); + LONGBOW_RUN_TEST_CASE(DecodeAlg, KeyName); + LONGBOW_RUN_TEST_CASE(DecodeAlg, SigTime); + + LONGBOW_RUN_TEST_CASE(DecodeAlg, KeyName_Invalid); +} + +LONGBOW_TEST_FIXTURE_SETUP(DecodeAlg) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(DecodeAlg) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(DecodeAlg, CRC32C) +{ + CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvSuite = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C; + PARCCryptoSuite parcSuite = PARCCryptoSuite_NULL_CRC32C; + + uint8_t encoded[] = { + 0x00, tlvSuite, 0x00, 0, + 0x00, 0x00, 0x00, 0x00 + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary); + assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCCryptoSuite test = (PARCCryptoSuite) ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE); + assertTrue(test == parcSuite, "Got wrong suite, expected %d got %d", parcSuite, test); + + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(DecodeAlg, HMAC_SHA256) +{ + CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvSuite = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256; + PARCCryptoSuite parcSuite = PARCCryptoSuite_HMAC_SHA256; + + uint8_t encoded[] = { + 0x00, tlvSuite, 0x00, 0, + 0x00, 0x00, 0x00, 0x00 + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary); + assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCCryptoSuite test = (PARCCryptoSuite) ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE); + assertTrue(test == parcSuite, "Got wrong suite, expected %d got %d", parcSuite, test); + + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(DecodeAlg, RSA_SHA256) +{ + CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvSuite = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256; + PARCCryptoSuite parcSuite = PARCCryptoSuite_RSA_SHA256; + + uint8_t encoded[] = { + 0x00, tlvSuite, 0x00, 0, + 0x00, 0x00, 0x00, 0x00 + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary); + assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCCryptoSuite test = (PARCCryptoSuite) ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE); + assertTrue(test == parcSuite, "Got wrong suite, expected %d got %d", parcSuite, test); + + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(DecodeAlg, Cert) +{ + uint8_t encoded[] = { + 0x00, 0x06, 0x00, 10, + 0x00, 0x0C, 0x00, 6, + 0x0a, 0x0b, 0x0c, 0x0d, + 0x0e, 0x0f + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary); + assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 8, sizeof(encoded)); + PARCBuffer *test = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CERT); + assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(DecodeAlg, PublicKey) +{ + uint8_t encoded[] = { + 0x00, 0x06, 0x00, 10, + 0x00, 0x0B, 0x00, 6, + 0x0a, 0x0b, 0x0c, 0x0d, + 0x0e, 0x0f + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary); + assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 8, sizeof(encoded)); + PARCBuffer *test = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEY); + assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(DecodeAlg, KeyId) +{ + uint8_t encoded[] = { + 0x00, 0x06, 0x00, 10, + 0x00, 0x09, 0x00, 6, + 0x0a, 0x0b, 0x0c, 0x0d, + 0x0e, 0x0f + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary); + assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 8, sizeof(encoded)); + PARCBuffer *test = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID); + assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(DecodeAlg, KeyName) +{ + uint8_t encoded[] = { + 0x00, 0x06, 0x00, 44, + 0x00, 0x0E, 0x00, 40, + // --- name + 0x00, 0x00, 0x00, 16, + 0x00, 0x03, 0x00, 5, + 'a', 'p', 'p', 'l', + 'e', + 0x00, 0x03, 0x00, 3, + 'p', 'i', 'e', + // --- keyid + 0x00, 0x01, 0x00, 4, + 0xa1, 0xa2, 0xa3, 0xa4, + // --- hash + 0x00, 0x02, 0x00, 8, + 0xb1, 0xb2, 0xb3, 0xb4, + 0xb5, 0xb6, 0xb7, 0xb8, + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxName *name = ccnxName_CreateFromCString("lci:/3=apple/3=pie"); + PARCBuffer *keyid = parcBuffer_Wrap(encoded, sizeof(encoded), 32, 36); + PARCBuffer *hash = parcBuffer_Wrap(encoded, sizeof(encoded), 40, 48); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary); + assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + // now test the 3 decoded fields + CCNxName *testName = ccnxTlvDictionary_GetName(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_NAME); + assertTrue(ccnxName_Equals(testName, name), "keynames do not match") + { + printf("Expected\n"); + ccnxName_Display(name, 3); + printf("Got\n"); + ccnxName_Display(testName, 3); + } + + PARCBuffer *testKeyid = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_KEYID); + assertTrue(parcBuffer_Equals(testKeyid, keyid), "keyid do not match") + { + printf("Expected\n"); + parcBuffer_Display(keyid, 3); + printf("Got\n"); + parcBuffer_Display(testKeyid, 3); + } + + PARCBuffer *testHash = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_OBJHASH); + assertTrue(parcBuffer_Equals(testHash, hash), "keyid do not match") + { + printf("Expected\n"); + parcBuffer_Display(hash, 3); + printf("Got\n"); + parcBuffer_Display(testHash, 3); + } + + parcBuffer_Release(&keyid); + parcBuffer_Release(&hash); + ccnxName_Release(&name); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(DecodeAlg, KeyName_Invalid) +{ + // link is missing the Name + uint8_t encoded[] = { + 0x00, 0x06, 0x00, 24, + 0x00, 0x0E, 0x00, 20, + // --- keyid + 0x00, 0x01, 0x00, 4, + 0xa1, 0xa2, 0xa3, 0xa4, + // --- hash + 0x00, 0x02, 0x00, 8, + 0xb1, 0xb2, 0xb3, 0xb4, + 0xb5, 0xb6, 0xb7, 0xb8, + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary); + assertFalse(success, "Should have failed decode as keyname is invalid"); + + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(DecodeAlg, SigTime) +{ + uint64_t sigtime = 0x1122334455667788ULL; + uint8_t encoded[] = { + 0x00, 0x06, 0x00, 12, + 0x00, 0x0F, 0x00, 8, + 0x11, 0x22, 0x33, 0x44, + 0x55, 0x66, 0x77, 0x88 + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1ValidationDecoder_DecodeAlg(decoder, dictionary); + assertTrue(success, "Failed ccnxCodecSchemaV1ValidationDecoder_DecodeAlg: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + uint64_t test = ccnxTlvDictionary_GetInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME); + assertTrue(test == sigtime, "Wrong sig time, expected %" PRIx64 ", got %" PRIx64, sigtime, test); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(DecodePayload) +{ + LONGBOW_RUN_TEST_CASE(DecodePayload, payload); + LONGBOW_RUN_TEST_CASE(DecodePayload, payload_zero); +} + +LONGBOW_TEST_FIXTURE_SETUP(DecodePayload) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(DecodePayload) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(DecodePayload, payload) +{ + uint8_t encoded[] = { + 0x00, 0x04, 0x00, 8, + 0x11, 0x22, 0x33, 0x44, + 0x55, 0x66, 0x77, 0x88 + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + + // the caller has already parsed the T and L, so we point to just payload + ccnxCodecTlvDecoder_Advance(decoder, 4); + + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1ValidationDecoder_DecodePayload(decoder, dictionary); + assertTrue(success, "Failed to decode a valid payload: %s", ccnxCodecError_ToString(ccnxCodecTlvDecoder_GetError(decoder))); + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 4, 12); + PARCBuffer *test = ccnxTlvDictionary_GetBuffer(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD); + assertTrue(parcBuffer_Equals(truth, test), "Buffer mismatch") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +LONGBOW_TEST_CASE(DecodePayload, payload_zero) +{ + uint8_t encoded[] = { + 0x00, 0x04, 0x00, 0, + }; + + PARCBuffer *buffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(buffer); + + // the caller has already parsed the T and L, so we point to just payload + ccnxCodecTlvDecoder_Advance(decoder, 4); + + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + bool success = ccnxCodecSchemaV1ValidationDecoder_DecodePayload(decoder, dictionary); + assertFalse(success, "Should have failed on 0-length payload"); + + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvDecoder_Destroy(&decoder); + parcBuffer_Release(&buffer); +} + +// ========================================================================= + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_ValidationDecoder); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationEncoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationEncoder.c new file mode 100755 index 00000000..8a4d951a --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_ValidationEncoder.c @@ -0,0 +1,565 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_ValidationEncoder.c" +#include +#include +#include +#include +#include + +#include "testrig_packetwrapper.c" + +#include + +#include +#include + +// ========================================================================= + +LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_ValidationDecoder) +{ + LONGBOW_RUN_TEST_FIXTURE(EncodeAlg); + LONGBOW_RUN_TEST_FIXTURE(EncodePayload); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_ValidationDecoder) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_ValidationDecoder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(EncodeAlg) +{ + LONGBOW_RUN_TEST_CASE(EncodeAlg, CRC32C); + LONGBOW_RUN_TEST_CASE(EncodeAlg, HMAC_SHA256); + LONGBOW_RUN_TEST_CASE(EncodeAlg, RSA_SHA256); + LONGBOW_RUN_TEST_CASE(EncodeAlg, DeduceFromSigner); + + LONGBOW_RUN_TEST_CASE(EncodeAlg, _encodeCertificate); + LONGBOW_RUN_TEST_CASE(EncodeAlg, _encodePublicKey); + LONGBOW_RUN_TEST_CASE(EncodeAlg, _encodeKeyId); + LONGBOW_RUN_TEST_CASE(EncodeAlg, _encodeKeyName); + LONGBOW_RUN_TEST_CASE(EncodeAlg, _encodeSignatureTime_Specified); + LONGBOW_RUN_TEST_CASE(EncodeAlg, _encodeSignatureTime_Generated); +} + +LONGBOW_TEST_FIXTURE_SETUP(EncodeAlg) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(EncodeAlg) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(EncodeAlg, CRC32C) +{ + CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvSuite = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C; + PARCCryptoSuite suite = PARCCryptoSuite_NULL_CRC32C; + + uint8_t encoded[] = { + 0x00, tlvSuite, 0x00, 0, + }; + + PARCBuffer *trueEncoded = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + ccnxTlvDictionary_PutInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE, suite); + + ssize_t length = ccnxCodecSchemaV1ValidationEncoder_EncodeAlg(encoder, dictionary); + assertFalse(length < 0, "Error on encoding: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(trueEncoded, test), "Wrong buffer") + { + printf("Expected\n"); + parcBuffer_Display(trueEncoded, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&test); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&trueEncoded); +} + +LONGBOW_TEST_CASE(EncodeAlg, HMAC_SHA256) +{ + CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvSuite = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_HmacSha256; + PARCCryptoSuite suite = PARCCryptoSuite_HMAC_SHA256; + + uint8_t encoded[] = { + 0x00, tlvSuite, 0x00, 0, + }; + + PARCBuffer *trueEncoded = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + ccnxTlvDictionary_PutInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE, suite); + + ssize_t length = ccnxCodecSchemaV1ValidationEncoder_EncodeAlg(encoder, dictionary); + assertFalse(length < 0, "Error on encoding: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(trueEncoded, test), "Wrong buffer") + { + printf("Expected\n"); + parcBuffer_Display(trueEncoded, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&test); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&trueEncoded); +} + +LONGBOW_TEST_CASE(EncodeAlg, RSA_SHA256) +{ + CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvSuite = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_RsaSha256; + PARCCryptoSuite suite = PARCCryptoSuite_RSA_SHA256; + + uint8_t encoded[] = { + 0x00, tlvSuite, 0x00, 0, + }; + + PARCBuffer *trueEncoded = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + ccnxTlvDictionary_PutInteger(dictionary, CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE, suite); + + ssize_t length = ccnxCodecSchemaV1ValidationEncoder_EncodeAlg(encoder, dictionary); + assertFalse(length < 0, "Error on encoding: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(trueEncoded, test), "Wrong buffer") + { + printf("Expected\n"); + parcBuffer_Display(trueEncoded, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&test); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&trueEncoded); +} + +LONGBOW_TEST_CASE(EncodeAlg, DeduceFromSigner) +{ + PARCSigner *signer = ccnxValidationCRC32C_CreateSigner(); + CCNxCodecSchemaV1TlvDictionary_CryptoSuite tlvsuite = CCNxCodecSchemaV1TlvDictionary_CryptoSuite_CRC32C; + + uint8_t encoded[] = { + 0x00, tlvsuite, 0x00, 0, + }; + + PARCBuffer *trueEncoded = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecTlvEncoder_SetSigner(encoder, signer); + + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + + ssize_t length = ccnxCodecSchemaV1ValidationEncoder_EncodeAlg(encoder, dictionary); + assertFalse(length < 0, "Error on encoding: %s", ccnxCodecError_ToString(ccnxCodecTlvEncoder_GetError(encoder))); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(trueEncoded, test), "Wrong buffer") + { + printf("Expected\n"); + parcBuffer_Display(trueEncoded, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&test); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&trueEncoded); + parcSigner_Release(&signer); +} + +// ======= + +LONGBOW_TEST_CASE(EncodeAlg, _encodeCertificate) +{ + uint8_t encoded[] = { + 0x00, 0x0C, 0x00, 6, + 0x0a, 0x0b, 0x0c, 0x0d, + 0x0e, 0x0f + }; + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + PARCBuffer *cert = parcBuffer_Wrap(encoded, sizeof(encoded), 4, sizeof(encoded)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + ccnxValidationFacadeV1_SetCertificate(dictionary, cert); + + ssize_t length = _encodeCertificate(encoder, dictionary); + assertTrue(length == sizeof(encoded), "Wrong length, expected %zu got %zd", sizeof(encoded), length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&test); + parcBuffer_Release(&truth); + parcBuffer_Release(&cert); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + + +LONGBOW_TEST_CASE(EncodeAlg, _encodePublicKey) +{ + uint8_t encoded[] = { + 0x00, 0x0B, 0x00, 6, + 0x0a, 0x0b, 0x0c, 0x0d, + 0x0e, 0x0f + }; + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + PARCBuffer *key = parcBuffer_Wrap(encoded, sizeof(encoded), 4, sizeof(encoded)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + ccnxValidationFacadeV1_SetPublicKey(dictionary, key); + + ssize_t length = _encodePublicKey(encoder, dictionary); + assertTrue(length == sizeof(encoded), "Wrong length, expected %zu got %zd", sizeof(encoded), length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&test); + parcBuffer_Release(&truth); + parcBuffer_Release(&key); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(EncodeAlg, _encodeKeyId) +{ + uint8_t encoded[] = { + 0x00, 0x09, 0x00, 6, + 0x0a, 0x0b, 0x0c, 0x0d, + 0x0e, 0x0f + }; + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + PARCBuffer *keyid = parcBuffer_Wrap(encoded, sizeof(encoded), 4, sizeof(encoded)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + ccnxValidationFacadeV1_SetKeyId(dictionary, keyid); + + ssize_t length = _encodeKeyId(encoder, dictionary); + assertTrue(length == sizeof(encoded), "Wrong length, expected %zu got %zd", sizeof(encoded), length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&test); + parcBuffer_Release(&truth); + parcBuffer_Release(&keyid); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(EncodeAlg, _encodeKeyName) +{ + uint8_t encoded[] = { + 0x00, 0x0E, 0x00, 40, + // --- name + 0x00, 0x00, 0x00, 16, + 0x00, 0x03, 0x00, 5, + 'a', 'p', 'p', 'l', + 'e', + 0x00, 0x03, 0x00, 3, + 'p', 'i', 'e', + // --- keyid + 0x00, 0x01, 0x00, 4, + 0xa1, 0xa2, 0xa3, 0xa4, + // --- hash + 0x00, 0x02, 0x00, 8, + 0xb1, 0xb2, 0xb3, 0xb4, + 0xb5, 0xb6, 0xb7, 0xb8, + }; + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + PARCBuffer *keyid = parcBuffer_Wrap(encoded, sizeof(encoded), 28, 32); + PARCBuffer *hash = parcBuffer_Wrap(encoded, sizeof(encoded), 36, 44); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + CCNxName *name = ccnxName_CreateFromCString("lci:/3=apple/3=pie"); + CCNxLink *link = ccnxLink_Create(name, keyid, hash); + + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + ccnxValidationFacadeV1_SetKeyName(dictionary, link); + + ssize_t length = _encodeKeyName(encoder, dictionary); + assertTrue(length == sizeof(encoded), "Wrong length, expected %zu got %zd", sizeof(encoded), length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&test); + parcBuffer_Release(&truth); + parcBuffer_Release(&keyid); + parcBuffer_Release(&hash); + ccnxName_Release(&name); + ccnxLink_Release(&link); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +LONGBOW_TEST_CASE(EncodeAlg, _encodeSignatureTime_Specified) +{ + uint64_t sigtime = 0x1122334455667788ULL; + uint8_t encoded[] = { + 0x00, 0x0F, 0x00, 8, + 0x11, 0x22, 0x33, 0x44, + 0x55, 0x66, 0x77, 0x88 + }; + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + ccnxValidationFacadeV1_SetSigningTime(dictionary, sigtime); + + ssize_t length = _encodeSignatureTime(encoder, dictionary); + assertTrue(length == sizeof(encoded), "Wrong length, expected %zu got %zd", sizeof(encoded), length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&test); + parcBuffer_Release(&truth); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +/* + * Do not specify a signing time, but rather set a Signer and let the code + * create the time on its own + */ +LONGBOW_TEST_CASE(EncodeAlg, _encodeSignatureTime_Generated) +{ + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + PARCBuffer *password = parcBuffer_Wrap("password", 8, 0, 8); + PARCSigner *signer = ccnxValidationHmacSha256_CreateSigner(password); + ccnxCodecTlvEncoder_SetSigner(encoder, signer); + parcSigner_Release(&signer); + + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + + ssize_t length = _encodeSignatureTime(encoder, dictionary); + assertTrue(length == 12, "Wrong length, expected 12, got %zd", length); + + parcBuffer_Release(&password); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +// ========================================================================= + +LONGBOW_TEST_FIXTURE(EncodePayload) +{ + LONGBOW_RUN_TEST_CASE(EncodePayload, payload_Specified); + LONGBOW_RUN_TEST_CASE(EncodePayload, payload_Generated); +} + +LONGBOW_TEST_FIXTURE_SETUP(EncodePayload) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(EncodePayload) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(EncodePayload, payload_Specified) +{ + uint8_t encoded[] = { + 0x11, 0x22, 0x33, 0x44, + 0x55, 0x66, 0x77, 0x88 + }; + + PARCBuffer *truth = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + ccnxValidationFacadeV1_SetPayload(dictionary, truth); + + ssize_t length = ccnxCodecSchemaV1ValidationEncoder_EncodePayload(encoder, dictionary); + assertTrue(length == sizeof(encoded), "Wrong length, expected %zu got %zd", sizeof(encoded), length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&test); + parcBuffer_Release(&truth); + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvEncoder_Destroy(&encoder); +} + +/* + * Put the guts of v1_interest_nameA_crc32c in to the encoding buffer and mark it + * as the signature block. Generate the CRC and make sure we got the right thing. + */ +LONGBOW_TEST_CASE(EncodePayload, payload_Generated) +{ + TlvExtent interestExtent = getTruthTableExtent(TRUTHTABLENAME(v1_interest_nameA_crc32c), V1_MANIFEST_INT_INTEREST); + + // This will test against the string (Interest, ValidationAlg, ValidationPayload) + PARCBuffer *truth = parcBuffer_Wrap(v1_interest_nameA_crc32c, + sizeof(v1_interest_nameA_crc32c), + interestExtent.offset, + sizeof(v1_interest_nameA_crc32c)); + + CCNxCodecTlvEncoder *encoder = ccnxCodecTlvEncoder_Create(); + PARCSigner *signer = ccnxValidationCRC32C_CreateSigner(); + ccnxCodecTlvEncoder_SetSigner(encoder, signer); + parcSigner_Release(&signer); + + // This will append from the beginning of the Interest message up to the end of the ValidationAlg + // This space is all marked as the "to-be-signed" section. + ccnxCodecTlvEncoder_MarkSignatureStart(encoder); + size_t signedInfoLenth = sizeof(v1_interest_nameA_crc32c) - 8 - interestExtent.offset; + ccnxCodecTlvEncoder_AppendRawArray(encoder, signedInfoLenth, v1_interest_nameA_crc32c + interestExtent.offset); + ccnxCodecTlvEncoder_MarkSignatureEnd(encoder); + + // add the validation payload container, then generate the signature + ccnxCodecTlvEncoder_AppendContainer(encoder, CCNxCodecSchemaV1Types_MessageType_ValidationPayload, 4); + + // Do the actual encoding. This will calculate the signature on the fly. + CCNxTlvDictionary *dictionary = ccnxCodecSchemaV1TlvDictionary_CreateContentObject(); + ssize_t length = ccnxCodecSchemaV1ValidationEncoder_EncodePayload(encoder, dictionary); + assertTrue(length == 4, "Wrong length, expected 4 got %zd", length); + + ccnxCodecTlvEncoder_Finalize(encoder); + PARCBuffer *test = ccnxCodecTlvEncoder_CreateBuffer(encoder); + + // Tests that we got the right signature (CRC32c in this case) + assertTrue(parcBuffer_Equals(truth, test), "Wrong buffer") + { + printf("Expected\n"); + parcBuffer_Display(truth, 3); + printf("Got\n"); + parcBuffer_Display(test, 3); + } + + ccnxTlvDictionary_Release(&dictionary); + ccnxCodecTlvEncoder_Destroy(&encoder); + parcBuffer_Release(&truth); + parcBuffer_Release(&test); +} + +// ========================================================================= + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_ValidationDecoder); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/testrig_encoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/testrig_encoder.c new file mode 100644 index 00000000..f925dd28 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/testrig_encoder.c @@ -0,0 +1,472 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ + +#include +#include + +#include +#include + + +#include +#include +#include + +#include + +/** + * Finds a row in the truthtable where bodyManifest is TRUE and the + * indexOrKey equals 'key'. + */ +TlvExtent +getTruthTableExtent(TruthTableEntry *ttentry, int key) +{ + for (int i = 0; ttentry[i].indexOrKey != T_INVALID; i++) { + if (ttentry[i].bodyManifest && ttentry[i].indexOrKey == key) { + return ttentry[i].extent; + } + } + return (TlvExtent) { 0, 0 }; +} + +/** + * Finds a row in the truthtable where bodyManifest is FALSE and the + * indexOrKey equals 'key'. + */ +TlvExtent +getTruthTableHeaderExtent(TruthTableEntry *ttentry, int key) +{ + for (int i = 0; ttentry[i].indexOrKey != T_INVALID; i++) { + if (!ttentry[i].bodyManifest && ttentry[i].indexOrKey == key) { + return ttentry[i].extent; + } + } + return (TlvExtent) { 0, 0 }; +} + +typedef struct test_data { + // the memory region extracted from a Truth Table entry + PARCBuffer *memoryRegion; + + CCNxCodecTlvEncoder *encoder; + CCNxTlvDictionary *dictionary; + + uint8_t *packet; + size_t packetLength; + TruthTableEntry *truthTable; + + // If the user creates one of these, we'll destroy it. + PARCSigner *signer; +} TestData; + +static SchemaV1ManifestContentObjectBody manifestContentObjectContainerArray[] = { + V1_MANIFEST_OBJ_CONTENTOBJECT, + V1_MANIFEST_OBJ_NAMEAUTH, + V1_MANIFEST_OBJ_ValidationPayload, + V1_MANIFEST_OBJ_KEYNAME, + V1_MANIFEST_OBJ_METADATA, + V1_MANIFEST_OBJ_ValidationAlg, + V1_MANIFEST_OBJ_BODYEND +}; + +static bool +isContentObjectContainer(SchemaV1ManifestContentObjectBody value) +{ + for (int i = 0; manifestContentObjectContainerArray[i] != V1_MANIFEST_OBJ_BODYEND; i++) { + if (value == manifestContentObjectContainerArray[i]) { + return true; + } + } + return false; +} + +/** + * The testdata truth tables were written with the tlv_1.0 array indicies, so we + * need to translate those old indicies to the new indicies. + */ +static CCNxCodecSchemaV1TlvDictionary_MessageFastArray +translateTestDataManifestToSchemaKey(SchemaV1ManifestContentObjectBody oldKey) +{ + switch (oldKey) { + case V1_MANIFEST_INT_NAME: + // fallthrough + case V1_MANIFEST_OBJ_NAME: + return CCNxCodecSchemaV1TlvDictionary_MessageFastArray_NAME; + + case V1_MANIFEST_OBJ_PAYLOAD: + return CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOAD; + + case V1_MANIFEST_OBJ_KEYID: + return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYID; + + case V1_MANIFEST_OBJ_CRYPTO_SUITE: + return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CRYPTO_SUITE; + + case V1_MANIFEST_OBJ_KEY: + return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEY; + + case V1_MANIFEST_OBJ_CERT: + return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_CERT; + + case V1_MANIFEST_OBJ_KEYNAME_NAME: + return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_NAME; + + case V1_MANIFEST_OBJ_KEYNAME_OBJHASH: + return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_KEYNAME_OBJHASH; + + case V1_MANIFEST_OBJ_OBJ_TYPE: + return CCNxCodecSchemaV1TlvDictionary_MessageFastArray_PAYLOADTYPE; + + case V1_MANIFEST_OBJ_SIGBITS: + return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_PAYLOAD; + + case V1_MANIFEST_OBJ_SigningTime: + return (CCNxCodecSchemaV1TlvDictionary_MessageFastArray) CCNxCodecSchemaV1TlvDictionary_ValidationFastArray_SIGNTIME; + + case V1_MANIFEST_OBJ_ENDSEGMENT: + return CCNxCodecSchemaV1TlvDictionary_MessageFastArray_ENDSEGMENT; + + case V1_MANIFEST_INT_KEYID: + return CCNxCodecSchemaV1TlvDictionary_MessageFastArray_KEYID_RESTRICTION; + + case V1_MANIFEST_INT_OBJHASH: + return CCNxCodecSchemaV1TlvDictionary_MessageFastArray_OBJHASH_RESTRICTION; + + default: + trapIllegalValue(oldKey, "Unexpected old manifest value: %d", oldKey); + break; + } + return -1; +} + +/** + * The testdata truth tables were written with the tlv_1.0 array indicies, so we + * need to translate those old indicies to the new indicies. + */ +static CCNxCodecSchemaV1TlvDictionary_HeadersFastArray +translateOldOptionalHeadersManifestToNewKey(CCNxTlvDictionary *packetDictionary, int oldKey) +{ + if (ccnxTlvDictionary_IsInterest(packetDictionary)) { + switch (oldKey) { + case V1_MANIFEST_INT_LIFETIME: + return CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime; + + case V1_MANIFEST_INT_E2EFRAG: + return CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_INTFRAG; + + default: + trapIllegalValue(oldKey, "Unexpected old manifest value: %d", oldKey); + break; + } + } else if (ccnxTlvDictionary_IsContentObject(packetDictionary)) { + switch (oldKey) { + case V1_MANIFEST_OBJ_E2EFRAG: + return CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_OBJFRAG; + + default: + trapIllegalValue(oldKey, "Unexpected old manifest value: %d", oldKey); + break; + } + } + return -1; +} + +static void +addBuffer(TestData *data, CCNxTlvDictionary *packetDictionary, size_t item_start, size_t item_end, uint32_t translatedKey) +{ + PARCBuffer *itemBuffer = parcBuffer_Wrap(data->packet, data->packetLength, item_start, item_end); + ccnxTlvDictionary_PutBuffer(packetDictionary, translatedKey, itemBuffer); + parcBuffer_Release(&itemBuffer); +} + +/** + * The extent should be treated like a CCNxName, so decode it and add it as a CCNxName. + */ +static void +addName(TestData *data, CCNxTlvDictionary *packetDictionary, size_t item_start, size_t item_end, uint32_t translatedKey) +{ + // we need to backup 4 bytes to the the TLV container + PARCBuffer *itemBuffer = parcBuffer_Wrap(data->packet, data->packetLength, item_start - 4, item_end); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(itemBuffer); + CCNxName *name = ccnxCodecSchemaV1NameCodec_Decode(decoder, CCNxCodecSchemaV1Types_CCNxMessage_Name); + ccnxCodecTlvDecoder_Destroy(&decoder); + + ccnxTlvDictionary_PutName(packetDictionary, translatedKey, name); + ccnxName_Release(&name); + parcBuffer_Release(&itemBuffer); +} + + +/** + * Called on the body of a content object, does not include the fixed header or optional headers + * + * <#Paragraphs Of Explanation#> + * + * @param [<#in out in,out#>] <#name#> <#description#> + * + * @return <#value#> <#explanation#> + * + * Example: + * @code + * <#example#> + * @endcode + */ +static void +buildContentObjectDictionary(TestData *data, CCNxTlvDictionary *packetDictionary, TlvExtent extent) +{ + size_t start = extent.offset; + size_t end = start + extent.length; + + ccnxTlvDictionary_SetMessageType_ContentObject(packetDictionary, CCNxTlvDictionary_SchemaVersion_V1); + + for (int i = 0; data->truthTable[i].indexOrKey != T_INVALID; i++) { + size_t item_start = data->truthTable[i].extent.offset; + size_t item_end = item_start + data->truthTable[i].extent.length; + + // Is this item included in the given extent? + if (start < item_start && item_end <= end) { + // Is it a container or a nested dictionary? This check only applies to a ContentObject + if (!isContentObjectContainer(data->truthTable[i].indexOrKey)) { + uint32_t translatedKey = translateTestDataManifestToSchemaKey(data->truthTable[i].indexOrKey); + + if (data->truthTable[i].indexOrKey == V1_MANIFEST_OBJ_NAME) { + addName(data, packetDictionary, item_start, item_end, translatedKey); + } else { + addBuffer(data, packetDictionary, item_start, item_end, translatedKey); + } + } + } + } +} + +static void +buildInterestDictionary(TestData *data, CCNxTlvDictionary *packetDictionary, TlvExtent extent) +{ + size_t start = extent.offset; + size_t end = start + extent.length; + + ccnxTlvDictionary_SetMessageType_Interest(packetDictionary, CCNxTlvDictionary_SchemaVersion_V1); + + for (int i = 0; data->truthTable[i].indexOrKey != T_INVALID && data->truthTable[i].bodyManifest; i++) { + size_t item_start = data->truthTable[i].extent.offset; + size_t item_end = item_start + data->truthTable[i].extent.length; + + // Is this item included in the given extent? + if (start < item_start && item_end <= end) { + uint32_t translatedKey = translateTestDataManifestToSchemaKey(data->truthTable[i].indexOrKey); + + if (data->truthTable[i].indexOrKey == V1_MANIFEST_INT_NAME) { + addName(data, packetDictionary, item_start, item_end, translatedKey); + } else { + addBuffer(data, packetDictionary, item_start, item_end, translatedKey); + } + } + } +} + +/** + * Make a dictionary entry for everything inside the selected extent, not including it + * + * Use the truth table and for each listed item whose extent is within the given extent, + * add a dictionary entry + * + * @param [<#in out in,out#>] <#name#> <#description#> + * + * @return <#value#> <#explanation#> + * + * Example: + * @code + * <#example#> + * @endcode + */ +static void +buildMessageDictionary(TestData *data, CCNxTlvDictionary *dictionary, TlvExtent extent) +{ + uint8_t packetType = data->packet[1]; + switch (packetType) { + case CCNxCodecSchemaV1Types_PacketType_Interest: + buildInterestDictionary(data, dictionary, extent); + break; + + case CCNxCodecSchemaV1Types_PacketType_ContentObject: + buildContentObjectDictionary(data, dictionary, extent); + break; + + case CCNxCodecSchemaV1Types_PacketType_InterestReturn: + trapNotImplemented("not implemented"); + break; + + default: + trapIllegalValue(packetType, "Unknown PacketType"); + } +} + +static void +buildSetDictionaryType(TestData *data, CCNxTlvDictionary *dictionary) +{ + uint8_t packetType = data->packet[1]; + switch (packetType) { + case CCNxCodecSchemaV1Types_PacketType_Interest: + ccnxTlvDictionary_SetMessageType_Interest(dictionary, CCNxTlvDictionary_SchemaVersion_V1); + break; + + case CCNxCodecSchemaV1Types_PacketType_ContentObject: + ccnxTlvDictionary_SetMessageType_ContentObject(dictionary, CCNxTlvDictionary_SchemaVersion_V1); + break; + + case CCNxCodecSchemaV1Types_PacketType_InterestReturn: + trapNotImplemented("not implemented"); + break; + + default: + trapIllegalValue(packetType, "Unknown PacketType"); + } +} + +/** + * Builds a packet dictionary with OptionalHeaders and Message + * + * <#Paragraphs Of Explanation#> + * + * @param [<#in out in,out#>] <#name#> <#description#> + * + * @return <#value#> <#explanation#> + * + * Example: + * @code + * <#example#> + * @endcode + */ +static void +buildPacketDictionary(TestData *data, CCNxTlvDictionary *packetDictionary, TlvExtent extent) +{ + buildSetDictionaryType(data, packetDictionary); + + size_t start = extent.offset; + size_t end = start + extent.length; + + for (int i = 0; data->truthTable[i].indexOrKey != T_INVALID; i++) { + size_t item_start = data->truthTable[i].extent.offset; + size_t item_end = item_start + data->truthTable[i].extent.length; + + // Is this item included in the given extent? + if (start < item_start && item_end <= end) { + if (data->truthTable[i].bodyManifest == false) { + PARCBuffer *itemBuffer = parcBuffer_Wrap(data->packet, data->packetLength, item_start, item_end); + uint32_t translatedKey = translateOldOptionalHeadersManifestToNewKey(packetDictionary, data->truthTable[i].indexOrKey); + ccnxTlvDictionary_PutBuffer(packetDictionary, translatedKey, itemBuffer); + parcBuffer_Release(&itemBuffer); + } else { + buildMessageDictionary(data, packetDictionary, data->truthTable[i].extent); + } + + // advance start to skip over whatever we just included + start = item_end; + } + } +} + +/** + * Wraps the given (packet, length) in a PARCBuffer where the data->memoryRegion member will be set + * to a given extent within that PARCBuffer. The function will locate the truthTableKey in the truthTable and + * use it's extent as the bounds for the wrapped packet. + * + * For example, if the key V1_INT_NAME has the extent {32, 12}, then the PARCBuffer will wrap the packet + * memory and it will have and offset of 32 and a limit of 12. + */ +TestData * +commonSetup(uint8_t *packet, size_t length, TruthTableEntry *truthTable, int truthTableKey) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + + TlvExtent extent = getTruthTableExtent(truthTable, truthTableKey); + + data->memoryRegion = parcBuffer_Wrap(packet, length, extent.offset, extent.offset + extent.length); + data->encoder = ccnxCodecTlvEncoder_Create(); + ccnxCodecTlvEncoder_Initialize(data->encoder); + + // use the content object lenghts, they are the largest + data->dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END); + + data->packet = packet; + data->packetLength = length; + data->truthTable = truthTable; + + buildMessageDictionary(data, data->dictionary, extent); + return data; +} + +/** + * Wraps a packet like commonSetup, but will do the whole packet including headers not just + * the message body. This is used by the PacketEncoder tests. + */ +TestData * +testrigencoder_CommonSetupWholePacket(uint8_t *packet, size_t length, TruthTableEntry *truthTable) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + + data->memoryRegion = parcBuffer_Wrap(packet, length, 0, length); + data->encoder = ccnxCodecTlvEncoder_Create(); + + // use the content object lenghts, they are the largest + data->dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END); + + data->packet = packet; + data->packetLength = length; + data->truthTable = truthTable; + + buildPacketDictionary(data, data->dictionary, (TlvExtent) { 0, length }); + + return data; +} + +void +testrigencoder_CommonTeardown(TestData *data) +{ + ccnxTlvDictionary_Release(&data->dictionary); + ccnxCodecTlvEncoder_Destroy(&data->encoder); + parcBuffer_Release(&data->memoryRegion); + + if (data->signer) { + parcSigner_Release(&data->signer); + } + + parcMemory_Deallocate((void **) &data); +} + +void +testDisplayIoVec(CCNxCodecEncodingBufferIOVec *vec) +{ + printf("Display iovec %p with %d elements\n", (void *) vec, vec->iovcnt); + size_t totalLength = 0; + for (int i = 0; i < vec->iovcnt; i++) { + totalLength += vec->iov[i].iov_len; + printf(" %3d: base %p length %4zu total length %4zu\n", i, (void *) vec->iov[i].iov_base, vec->iov[i].iov_len, totalLength); + } + printf("done\n\n"); +} + +void +testExecute(TestData *data, ssize_t (*encoderFunction)(CCNxCodecTlvEncoder *encoder, CCNxTlvDictionary *dictionary)) +{ + encoderFunction(data->encoder, data->dictionary); + testCompareEncoderToBuffer(data->encoder, data->memoryRegion); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/testrig_packetwrapper.c b/libccnx-common/ccnx/common/codec/schema_v1/test/testrig_packetwrapper.c new file mode 100644 index 00000000..9a213b13 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/testrig_packetwrapper.c @@ -0,0 +1,516 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This test rig sets up test data to wrap a packet and prepare it for use in a decoder + * + * A hand-encoded packet, such as from the testdata directory can be passed to commonSetup and then + * run automated tests against it based on its manifest. + * + * Example: + * @code + * + * static uint8_t object_nameC_keyid3_protoinfo[] = { + * 0x00, 0x02, 0x00, 110, // ver = 0, type = object, length = 110 + * 0x00, 0x00, 0x00, 5, // reserved = 0, header length = 5 + * // --------------------------- + * // snip middle of packet + * // ------------------------ + * // byte offset 76 + * 0x00, 0x03, 0x00, 26, // Protocol Information, length = 26 + * 0x00, 0x0B, 0x00, 17, // Object Metadata, length = 17 + * 0x00, 0x0C, 0x00, 0x01, // Object Type, length = 1 + * 0x04, // LINK + * 0x00, 0x0D, 0x00, 8, // Creation Time + * 0x00, 0x00, 0x01, 0x43, // 1,388,534,400,000 msec + * 0x4B, 0x19, 0x84, 0x00, + * 0x00, 0x19, 0x00, 0x01, // EndSegment, length = 1 + * 42, + * // --------------------------- + * // snip to end of packet + * // --------------------------- + * }; + * + * static TruthTableEntry TRUTHTABLENAME(object_nameC_keyid3_protoinfo)[] = { + * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_METADATA, .bodyManifest=true, .extent = { 80, 17} }, + * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_OBJ_TYPE, .bodyManifest=true, .extent = { 84, 1} }, + * { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0} }, + * }; + * + * LONGBOW_TEST_FIXTURE_SETUP(Global) + * { + * commonSetup(testCase, object_nameC_keyid3_protoinfo, sizeof(object_nameC_keyid3_protoinfo), object_nameC_keyid3_protoinfo_truthTableEntries, MANIFEST_OBJ_METADATA); + * return LONGBOW_STATUS_SUCCEEDED; + * } + * + * LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV0ProtoInfo_GetEndSegmentNumber) + * { + * testInt32Getter(testCase, MANIFEST_OBJ_OBJ_TYPE, ccnxCodecSchemaV0Metadata_Decode, ccnxCodecSchemaV0Metadata_GetContentType); + * } + * + * @endcode + * + */ + +#include +#include + +#include +#include +#include +#include + +/** + * Finds a row in the truthtable where bodyManifest is TRUE and the + * indexOrKey equals 'key'. + */ +TlvExtent +getTruthTableExtent(TruthTableEntry *ttentry, int key) +{ + for (int i = 0; ttentry[i].indexOrKey != T_INVALID; i++) { + if (ttentry[i].bodyManifest && ttentry[i].indexOrKey == key) { + return ttentry[i].extent; + } + } + return (TlvExtent) { 0, 0 }; +} + +/** + * Finds a row in the truthtable where bodyManifest is FALSE and the + * indexOrKey equals 'key'. + */ +TlvExtent +getTruthTableHeaderExtent(TruthTableEntry *ttentry, int key) +{ + for (int i = 0; ttentry[i].indexOrKey != T_INVALID; i++) { + if (!ttentry[i].bodyManifest && ttentry[i].indexOrKey == key) { + return ttentry[i].extent; + } + } + return (TlvExtent) { 0, 0 }; +} + +typedef struct test_data { + PARCBuffer *interest; + CCNxCodecTlvDecoder *decoder; + CCNxTlvDictionary *dictionary; + + uint8_t *packet; + size_t packetLength; + TruthTableEntry *truthTable; +} TestData; + +/** + * Wraps the given (packet, length) in a PARCBuffer where the data->memoryRegion member will be set + * to a given extent within that PARCBuffer. The function will locate the truthTableKey in the truthTable and + * use it's extent as the bounds for the wrapped packet. + * + * For example, if the key V1_INT_NAME has the extent {32, 12}, then the PARCBuffer will wrap the packet + * memory and it will have and offset of 32, position 0, and a limit of 12. + */ +TestData * +commonSetup(uint8_t *packet, size_t length, TruthTableEntry *truthTable, int truthTableKey) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + + TlvExtent extent = getTruthTableExtent(truthTable, truthTableKey); + + data->interest = parcBuffer_Wrap(packet, length, extent.offset, extent.offset + extent.length); + data->decoder = ccnxCodecTlvDecoder_Create(data->interest); + + // content objects have more fields than interests, so use that + data->dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END); + + data->packet = packet; + data->packetLength = length; + data->truthTable = truthTable; + return data; +} + +void +commonSetupWholePacket(LongBowTestCase *testCase, uint8_t *packet, size_t length, TruthTableEntry *truthTable) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + + data->interest = parcBuffer_Wrap(packet, length, 0, length); + data->decoder = ccnxCodecTlvDecoder_Create(data->interest); + data->dictionary = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END); + + data->packet = packet; + data->packetLength = length; + data->truthTable = truthTable; + + longBowTestCase_SetClipBoardData(testCase, data); +} + +void +commonTeardown(TestData *data) +{ + ccnxTlvDictionary_Release(&data->dictionary); + ccnxCodecTlvDecoder_Destroy(&data->decoder); + parcBuffer_Release(&data->interest); + parcMemory_Deallocate((void **) &data); +} + +/** + * Tests that an int32_t getter returns the right value + * + * Given a packet byte array and a truth table (see transport/test_tools/testdata/testrig_truthTable.h), + * check that the buffer the decoder parsed is the right buffer. + * + * The function will run the specified decoder on the TestData's packet and put the results in the + * TestData's dictionary. It will then call the specified getter and make sure its value is equal + * to the truth table's value. + * + * The function will assert if the test fails. + * + * @param [in] testCase Used to get the clipboard data with the TestData member + * @param [in] truthTableKey Used to match the .indexOrKey truth table member + * @param [in] containerDecoder The decoder to use on the packet contained in TestData + * @param [in] getter The function to call to fetch a decoded value + * + * Example: + * @code + * + * static uint8_t object_nameC_keyid3_protoinfo[] = { + * 0x00, 0x02, 0x00, 110, // ver = 0, type = object, length = 110 + * 0x00, 0x00, 0x00, 5, // reserved = 0, header length = 5 + * // --------------------------- + * // snip middle of packet + * // ------------------------ + * // byte offset 76 + * 0x00, 0x03, 0x00, 26, // Protocol Information, length = 26 + * 0x00, 0x0B, 0x00, 17, // Object Metadata, length = 17 + * 0x00, 0x0C, 0x00, 0x01, // Object Type, length = 1 + * 0x04, // LINK + * 0x00, 0x0D, 0x00, 8, // Creation Time + * 0x00, 0x00, 0x01, 0x43, // 1,388,534,400,000 msec + * 0x4B, 0x19, 0x84, 0x00, + * 0x00, 0x19, 0x00, 0x01, // EndSegment, length = 1 + * 42, + * // --------------------------- + * // snip to end of packet + * // --------------------------- + * }; + * + * static TruthTableEntry TRUTHTABLENAME(object_nameC_keyid3_protoinfo)[] = { + * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_METADATA, .bodyManifest=true, .extent = { 80, 17} }, + * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_OBJ_TYPE, .bodyManifest=true, .extent = { 84, 1} }, + * { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0} }, + * }; + * + * LONGBOW_TEST_FIXTURE_SETUP(Global) + * { + * commonSetup(testCase, object_nameC_keyid3_protoinfo, sizeof(object_nameC_keyid3_protoinfo), object_nameC_keyid3_protoinfo_truthTableEntries, MANIFEST_OBJ_METADATA); + * return LONGBOW_STATUS_SUCCEEDED; + * } + * + * LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV0ProtoInfo_GetEndSegmentNumber) + * { + * testInt32Getter(testCase, MANIFEST_OBJ_OBJ_TYPE, ccnxCodecSchemaV0Metadata_Decode, ccnxCodecSchemaV0Metadata_GetContentType); + * } + * * @endcode + */ +void +testInt32Getter(LongBowTestCase *testCase, int truthTableKey, bool containerDecoder(CCNxCodecTlvDecoder *, CCNxTlvDictionary *), + int32_t (*getter)(CCNxTlvDictionary *)) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + containerDecoder(data->decoder, data->dictionary); + int32_t testvalue = getter(data->dictionary); + + // look up the true name buffer from the truth table + TlvExtent extent = getTruthTableExtent(data->truthTable, truthTableKey); + PARCBuffer *truthbuffer = parcBuffer_Wrap(data->packet, data->packetLength, extent.offset, extent.offset + extent.length); + uint64_t truthvalue = -2; + ccnxCodecTlvUtilities_GetVarInt(truthbuffer, parcBuffer_Remaining(truthbuffer), &truthvalue); + + parcBuffer_Release(&truthbuffer); + + assertTrue(testvalue == (int32_t) truthvalue, "Wrong value, got %d expected %d", testvalue, (int32_t) truthvalue); +} + +/** + * Tests that an int64_t getter returns the right value + * + * Given a packet byte array and a truth table (see transport/test_tools/testdata/testrig_truthTable.h), + * check that the buffer the decoder parsed is the right buffer. + * + * The function will run the specified decoder on the TestData's packet and put the results in the + * TestData's dictionary. It will then call the specified getter and make sure its value is equal + * to the truth table's value. + * + * The function will assert if the test fails. + * + * @param [in] testCase Used to get the clipboard data with the TestData member + * @param [in] truthTableKey Used to match the .indexOrKey truth table member + * @param [in] containerDecoder The decoder to use on the packet contained in TestData + * @param [in] getter The function to call to fetch a decoded value + * + * Example: + * @code + * + * static uint8_t object_nameC_keyid3_protoinfo[] = { + * 0x00, 0x02, 0x00, 110, // ver = 0, type = object, length = 110 + * 0x00, 0x00, 0x00, 5, // reserved = 0, header length = 5 + * // --------------------------- + * // snip middle of packet + * // ------------------------ + * // byte offset 76 + * 0x00, 0x03, 0x00, 26, // Protocol Information, length = 26 + * 0x00, 0x0B, 0x00, 17, // Object Metadata, length = 17 + * 0x00, 0x0C, 0x00, 0x01, // Object Type, length = 1 + * 0x04, // LINK + * 0x00, 0x0D, 0x00, 8, // Creation Time + * 0x00, 0x00, 0x01, 0x43, // 1,388,534,400,000 msec + * 0x4B, 0x19, 0x84, 0x00, + * 0x00, 0x19, 0x00, 0x01, // EndSegment, length = 1 + * 42, + * // --------------------------- + * // snip to end of packet + * // --------------------------- + * }; + * + * static TruthTableEntry TRUTHTABLENAME(object_nameC_keyid3_protoinfo)[] = { + * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_PROTOINFO, .bodyManifest=true, .extent = { 76, 26} }, + * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_ENDSEGMENT, .bodyManifest=true, .extent = {101, 1} }, + * { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0} }, + * }; + * + * LONGBOW_TEST_FIXTURE_SETUP(Global) + * { + * commonSetup(testCase, object_nameC_keyid3_protoinfo, sizeof(object_nameC_keyid3_protoinfo), object_nameC_keyid3_protoinfo_truthTableEntries, MANIFEST_OBJ_PROTOINFO); + * return LONGBOW_STATUS_SUCCEEDED; + * } + * + * LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV0ProtoInfo_GetEndSegmentNumber) + * { + * testInt64Getter(testCase, MANIFEST_OBJ_ENDSEGMENT, ccnxCodecSchemaV0ProtoInfo_Decode, ccnxCodecSchemaV0ProtoInfo_GetEndSegmentNumber); + * } + * + * @endcode + */ +void +testInt64Getter(TestData *data, int truthTableKey, bool containerDecoder(CCNxCodecTlvDecoder *, CCNxTlvDictionary *), + int64_t (*getter)(CCNxTlvDictionary *)) +{ + containerDecoder(data->decoder, data->dictionary); + int64_t testvalue = getter(data->dictionary); + + // look up the true name buffer from the truth table + TlvExtent extent = getTruthTableExtent(data->truthTable, truthTableKey); + PARCBuffer *truthbuffer = parcBuffer_Wrap(data->packet, data->packetLength, extent.offset, extent.offset + extent.length); + uint64_t truthvalue = -2; + ccnxCodecTlvUtilities_GetVarInt(truthbuffer, parcBuffer_Remaining(truthbuffer), &truthvalue); + + parcBuffer_Release(&truthbuffer); + + assertTrue(testvalue == (int64_t) truthvalue, "Wrong value, got %" PRId64 " expected %" PRId64, testvalue, (int64_t) truthvalue); +} + +/** + * Tests that a buffer getter returns the right buffer + * + * Given a packet byte array and a truth table (see transport/test_tools/testdata/testrig_truthTable.h), + * check that the buffer the decoder parsed is the right buffer. + * + * The function will run the specified decoder on the TestData's packet and put the results in the + * TestData's dictionary. It will then call the specified getter and make sure its value is equal + * to the truth table's value. + * + * The function will assert if the test fails. + * + * @param [in] testCase Used to get the clipboard data with the TestData member + * @param [in] truthTableKey Used to match the .indexOrKey truth table member + * @param [in] containerDecoder The decoder to use on the packet contained in TestData + * @param [in] getter The function to call to fetch a decoded value + * + * Example: + * @code + * + * static uint8_t object_nameC_keyid3_protoinfo[] = { + * 0x00, 0x02, 0x00, 110, // ver = 0, type = object, length = 110 + * 0x00, 0x00, 0x00, 5, // reserved = 0, header length = 5 + * // --------------------------- + * // snip middle of packet + * // ------------------------ + * // byte offset = 117 + * 0x00, 0x05, 0x00, 0x06, // signature block, length = 6 + * 0x00, 0x0E, 0x00, 0x02, // signature bits, length = 2 + * 0xBE, 0xEF // value = 0xBEEF + * }; + * + * static TruthTableEntry TRUTHTABLENAME(object_nameC_keyid3_protoinfo)[] = { + * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_SIGBLOCK, .bodyManifest=true, .extent = {117, 6} }, + * { .wellKnownType = true, .indexOrKey = MANIFEST_OBJ_SIGBITS, .bodyManifest=true, .extent = {121, 2} }, + * { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0} }, + * }; + * + * LONGBOW_TEST_FIXTURE_SETUP(Global) + * { + * commonSetup(testCase, object_nameC_keyid3_protoinfo, sizeof(object_nameC_keyid3_protoinfo), object_nameC_keyid3_protoinfo_truthTableEntries, MANIFEST_OBJ_SIGBLOCK); + * return LONGBOW_STATUS_SUCCEEDED; + * } + * + * LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV0SigBlock_GetSignatureBits) + * { + * testBufferGetter(testCase, MANIFEST_OBJ_SIGBITS, ccnxCodecSchemaV0SigBlock_Decode, ccnxCodecSchemaV0SigBlock_GetSignatureBits); + * } + * + * @endcode + */ +void +testBufferGetter(TestData *data, int truthTableKey, bool containerDecoder(CCNxCodecTlvDecoder *, CCNxTlvDictionary *), + PARCBuffer *(*getter)(const CCNxTlvDictionary *)) +{ + containerDecoder(data->decoder, data->dictionary); + PARCBuffer *test = getter(data->dictionary); + + // look up the true name buffer from the truth table + TlvExtent extent = getTruthTableExtent(data->truthTable, truthTableKey); + PARCBuffer *truth = parcBuffer_Wrap(data->packet, data->packetLength, extent.offset, extent.offset + extent.length); + + assertTrue(parcBuffer_Equals(test, truth), "Buffers not equal") + { + printf("Expected:\n"); + parcBuffer_Display(truth, 3); + printf("Got:\n"); + parcBuffer_Display(test, 3); + } + + parcBuffer_Release(&truth); +} + +void +testHashGetter(TestData *data, int truthTableKey, bool containerDecoder(CCNxCodecTlvDecoder *, CCNxTlvDictionary *), + PARCCryptoHash *(*getter)(CCNxTlvDictionary *)) +{ + containerDecoder(data->decoder, data->dictionary); + PARCCryptoHash *testHash = getter(data->dictionary); + + // look up the true hash buffer from the truth table + TlvExtent extent = getTruthTableExtent(data->truthTable, truthTableKey); + PARCBuffer *truthBuffer = parcBuffer_Wrap(data->packet, data->packetLength, extent.offset, extent.offset + extent.length); + + // decode the hash value + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(truthBuffer); + PARCCryptoHash *truthHash = ccnxCodecSchemaV1HashCodec_DecodeValue(decoder, extent.length); + ccnxCodecTlvDecoder_Destroy(&decoder); + + // compare the decoded value against the expected value + assertTrue(parcCryptoHash_Equals(testHash, truthHash), "Hashes not equal") + { + printf("Expected:\n"); + printf(" %s\n", parcBuffer_ToHexString(parcCryptoHash_GetDigest(truthHash))); + printf("Got:\n"); + printf(" %s\n", parcBuffer_ToHexString(parcCryptoHash_GetDigest(testHash))); + } + + parcCryptoHash_Release(&truthHash); + parcBuffer_Release(&truthBuffer); +} + +void +testNameGetter(TestData *data, int truthTableKey, bool containerDecoder(CCNxCodecTlvDecoder *, CCNxTlvDictionary *), + CCNxName *(*getter)(CCNxTlvDictionary *)) +{ + containerDecoder(data->decoder, data->dictionary); + CCNxName *test = getter(data->dictionary); + + // look up the true name buffer from the truth table + TlvExtent extent = getTruthTableExtent(data->truthTable, truthTableKey); + + // we need to backup 4 bytes to get the TLV container + PARCBuffer *truthBuffer = + parcBuffer_Wrap(data->packet, data->packetLength, extent.offset - 4, extent.offset + extent.length); + + CCNxCodecTlvDecoder *decoder = ccnxCodecTlvDecoder_Create(truthBuffer); + CCNxName *truthName = ccnxCodecSchemaV1NameCodec_Decode(decoder, CCNxCodecSchemaV1Types_CCNxMessage_Name); + ccnxCodecTlvDecoder_Destroy(&decoder); + + assertTrue(ccnxName_Equals(test, truthName), "Names not equal") + { + printf("Expected:\n"); + ccnxName_Display(truthName, 3); + printf("Got:\n"); + ccnxName_Display(test, 3); + } + + ccnxName_Release(&truthName); + parcBuffer_Release(&truthBuffer); +} + +void +testMissingInt32Getter(LongBowTestCase *testCase, int32_t (*getter)(CCNxTlvDictionary *)) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + int32_t test = getter(data->dictionary); + + assertTrue(test == -1, "Wrong value, got %d expected %d", test, -1); +} + +/** + * Tried to retrieve execute the getter on the dictionary and ensures that + * the field is missing. + */ +void +testMissingInt64Getter(LongBowTestCase *testCase, int64_t (*getter)(CCNxTlvDictionary *)) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + int64_t test = getter(data->dictionary); + + assertTrue(test == -1, "Wrong value, got %" PRId64 " expected %d", test, -1); +} + +/** + * Tried to retrieve execute the getter on the dictionary and ensures that + * the field is missing. + */ +void +testMissingNameGetter(LongBowTestCase *testCase, CCNxName *(*getter)(CCNxTlvDictionary *)) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxName *test = getter(data->dictionary); + + assertNull(test, "Should have gotten null for missing field, got %p", (void *) test); +} + +/** + * Tried to retrieve execute the getter on the dictionary and ensures that + * the field is missing. + */ +void +testMissingBufferGetter(LongBowTestCase *testCase, PARCBuffer *(*getter)(CCNxTlvDictionary *)) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *test = getter(data->dictionary); + + assertNull(test, "Should have gotten null for missing field, got %p", (void *) test); +} + +/** + * Tried to retrieve execute the getter on the dictionary and ensures that + * the field is missing. + */ +void +testMissingDictionaryGetter(LongBowTestCase *testCase, CCNxTlvDictionary *(*getter)(CCNxTlvDictionary *)) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxTlvDictionary *test = getter(data->dictionary); + + assertNull(test, "Should have gotten null for missing field, got %p", (void *) test); +} diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/CMakeLists.txt b/libccnx-common/ccnx/common/codec/schema_v1/testdata/CMakeLists.txt new file mode 100644 index 00000000..c5c70ce4 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/CMakeLists.txt @@ -0,0 +1,27 @@ +# Enable gcov output for the tests +add_definitions(--coverage) +set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage") + +set(TestsExpectedToPass + test_ccnxCodecSchemaV1_CryptoSuite + test_ccnxCodecSchemaV1_FixedHeaderDecoder + test_ccnxCodecSchemaV1_FixedHeaderEncoder + test_ccnxCodecSchemaV1_LinkCodec + test_ccnxCodecSchemaV1_MessageDecoder + test_ccnxCodecSchemaV1_MessageEncoder + test_ccnxCodecSchemaV1_NameCodec + test_ccnxCodecSchemaV1_NameSegmentCodec + test_ccnxCodecSchemaV1_OptionalHeadersDecoder + test_ccnxCodecSchemaV1_OptionalHeadersEncoder + test_ccnxCodecSchemaV1_PacketDecoder + test_ccnxCodecSchemaV1_PacketEncoder + test_ccnxCodecSchemaV1_TlvDictionary + test_ccnxCodecSchemaV1_ValidationDecoder + test_ccnxCodecSchemaV1_ValidationEncoder +) + + +foreach(test ${TestsExpectedToPass}) + AddTest(${test}) +endforeach() + diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_CPISchema.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_CPISchema.h new file mode 100644 index 00000000..70899d13 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_CPISchema.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Defines the truthtable manifest constants used by the version 1 test vectors. + * + */ + +/** + * Schema for Control Plane Interface packets. These packets are a TLV wrapping + * the control JSON. + * + * Example: + * @code + * <#example#> + * @endcode + */ + +#ifndef Libccnx_v1_CPISchema_h +#define Libccnx_v1_CPISchema_h + +#include + +// ----------------------------------------------------- +// these are the array indicies used to store the TlvExtent for the item +typedef enum { + V1_MANIFEST_CPI_PAYLOAD = 0, + V1_MANIFEST_CPI_SIGBITS = 5, // the payload of the signature + V1_MANIFEST_CPI_ValidationAlg = 6, // start of validation algorithm + V1_MANIFEST_CPI_ValidationPayload = 7, // start of validation payload + V1_MANIFEST_CPI_BODYEND = 8 +} V1_ManifestCPIBody; + +typedef enum { + V1_MANIFEST_CPI_HEADEND = 0 +} V1_ManifestCPIHeaders; + +#endif // Libccnx_tlv_CPISchema_h diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_ContentObjectSchema.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_ContentObjectSchema.h new file mode 100644 index 00000000..cb59d937 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_ContentObjectSchema.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This is from the version 1 codec. All the test vectors in this directory (e.g. interest_nameA.h) + * are encoded using these constants. These are no longer used for any functional code, only to interpret the test vectors. + * + */ + +#ifndef Libccnx_v1_ContentObjectSchema_h +#define Libccnx_v1_ContentObjectSchema_h + +#include + +#define T_CONTENTOBJECT 0x0002 + +// these are the array indicies used to store the TlvExtent for the item +typedef enum { + // top level entities + V1_MANIFEST_OBJ_NAME = 0, + V1_MANIFEST_OBJ_CONTENTOBJECT = 1, // the top container + V1_MANIFEST_OBJ_NAMEAUTH = 2, + V1_MANIFEST_OBJ_PAYLOADTYPE = 3, + V1_MANIFEST_OBJ_PAYLOAD = 4, + V1_MANIFEST_OBJ_SIGBITS = 5, + + // inside the name authenticator + V1_MANIFEST_OBJ_KEYID = 6, + V1_MANIFEST_OBJ_CRYPTO_SUITE = 7, + V1_MANIFEST_OBJ_KEY = 8, + V1_MANIFEST_OBJ_CERT = 9, + V1_MANIFEST_OBJ_KEYNAME = 10, + V1_MANIFEST_OBJ_KEYNAME_NAME = 11, + V1_MANIFEST_OBJ_KEYNAME_OBJHASH = 12, + + // inside the protocol information + V1_MANIFEST_OBJ_METADATA = 13, + + // inside metadata + V1_MANIFEST_OBJ_OBJ_TYPE = 14, + V1_MANIFEST_OBJ_CREATE_TIME = 15, + V1_MANIFEST_OBJ_EXPIRY_TIME = 16, + + // inside signature block + V1_MANIFEST_OBJ_ValidationPayload = 17, + V1_MANIFEST_OBJ_ENDSEGMENT = 18, + V1_MANIFEST_OBJ_PUBKEY = 19, + + V1_MANIFEST_OBJ_ValidationAlg = 20, + V1_MANIFEST_OBJ_SigningTime = 21, + V1_MANIFEST_OBJ_BODYEND = 22 +} SchemaV1ManifestContentObjectBody; + +typedef enum { + V1_MANIFEST_OBJ_OPTHEAD = 0, + V1_MANIFEST_OBJ_E2EFRAG = 2, + V1_MANIFEST_OBJ_FIXEDHEADER = 3, + V1_MANIFEST_OBJ_RecommendedCacheTime = 4, + V1_MANIFEST_OBJ_HEADEND = 5 +} SchemaV1ManifestContentObjectHeaders; + +#endif // Libccnx_tlv_ContentObjectSchema_h diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h new file mode 100644 index 00000000..894b3cc7 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_InterestSchema.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This is from the version 0 codec. All the test vectors in this directory (e.g. interest_nameA.h) + * are encoded using these constants. These are no longer used for any functional code, only to interpret the test vectors. + * + */ + +#ifndef Libccnx_v1_InterestSchema_h +#define Libccnx_v1_InterestSchema_h + +#include + +// ----------------------------------------------------- +// these are the array indicies used to store the TlvExtent for the item +typedef enum { + V1_MANIFEST_INT_INTEREST = 0, // start of Interest body to end + + V1_MANIFEST_INT_NAME = 1, + V1_MANIFEST_INT_KEYID = 2, + V1_MANIFEST_INT_OBJHASH = 3, + V1_MANIFEST_INT_PAYLOAD = 4, + V1_MANIFEST_INT_IPIDM = 5, + + V1_MANIFEST_INT_ValidationAlg = 6, // start of validation algorithm + V1_MANIFEST_INT_ValidationPayload = 7, // start of validation payload + + V1_MANIFEST_INT_BODYEND = 7 +} ScheamV1ManifestInterestBody; + +typedef enum { + V1_MANIFEST_INT_OPTHEAD = 0, // the start of the optional headers + V1_MANIFEST_INT_LIFETIME = 1, + V1_MANIFEST_INT_E2EFRAG = 2, + V1_MANIFEST_INT_HEADEND = 3, +} ScheamV1ManifestInterestHeaders; + + +#define T_INTEREST 0x0001 + +#endif // Libccnx_tlv_InterestSchema_h diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameA_crc32c.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameA_crc32c.h new file mode 100644 index 00000000..e4695849 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameA_crc32c.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file interest_nameA_crc32c.h + * @brief Interest with CRC validation + * + * Ground truth set derived from CRC RevEng http://reveng.sourceforge.net + * e.g. reveng -c -m CRC-32C 313233343536373839 gives the canonical check value 0xe306928e + * + * You can also calcaulate CRC32C online at http://www.zorc.breitbandkatze.de/crc.html using + * CRC polynomial 0x1EDC6F41, init 0xFFFFFFFF, final 0xFFFFFFFF, reverse data bytes (check), + * and reverse CRC result before final XOR (check). + * + * you can get the packet dump from the "write_packets" command. here's the detailed steps. + * The -c size of 4 in steps 4 and 7 are chosen to make it easy to delete the right number of lines. + * there's nothing magic about the "4". + * + * 1) execute ./write_packets + * 2) xxd -r -c 8 v1_content_nameA_crc32c.txt > y + * 3) vim -b y + * 4) :%!xxd -p -c 4 + * 5) Delete the frist 44 bytes (11 lines). The first line should now be: + * 00020015 + * 6) Delete the last 8 bytes + * The last line two lines should be: + * 04000200 + * 00 + * What's left is the part to be signed. + * 7) :%!xxd -r -p -c 4 + * 8) :wq + * 9) dump the file to one long URL-escaped hex string with + * xxd -p -c 256 y | sed 's/[0-9a-f]\{2\}/%&/g' + * 10) Copy the hex string to the website and use the settings specified above (don't use 0x in front + * of any hex strings). Click "compute!" + * 11) The answer should be 2C3CC0Af + * 12) Put the byte array from (11) in the Validation Payload. + * + */ + +#ifndef v1_content_nameA_crc32c_h +#define v1_content_nameA_crc32c_h + +#include +#include + +/** + * A well formed interest with only a name + */ + +__attribute__((unused)) +static uint8_t v1_content_nameA_crc32c[] = { + 0x01, 0x01, 0x00, 85, // ver = 1, type = content object, length = 85 + 0x00, 0x00, 0x00, 44, // HopLimit = 31, reserved = 0, header length = 44 + // ------------------------ + 0x00, 0x04, 0x00, 20, // ContentObject Fragment, length = 20 + 0x12, 0x23, 0x34, 0x45, + 0x56, 0x67, 0x78, 0x89, // fragid 0x1223344556677889 + 0x05, 0xDC, 0x01, 0x00, // MTU 1500, fragcnt 1, fragnum 0 + 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, // interest fragment 0x0102030405060708 + // ------------------------ + 0x00, 0x02, 0x00, 8, // Recommended Cache Time + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x6D, 0xDD, 0x00, // 2 hours (0x6DDD00 milli seconds) + // ------------------------ + 0x00, 0x02, 0x00, 21, // type = content object, length = 21 + // ------------------------ + 0x00, 0x00, 0x00, 0x11, // type = name, length = 17 + 0x00, 0x03, 0x00, 0x05, // type = binary, length = 5 + 'h', 'e', 'l', 'l', // "hello" + 'o', + 0xF0, 0x00, 0x00, 0x04, // type = app, length = 4 + 'o', 'u', 'c', 'h', // "ouch" + // ------------------------ + 0x00, 0x03, 0x00, 4, // validation alg, length = 4 + 0x00, 0x02, 0x00, 0x00, // CRC32C + // ------------------------ + 0x00, 0x04, 0x00, 4, // validation payload + 0x2C, 0x3C, 0xC0, 0xAF // 2C3CC0AF +}; + +__attribute__((unused)) +static TruthTableEntry +TRUTHTABLENAME(v1_content_nameA_crc32c)[] = +{ + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_E2EFRAG, .bodyManifest = false, .extent = { 12, 20 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_RecommendedCacheTime, .bodyManifest = false, .extent = { 36, 8 } }, + + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_CONTENTOBJECT, .bodyManifest = true, .extent = { 48, 21 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_NAME, .bodyManifest = true, .extent = { 52, 17 } }, + + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_ValidationAlg, .bodyManifest = true, .extent = { 73, 4 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_SIGBITS, .bodyManifest = true, .extent = { 81, 4 } }, + { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } }, +}; + +#define v1_content_nameA_crc32c_truthTable TABLEENTRY(v1_content_nameA_crc32c, TLV_ERR_NO_ERROR) + +#define v1_content_nameA_crc32c_URI "lci:/3=hello/0xf000=ouch" + +#endif diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h new file mode 100644 index 00000000..ef37fb5e --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file interest_nameA_crc32c.h + * @brief Interest with CRC validation + * + * Signature generated using "openssl sha -sign test_rsa_key.pem -sha256 -binary y > sig", where "y" is + * generated from the "xxd -r" of the message hex dump. You need to manually edit "y" so it only + * contains the parts begin signed. Then use "xxd -i sig" to get the byte array. + * + * you can get the dump from the "write_packets" command. here's the detailed steps: + * + * 1) execute ./write_packets + * 2) xxd -r -c 8 v1_content_nameA_keyid1_rsasha256.txt > y + * 3) vim -b y + * 4) :%!xxd -p -c 16 + * 5) Delete the frist 32 bytes (2 lines). The first line should now be: + * 0002003a000000110002000568656c6c + * 6) Delete the last 132 bytes (9 lines, 8 full lines plus the last 4 byte line) + * The last line in the file should now be: + * 0f3592ae7027fbd2e41e270203010001 + * What's left is the part to be signed. + * 7) :%!xxd -r -p -c 16 + * 8) :wq + * 9) Copy the PEM blocks below and put them in the file "key.pem". Make sure to remove + * any leading whitespace. If you get an error in the next command like + * "53999:error:0906D06C:PEM routines:PEM_read_bio:no start ... 648:Expecting: ANY PRIVATE KEY" then + * you most likely have leading whitespace. Make sure all lines are flush left. + * 10) openssl sha -sign key.pem -sha256 -binary y > sig + * 11) xxd -i sig + * 12) Put the byte array from (11) in the Validation Payload. Verify the length, it should be + * 128 bytes. If not, fixup the length of the ValidatonPayload and the PacketLength. + * + */ + +/* + * -----BEGIN RSA PRIVATE KEY----- + * MIICXAIBAAKBgQCn1pPF8XPGErX6ecXvGIvvqs0EAY+Ddz+xZqFauTkqsj4w+xH8 + * V/yd0S938Kt3rWYsJsibUW9pvyYQBinuy7AsXpEOJEKN5nWgTgRDDD5MBnRnrYTD + * 6PTFlHPEnyWoQga/RRnimBw2oUNNm3EI4YLf4k8qPD0PNZKucCf70uQeJwIDAQAB + * AoGAVOYPA/7aIGSQlu4IOKTDDG3qnM8pSEgG+PbAQgMVrspQ+TfXZj0ftLj++P3N + * zpDw8P6BVUfBQs2FNG/ZwEhaiZVgJAl7cIAxJ9Ac+1oZYSgGyJfb3u9iWvkbMOoj + * 83Inx5yyN+Qmk5zceH4pOC5D5cDAuGGZ740Euv4o2/2O3qECQQDTmWZw021PvEbA + * r18O1YfZGxO3zFCwFXCpnHvtSMbP+MXAG5Gt47wZt4Vx1rX9k78beeCUitwqp3d3 + * ZI+YlUu3AkEAyw5wssQsJty/n2FL8DbJN3UzUhkcaCFYrKz3RtFye9wu+Bw0TxPC + * 3jhFVcynm3nH3ZJN0JsnsPnHXuoQToShEQJATXC51hb6zZC5UDGel348fo9zUvP6 + * n8bo+ZoknL3izSBdtyYf1cUgBUVuGDCdYFWfPn4HXDXJx+6MQWzTRON21wJBAMZL + * U8M/z94jtP3wBjiPR/Dggz2pSBRofDAkuVZvM13BqByjbnHK2oIocY1YTlWGl6fJ + * ODR/UEODqS8HZOVIoAECQANcuvVnqDixSIl2ySZvydQytv4DKTbvE0nYSRroYIlJ + * PTOBPy8ynIUkJwc2E1BsLl7V8gO62a5O0ntTwBMnPSQ= + * -----END RSA PRIVATE KEY----- + * + * -----BEGIN PUBLIC KEY----- + * MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCn1pPF8XPGErX6ecXvGIvvqs0E + * AY+Ddz+xZqFauTkqsj4w+xH8V/yd0S938Kt3rWYsJsibUW9pvyYQBinuy7AsXpEO + * JEKN5nWgTgRDDD5MBnRnrYTD6PTFlHPEnyWoQga/RRnimBw2oUNNm3EI4YLf4k8q + * PD0PNZKucCf70uQeJwIDAQAB + * -----END PUBLIC KEY----- + */ + +#ifndef v1_content_nameA_keyid1_rsasha256_h +#define v1_content_nameA_keyid1_rsasha256_h + +#include +#include + +/** + * A well formed interest with only a name + */ + + +__attribute__((unused)) +static uint8_t v1_content_nameA_keyid1_rsasha256[] = { + 0x01, 0x01, 0x01, 0xB4,// ver = 1, type = content object, length = 436 + 0x00, 0x00, 0x00, 32, // HopLimit = 0, reserved = 0, header length = 32 + // ------------------------ + 0x00, 0x04, 0x00, 20, // ContentObject Fragment, length = 20 + 0x12, 0x23, 0x34, 0x45, + 0x56, 0x67, 0x78, 0x89,// fragid 0x1223344556677889 + 0x05, 0xDC, 0x01, 0x00,// MTU 1500, fragcnt 1, fragnum 0 + 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08,// interest fragment 0x0102030405060708 + // ------------------------ + 0x00, 0x02, 0x00, 58, // type = content object, length = 58 + // ------------------------ + 0x00, 0x00, 0x00, 17, // type = name, length = 17 + 0x00, 0x03, 0x00, 0x05,// type = binary, length = 5 + 'h', 'e', 'l', 'l', // "hello" + 'o', + 0xF0, 0x00, 0x00, 0x04,// type = app, length = 4 + 'o', 'u', 'c', 'h', // "ouch" + // ------------------------ + 0x00, 0x05, 0x00, 1, // PayloadType + 1, // type 1 = key + 0x00, 0x06, 0x00, 0x08,// expiry time in msec + 0x00, 0x00, 0x01, 0x43,// 1,388,534,400,000 msec + 0x4B, 0x19, 0x84, 0x00, + 0x00, 0x19, 0x00, 4, // end chunk number + 0x06, 0x05, 0x04, 0x03, + // ------------------------ + 0x00, 0x01, 0x00, 8, // payload, length = 8 + 0x73, 0x75, 0x72, 0x70, + 0x72, 0x69, 0x73, 0x65, + // ------------------------ + 0x00, 0x03, 0x00, 206, // validation alg, length = 206 + 0x00, 0x06, 0x00, 202, // RSA-SHA256, length = 162 + 4 + 32 + 4 = 202 + 0x00, 0x09, 0x00, 32, // type = keyid, length = 32 + 0x5c, 0x23, 0x4c, 0x28, + 0x50, 0xda, 0x20, 0x7b, + 0x88, 0x25, 0x8b, 0xf3, + 0x62, 0x61, 0x96, 0xd8, + 0xf0, 0x60, 0x76, 0x38, + 0xa2, 0xd4, 0xe0, 0xe2, + 0x49, 0xb2, 0xa9, 0xaf, + 0xce, 0xb8, 0x85, 0x59, + 0x00, 0x0B, 0x00, 162, // public key, length = 162 + 0x30, 0x81, 0x9f, 0x30,0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01,0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, + 0x89, 0x02, 0x81, 0x81,0x00, 0xa7, 0xd6, 0x93, 0xc5, 0xf1, 0x73, 0xc6, + 0x12, 0xb5, 0xfa, 0x79,0xc5, 0xef, 0x18, 0x8b, 0xef, 0xaa, 0xcd, 0x04, + 0x01, 0x8f, 0x83, 0x77,0x3f, 0xb1, 0x66, 0xa1, 0x5a, 0xb9, 0x39, 0x2a, + 0xb2, 0x3e, 0x30, 0xfb,0x11, 0xfc, 0x57, 0xfc, 0x9d, 0xd1, 0x2f, 0x77, + 0xf0, 0xab, 0x77, 0xad,0x66, 0x2c, 0x26, 0xc8, 0x9b, 0x51, 0x6f, 0x69, + 0xbf, 0x26, 0x10, 0x06,0x29, 0xee, 0xcb, 0xb0, 0x2c, 0x5e, 0x91, 0x0e, + 0x24, 0x42, 0x8d, 0xe6,0x75, 0xa0, 0x4e, 0x04, 0x43, 0x0c, 0x3e, 0x4c, + 0x06, 0x74, 0x67, 0xad,0x84, 0xc3, 0xe8, 0xf4, 0xc5, 0x94, 0x73, 0xc4, + 0x9f, 0x25, 0xa8, 0x42,0x06, 0xbf, 0x45, 0x19, 0xe2, 0x98, 0x1c, 0x36, + 0xa1, 0x43, 0x4d, 0x9b,0x71, 0x08, 0xe1, 0x82, 0xdf, 0xe2, 0x4f, 0x2a, + 0x3c, 0x3d, 0x0f, 0x35,0x92, 0xae, 0x70, 0x27, 0xfb, 0xd2, 0xe4, 0x1e, + 0x27, 0x02, 0x03, 0x01,0x00, 0x01, + // ------------------------ + 0x00, 0x04, 0x00, 128, // validation payload, length = 128 + 0x03, 0x46, 0xee, 0xb7,0x30, 0x1c, 0xea, 0x13, 0x0c, 0xce, 0x83, 0x5b, + 0x7b, 0x4f, 0xf5, 0x83,0x37, 0x08, 0x7f, 0xe0, 0xe1, 0xc9, 0x70, 0x09, + 0x5e, 0xc2, 0x1c, 0xd3,0x74, 0xbb, 0xbd, 0x72, 0x35, 0xa4, 0x1b, 0x0f, + 0x3d, 0x04, 0x5e, 0xf7,0xc1, 0xdf, 0xea, 0xc3, 0x50, 0x47, 0x14, 0xf9, + 0xb7, 0xbb, 0x42, 0xf9,0x3e, 0xaa, 0x49, 0xd2, 0x9f, 0xd1, 0xab, 0xf6, + 0xda, 0x32, 0x4a, 0xb1,0xb9, 0x69, 0x91, 0x57, 0x43, 0x5d, 0x06, 0xcf, + 0x1d, 0x9f, 0x7c, 0x28,0xee, 0x35, 0xaa, 0xd0, 0xb2, 0x8d, 0x34, 0x09, + 0xcd, 0xdb, 0x01, 0xf7,0xda, 0xe8, 0x59, 0x98, 0x4e, 0x59, 0xfa, 0x13, + 0xd0, 0xd1, 0x54, 0x8e,0x64, 0x8c, 0xc6, 0xd7, 0x6b, 0xc5, 0x89, 0xeb, + 0x37, 0x8f, 0x53, 0x04,0xba, 0x03, 0x05, 0xb4, 0x67, 0x73, 0xe1, 0x51, + 0x59, 0x12, 0xbc, 0x25,0xaa, 0xa2, 0xc1, 0x18 +}; + +__attribute__((unused)) +static TruthTableEntry +TRUTHTABLENAME(v1_content_nameA_keyid1_rsasha256)[] = +{ + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_E2EFRAG, .bodyManifest = false, .extent = { 12, 20 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_CONTENTOBJECT, .bodyManifest = true, .extent = { 36, 58 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_NAME, .bodyManifest = true, .extent = { 40, 17 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_PAYLOADTYPE, .bodyManifest = true, .extent = { 61, 1 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_EXPIRY_TIME, .bodyManifest = true, .extent = { 66, 8 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_ENDSEGMENT, .bodyManifest = true, .extent = { 78, 4 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_PAYLOAD, .bodyManifest = true, .extent = { 86, 8 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_ValidationAlg, .bodyManifest = true, .extent = { 94, 206 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_KEYID, .bodyManifest = true, .extent = { 106, 32 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_PUBKEY, .bodyManifest = true, .extent = { 142, 162 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_SIGBITS, .bodyManifest = true, .extent = { 308, 128 } }, + { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } }, +}; + +#define v1_content_nameA_keyid1_rsasha256_truthTable TABLEENTRY(v1_content_nameA_keyid1_rsasha256, TLV_ERR_NO_ERROR) + +#define v1_content_nameA_keyid1_rsasha256_URI "lci:/3=hello/0xf000=ouch" + +#endif diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameless_nosig.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameless_nosig.h new file mode 100644 index 00000000..f1fc59cb --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_nameless_nosig.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file v1_content_nameless_nosig.h + * @brief A v1 content object without a name + * + */ + +#ifndef v1_content_nameless_nosig_h +#define v1_content_nameless_nosig_h + +#include +#include + +/** + * A well formed nameless V1 Content Object + */ +__attribute__((unused)) +static uint8_t v1_content_nameless_nosig[] = { + 0x01, 0x01, 0x00, 0x31, // ver = 1, type = content object, length = 0x31 + 0x00, 0x00, 0x00, 0x08, // HopLimit = 0, reserved = 0, header length = 8 + // ------------------------ + 0x00, 0x02, 0x00, 37, // type = content object, length = 37 + // ------------------------ + 0x00, 0x05, 0x00, 1, // PayloadType + 1, // type 1 = key + 0x00, 0x06, 0x00, 0x08, // expiry time in msec + 0x00, 0x00, 0x01, 0x43, // 1,388,534,400,000 msec + 0x4B, 0x19, 0x84, 0x00, + 0x00, 0x19, 0x00, 4, // end chunk number + 0x06, 0x05, 0x04, 0x03, + // ------------------------ + 0x00, 0x01, 0x00, 8, // payload, length = 8 + 0x73, 0x75, 0x72, 0x70, + 0x72, 0x69, 0x73, 0x65, +}; + +__attribute__((unused)) +static TruthTableEntry +TRUTHTABLENAME(v1_content_nameless_nosig)[] = +{ + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_CONTENTOBJECT, .bodyManifest = true, .extent = { 12, 37 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_PAYLOADTYPE, .bodyManifest = true, .extent = { 17, 1 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_EXPIRY_TIME, .bodyManifest = true, .extent = { 22, 8 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_ENDSEGMENT, .bodyManifest = true, .extent = { 30, 4 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_PAYLOAD, .bodyManifest = true, .extent = { 41, 8 } }, + { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } }, +}; + +#define v1_content_nameless_nosig_truthTable TABLEENTRY(v1_content_nameless_nosig, TLV_ERR_NO_ERROR) + +#endif // v1_content_nameless_nosig_h diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_no_payload.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_no_payload.h new file mode 100644 index 00000000..ae439bf5 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_no_payload.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file v1_content_no_payload.h + * @brief Content Object without a payload TLV + * + * + */ + + +#ifndef CCNx_Common_v1_content_no_payload_h +#define CCNx_Common_v1_content_no_payload_h + +#include +#include + +__attribute__((unused)) +static uint8_t v1_content_no_payload[] = { + 0x01, 0x01, 0x00, 0x21, + 0x00, 0x00, 0x00, 0x08, + // -- content object + 0x00, 0x02, 0x00, 0x15, + // -- name + 0x00, 0x00, 0x00, 0x11, + 0x00, 0x03, 0x00, 0x02, + 0x6e, 0x6f, + 0x00, 0x03, 0x00, 0x07, + 0x70, 0x61, 0x79, 0x6c, + 0x6f, 0x61, 0x64 +}; + +__attribute__((unused)) +static TruthTableEntry +TRUTHTABLENAME(v1_content_no_payload)[] = +{ + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_CONTENTOBJECT, .bodyManifest = true, .extent = { 12, 21 } }, + { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } }, +}; + +#define v1_content_no_payload_truthTable TABLEENTRY(v1_content_no_payload, TLV_ERR_NO_ERROR) + +#endif diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_zero_payload.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_zero_payload.h new file mode 100644 index 00000000..01f7a8b4 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_content_zero_payload.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file v1_content_zero_payload.h + * @brief Content Object with zero length payload + * + * + */ + + +#ifndef CCNx_Common_v1_content_zero_payload_h +#define CCNx_Common_v1_content_zero_payload_h + +#include +#include + +__attribute__((unused)) +static uint8_t v1_content_zero_payload[] = { + 0x01, 0x01, 0x00, 0x25, + 0x00, 0x00, 0x00, 0x08, + // -- content object + 0x00, 0x02, 0x00, 0x19, + // -- name + 0x00, 0x00, 0x00, 0x11, + 0x00, 0x03, 0x00, 0x02, + 0x6e, 0x6f, + 0x00, 0x03, 0x00, 0x07, + 0x70, 0x61, 0x79, 0x6c, + 0x6f, 0x61, 0x64, + // -- payload + 0x00, 0x01, 0x00, 0x00, +}; + +__attribute__((unused)) +static TruthTableEntry +TRUTHTABLENAME(v1_content_zero_payload)[] = +{ + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_OBJ_CONTENTOBJECT, .bodyManifest = true, .extent = { 12, 25 } }, + { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } }, +}; + +#define v1_content_zero_payload_truthTable TABLEENTRY(v1_content_zero_payload, TLV_ERR_NO_ERROR) + +#endif diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route.h new file mode 100644 index 00000000..9bcf7dfc --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file v1_cpi_add_route.h + * @brief A hand-encoded CPI packet to add a route + * + * The v1 old-style control packet is a fixed header plus a tlv container 0xBEEF with a "value" of the CPI JSON string. + * The packet type is 0xA4. + * + */ + +#ifndef TransportRTA_v1_cpi_AddRoute_h +#define TransportRTA_v1_cpi_AddRoute_h + +#include +#include + +__attribute__((unused)) +static uint8_t v1_cpi_add_route[] = "\x01\xA4\x00\xA7" + "\x00\x00\x00\x08" + "\xBE\xEF\x00\x9A" + "{\"CPI_REQUEST\":{\"SEQUENCE\":22,\"REGISTER\":{\"PREFIX\":\"lci:/howdie/stranger\",\"INTERFACE\":55,\"FLAGS\":0,\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200}}}"; + +__attribute__((unused)) +static TruthTableEntry +TRUTHTABLENAME(v1_cpi_add_route)[] = +{ + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_CPI_PAYLOAD, .bodyManifest = true, .extent = { 12, 155 } }, + { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } }, +}; + +#define v1_cpi_add_route_truthTable TABLEENTRY(v1_cpi_add_route, TLV_ERR_NO_ERROR) + +#define v1_cpi_add_route_PrefixUri "lci:/howdie/stranger" +#define v1_cpi_add_route_Sequence 22 +#define v1_cpi_add_route_Interface 55 +#endif // TransportRTA_cpi_AddRoute_h diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route_crc32c.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route_crc32c.h new file mode 100644 index 00000000..e31cfc85 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_cpi_add_route_crc32c.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file v1_cpi_add_route.h + * @brief A hand-encoded CPI packet to add a route + * + * The v1 old-style control packet is a fixed header plus a tlv container 0xBEEF with a "value" of the CPI JSON string. + * The packet type is 0xA4. + * + * This control packet has a CRC32C MIC on it. Otherwise, same as v1_cpi_add_route.h + * + * Ground truth set derived from CRC RevEng http://reveng.sourceforge.net + * e.g. reveng -c -m CRC-32C 313233343536373839 gives the canonical check value 0xe306928e + * + * You can also calcaulate CRC32C online at http://www.zorc.breitbandkatze.de/crc.html using + * CRC polynomial 0x1EDC6F41, init 0xFFFFFFFF, final 0xFFFFFFFF, reverse data bytes (check), + * and reverse CRC result before final XOR (check). + * + * you can get the packet dump from the "write_packets" command. here's the detailed steps. + * The -c size of 4 in steps 4 and 7 are chosen to make it easy to delete the right number of lines. + * there's nothing magic about the "4". + * + * 1) execute ./write_packets + * 2) xxd -r -c 8 v1_cpi_add_route_crc32c.txt > y + * 3) Delete the first 8 bytes and last 16 bytes and display has a hex string + * tail -c +9 y | head -c 158 | xxd -p -c 256 + * The string should be "beef...077d7d7d" + * 4) The string for this packet is too long for the website. Use another tool such as reveng. + * 5) The answer should be 78fd926a (the reveng answer will be byte reversed) + * 6) Put the byte array from (5) in the Validation Payload. + * + */ + +#ifndef TransportRTA_v1_v1_cpi_AddRoute_crc32c_h +#define TransportRTA_v1_v1_cpi_AddRoute_crc32c_h + +#include +#include + +__attribute__((unused)) +static uint8_t v1_cpi_add_route_crc32c[] = "\x01\xA4\x00\xB7" + "\x00\x00\x00\x08" + "\xBE\xEF\x00\x9A" + "{\"CPI_REQUEST\":{\"SEQUENCE\":22,\"REGISTER\":{\"PREFIX\":\"lci:/howdie/stranger\",\"INTERFACE\":55,\"FLAGS\":0,\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200}}}" + "\x00\x03\x00\x04" + "\x00\x02\x00\x00" + "\x00\x04\x00\x04" + "\x78\xfd\x92\x6a"; + +__attribute__((unused)) +static TruthTableEntry +TRUTHTABLENAME(v1_cpi_add_route_crc32c)[] = +{ + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_CPI_PAYLOAD, .bodyManifest = true, .extent = { 12, 155 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_CPI_ValidationAlg, .bodyManifest = true, .extent = { 171, 4 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_CPI_SIGBITS, .bodyManifest = true, .extent = { 178, 4 } }, + { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } }, +}; + +#define v1_cpi_add_route_crc32c_truthTable TABLEENTRY(v1_cpi_add_route_crc32c, TLV_ERR_NO_ERROR) + +#define v1_cpi_add_route_crc32c_PrefixUri "lci:/howdie/stranger" +#define v1_cpi_add_route_crc32c_Sequence 22 +#define v1_cpi_add_route_crc32c_Interface 55 +#endif // TransportRTA_cpi_AddRoute_h diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h new file mode 100755 index 00000000..f6524ad1 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file v1_interest_all_fields.h + * @brief A hand-encoded v1 interest in wireformat with all Interest fields. + * + * <#Detailed Description#> + * + */ + +#ifndef CCNx_Common_v1_interest_all_fields_h +#define CCNx_Common_v1_interest_all_fields_h + +#include +#include + +/** + * A well formed interest with all allowed Interest fields + */ +__attribute__((unused)) +static uint8_t v1_interest_all_fields[] = { + 0x01, 0x00, 0x00, 156, // ver = 1, type = interest, length = 156 + 0x20, 0x00, 0x11, 14, // HopLimit = 32, reserved = 0, flags = 0x11, header length = 14 + // ------------------------ + 0x00, 0x01, 0x00, 2, // Interest Lifetime (2 bytes) + 0xEA, 0xEB, + // ------------------------ + 0x00, 0x01, 0x00, 138, // type = interest, length = 138 + // ------------------------ + 0x00, 0x00, 0x00, 45, // type = name, length = 45 + 0x00, 0x03, 0x00, 4, // type = binary, length = 4 + 'c', 'o', 'o', 'l', // "cool" + // ----- segment 2 -------- + 0x00, 0x02, 0x00, 33, // type = payload id, length = 33 + 0x01, // payloadID type = sha256 + 0x89, 0x87, 0x69, 0xfc, // hash bytes based on payload + 0x8c, 0xff, 0x16, 0xff, + 0x3d, 0xfc, 0xe7, 0xfa, + 0x02, 0xd2, 0x6d, 0x26, + 0xf0, 0x91, 0x86, 0x27, + 0xcf, 0x18, 0xc1, 0x9b, + 0x0b, 0x5f, 0xe3, 0x93, + 0xce, 0x1a, 0xa3, 0x56, + // ------------------------ + 0x00, 0x02, 0x00, 36, // type = keyid restriction, length = 36 + 0x00, 0x01, 0x00, 0x20, // SHA256 hash, length 32 + 0xa0, 0xa1, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, + 0xac, 0xad, 0xae, 0xaf, + 0xa0, 0xa1, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, + 0xac, 0xad, 0xae, 0xaf, + // ------------------------ + 0x00, 0x03, 0x00, 36, // type = hash restriction, length = 36 + 0x00, 0x01, 0x00, 0x20, // SHA256 hash, length 32 + 0xb0, 0xb1, 0xb2, 0xb3, + 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, + 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, + 0xcc, 0xcd, 0xce, 0xcf, + // ------------------------ + 0x00, 0x01, 0x00, 5, // type = payload, length = 5 + 0xD0, 0xD1, 0xD2, 0xD3, + 0xD4, +}; + +__attribute__((unused)) +static TruthTableEntry +TRUTHTABLENAME(v1_interest_all_fields)[] = +{ + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_LIFETIME, .bodyManifest = false, .extent = { 12, 2 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_INTEREST, .bodyManifest = true, .extent = { 18, 138 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_NAME, .bodyManifest = true, .extent = { 22, 45 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_KEYID, .bodyManifest = true, .extent = { 71, 36 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_OBJHASH, .bodyManifest = true, .extent = { 111, 36 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_PAYLOAD, .bodyManifest = true, .extent = { 151, 5 } }, + { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } }, +}; + +#define v1_interest_all_fields_truthTable TABLEENTRY(v1_interest_all_fields, TLV_ERR_NO_ERROR) + +#define v1_interest_all_fields_URI "lci:/3=cool/2=\x01\x89\x87\x69\xfc\x8c\xff\x16\xff\x3d\xfc\xe7\xfa\x02\xd2\x6d\x26\xf0\x91\x86\x27\xcf\x18\xc1\x9b\x0b\x5f\xe3\x93\xce\x1a\xa3\x56" +#define v1_interest_all_fields_Lifetime 0xEAEB +#endif diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_bad_message_length.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_bad_message_length.h new file mode 100644 index 00000000..650c770e --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_bad_message_length.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file v1_interest_all_fields.h + * @brief A hand-encoded v1 interest in wireformat with all Interest fields. + * + * The Interest TLV length goes beyond the end of the packet + * + */ + +#ifndef CCNx_Common_v1_interest_bad_message_length_h +#define CCNx_Common_v1_interest_bad_message_length_h + +#include +#include + +/** + * A well formed interest with all allowed Interest fields + */ +__attribute__((unused)) +static uint8_t v1_interest_bad_message_length[] = { + 0x01, 0x00, 0x00, 30, // ver = 1, type = interest, length = 30 + 0x20, 0x00, 0x11, 14, // HopLimit = 31, reserved = 0, flags = 0x11, header length = 14 + // ------------------------ + 0x00, 0x01, 0x00, 2, // Interest Lifetime (2 bytes) + 0xEA, 0xEB, + // ------------------------ + 0x00, 0x01, 0x00, 13, // type = interest, length = 13 (1 byte too far) + // ------------------------ + 0x00, 0x00, 0x00, 8, // type = name, length = 8 + 0x00, 0x03, 0x00, 4, // type = binary, length = 4 + 'c', 'o', 'o', 'l', // "cool" +}; + +__attribute__((unused)) +static TruthTableEntry +TRUTHTABLENAME(v1_interest_bad_message_length)[] = +{ + { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } }, +}; + +#define v1_interest_bad_message_length_truthTable TABLEENTRY(v1_interest_bad_message_length, TLV_ERR_TOO_LONG) + +#endif diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_bad_validation_alg.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_bad_validation_alg.h new file mode 100644 index 00000000..9c4c3117 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_bad_validation_alg.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file v1_interest_bad_validation_alg.h + * @brief Interest with CRC validation + * + * This is an error packet, the ValidationAlg TLV does not have the correct type + * + */ + +#ifndef testdata_v1_interest_bad_validation_alg +#define testdata_v1_interest_bad_validation_alg + +/** + * A well formed interest with only a name + */ + +#include +#include + +__attribute__((unused)) +static uint8_t v1_interest_bad_validation_alg[] = { + 0x01, 0x00, 0x00, 65, // ver = 1, type = interest, length = 65 + 0x20, 0x00, 0x00, 24, // HopLimit = 32, reserved = 0, header length = 24 + // ------------------------ + 0x00, 0x03, 0x00, 12, // Interest Fragment + 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, // fragment 0x0102030405060708 + 0x05, 0xDC, 0x00, 0x00, // MTU 1500, fragcnt 0, fragnum 0 + // ------------------------ + 0x00, 0x01, 0x00, 0x15, // type = interest, length = 21 + // ------------------------ + 0x00, 0x00, 0x00, 0x11, // type = name, length = 17 + 0x00, 0x03, 0x00, 0x05, // type = binary, length = 5 + 'h', 'e', 'l', 'l', // "hello" + 'o', + 0xF0, 0x00, 0x00, 0x04, // type = app, length = 4 + 'o', 'u', 'c', 'h', // "ouch" + // ------------------------ + 0x00, 0xFF, 0x00, 4, // Not "0x03" validation alg length = 4 + 0x00, 0xFF, 0x00, 0x00, // unknown validation alg + // ------------------------ + 0x00, 0x04, 0x00, 4, // validation payload + 0x6A, 0xD7, 0xB1, 0xF2 // 6AD7B1F2 +}; + +__attribute__((unused)) +static TruthTableEntry +TRUTHTABLENAME(v1_interest_bad_validation_alg)[] = +{ + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_E2EFRAG, .bodyManifest = false, .extent = { 12, 12 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_INTEREST, .bodyManifest = true, .extent = { 24, 25 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_NAME, .bodyManifest = true, .extent = { 32, 17 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_ValidationAlg, .bodyManifest = true, .extent = { 53, 4 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_ValidationPayload, .bodyManifest = true, .extent = { 61, 4 } }, + { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } }, +}; + +#define v1_interest_bad_validation_alg_truthTable TABLEENTRY(v1_interest_bad_validation_alg, TLV_ERR_NO_ERROR) + +#endif diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA.h new file mode 100644 index 00000000..4bee1e40 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file v1_interest_nameA.h + * @brief A basic interest + * + * A basic Interest with a fragmentation header and Name. + * + */ + +#ifndef testdata_interest_nameA_h +#define testdata_interest_nameA_h + +#include +#include + +/** + * A well formed interest with only a name + */ + + +__attribute__((unused)) +static uint8_t v1_interest_nameA[] = { + 0x01, 0x00, 0x00, 61, // ver = 1, type = interest, length = 61 + 0x20, 0x00, 0x00, 36, // HopLimit = 31, reserved = 0, header length = 36 + // ------------------------ + // ------------------------ + 0x00, 0x03, 0x00, 12, // Interest Fragment + 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, // fragment 0x0102030405060708 + 0x05, 0xDC, 0x00, 0x00, // MTU 1500, fragcnt 0, fragnum 0 + // ------------------------ + 0x00, 0x01, 0x00, 8, // Interest Lifetime + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0F, 0xA0, // 4000 milli-seconds + // ------------------------ + 0x00, 0x01, 0x00, 0x15, // type = interest, length = 21 + // ------------------------ + 0x00, 0x00, 0x00, 0x11, // type = name, length = 17 + 0x00, 0x03, 0x00, 0x05, // type = binary, length = 5 + 'h', 'e', 'l', 'l', // "hello" + 'o', + 0xF0, 0x00, 0x00, 0x04, // type = app, length = 4 + 'o', 'u', 'c', 'h', // "ouch" +}; + +__attribute__((unused)) +static TruthTableEntry +TRUTHTABLENAME(v1_interest_nameA)[] = +{ + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_E2EFRAG, .bodyManifest = false, .extent = { 12, 12 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_LIFETIME, .bodyManifest = false, .extent = { 28, 8 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_INTEREST, .bodyManifest = false, .extent = { 40, 21 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_NAME, .bodyManifest = true, .extent = { 44, 17 } }, + { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } }, +}; + +#define v1_interest_nameA_truthTable TABLEENTRY(v1_interest_nameA, TLV_ERR_NO_ERROR) + +#define v1_interest_nameA_URI "lci:/3=hello/0xf000=ouch" + +#endif diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_badcrc32c.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_badcrc32c.h new file mode 100644 index 00000000..6af04f42 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_badcrc32c.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file interest_nameA_badcrc32c.h + * @brief Interest with CRC validation + * + * Has incorrect CRC32C payload + * + */ + +#ifndef testdata_interest_nameA_badcrc32c_h +#define testdata_interest_nameA_badcrc32c_h + +#include +#include + +/** + * A well formed interest with only a name + */ + +__attribute__((unused)) +static uint8_t v1_interest_nameA_badcrc32c[] = { + 0x01, 0x00, 0x00, 41, // ver = 1, type = interest, length = 65 + 0x20, 0x00, 0x00, 24, // HopLimit = 31, reserved = 0, header length = 24 + // ------------------------ + 0x00, 0x03, 0x00, 0x0C, // Interest Fragment + 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, // fragment 0x0102030405060708 + 0x05, 0xDC, 0x00, 0x00, // MTU 1500, fragcnt 0, fragnum 0 + // ------------------------ + 0x00, 0x01, 0x00, 0x15, // type = interest, length = 21 + // ------------------------ + 0x00, 0x00, 0x00, 0x11, // type = name, length = 17 + 0x00, 0x03, 0x00, 0x05, // type = binary, length = 5 + 'h', 'e', 'l', 'l', // "hello" + 'o', + 0xF0, 0x00, 0x00, 0x04, // type = app, length = 4 + 'o', 'u', 'c', 'h', // "ouch" + // ------------------------ + 0x00, 0x03, 0x00, 4, // validation alg, length = 4 + 0x00, 0x02, 0x00, 0x00, // CRC32C + // ------------------------ + 0x00, 0x04, 0x00, 4, // validation payload + 0x00, 0x00, 0x00, 0x00 // invalid CRC32C +}; + +__attribute__((unused)) +static TruthTableEntry +TRUTHTABLENAME(v1_interest_nameA_badcrc32c)[] = +{ + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_E2EFRAG, .bodyManifest = false, .extent = { 12, 12 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_INTEREST, .bodyManifest = true, .extent = { 20, 21 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_NAME, .bodyManifest = true, .extent = { 24, 17 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_ValidationAlg, .bodyManifest = true, .extent = { 45, 4 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_ValidationPayload, .bodyManifest = true, .extent = { 53, 4 } }, + { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } }, +}; + +#define v1_interest_nameA_badcrc32c_truthTable TABLEENTRY(v1_interest_nameA_badcrc32c, TLV_ERR_NO_ERROR) + +#define v1_interest_nameA_badcrc32c_URI "lci:/3=hello/0xf000=ouch" + +#endif diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_crc32c.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_crc32c.h new file mode 100644 index 00000000..64edf560 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_nameA_crc32c.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file interest_nameA_crc32c.h + * @brief Interest with CRC validation + * + * + * Ground truth set derived from CRC RevEng http://reveng.sourceforge.net + * e.g. reveng -c -m CRC-32C 313233343536373839 gives the canonical check value 0xe306928e (the output will be backwards) + * + * You can also calcaulate CRC32C online at http://www.zorc.breitbandkatze.de/crc.html using + * CRC polynomial 0x1EDC6F41, init 0xFFFFFFFF, final 0xFFFFFFFF, reverse data bytes (check), + * and reverse CRC result before final XOR (check). + * + * you can get the packet dump from the "write_packets" command. here's the detailed steps. + * The -c size of 8 in steps 4 and 7 are chosen to make it easy to delete the right number of lines. + * there's nothing magic about the "8". + * + * 1) execute ./write_packets + * 2) xxd -r -c 8 v1_interest_nameA_crc32c.txt > y + * 3) Delete the first 24 bytes and last 8 bytes and display as a URI-escaped hex string + * head -c 57 y | tail -c +25 | xxd -p -c 256 | sed 's/[0-9a-f]\{2\}/%&/g' + * The string should be "00010015...00020000" + * 4) Copy the hex string to the website and use the settings specified above (don't use 0x in front + * of any hex strings). IMPORTANT: you need to %-escape each hex byte!! Click "compute!" + * 5) The answer should be 6AD7B1F2 + * 6) Put the byte array from (5) in the Validation Payload. + * + */ + +#ifndef testdata_interest_nameA_crc32c_h +#define testdata_interest_nameA_crc32c_h + +/** + * A well formed interest with only a name + */ + +#include +#include + +#define NAME_A_CRC32_PACKET(_type, _code) \ + { \ + 0x01, _type, 0x00, 65, /* ver = 1, type = interest, length = 65 */ \ + 0x20, _code, 0x00, 24, /* HopLimit = 32, reserved = 0, header length = 24*/ \ + /* ------------------------ */ \ + 0x00, 0x03, 0x00, 12, /* Interest Fragment */ \ + 0x01, 0x02, 0x03, 0x04, \ + 0x05, 0x06, 0x07, 0x08, /* fragment 0x0102030405060708 */ \ + 0x05, 0xDC, 0x00, 0x00, /* MTU 1500, fragcnt 0, fragnum 0 */ \ + /* ------------------------ */ \ + 0x00, 0x01, 0x00, 0x15, /* type = interest, length = 21 */ \ + /* ------------------------ */ \ + 0x00, 0x00, 0x00, 0x11, /* type = name, length = 17 */ \ + 0x00, 0x03, 0x00, 0x05, /* type = binary, length = 5 */ \ + 'h', 'e', 'l', 'l', /* "hello" */ \ + 'o', \ + 0xF0, 0x00, 0x00, 0x04, /* type = app, length = 4 */ \ + 'o', 'u', 'c', 'h', /* "ouch" */ \ + /* ------------------------ */ \ + 0x00, 0x03, 0x00, 4, /* validation alg, length = 4 */ \ + 0x00, 0x02, 0x00, 0x00, /* CRC32C */ \ + /* ------------------------ */ \ + 0x00, 0x04, 0x00, 4, /* validation payload */ \ + 0xD0, 0x98, 0x73, 0x7C, /* D098737C */ \ + } + +__attribute__((unused)) +static uint8_t v1_interest_nameA_crc32c[] = NAME_A_CRC32_PACKET(0x00, 0x00); + +__attribute__((unused)) +static TruthTableEntry +TRUTHTABLENAME(v1_interest_nameA_crc32c)[] = +{ + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_E2EFRAG, .bodyManifest = false, .extent = { 12, 12 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_INTEREST, .bodyManifest = true, .extent = { 24, 25 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_NAME, .bodyManifest = true, .extent = { 32, 17 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_ValidationAlg, .bodyManifest = true, .extent = { 53, 4 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_ValidationPayload, .bodyManifest = true, .extent = { 61, 4 } }, + { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } }, +}; + +__attribute__((unused)) +static uint8_t v1_interest_nameA_crc32c_returned[] = NAME_A_CRC32_PACKET(0x02, 0x03); //InterestReturn & NoResource + +#define v1_interest_nameA_crc32c_truthTable TABLEENTRY(v1_interest_nameA_crc32c, TLV_ERR_NO_ERROR) + +#define v1_interest_nameA_crc32c_URI "lci:/3=hello/0xf000=ouch" + +#endif diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_validation_alg_overrun.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_validation_alg_overrun.h new file mode 100644 index 00000000..8f3b55a5 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_interest_validation_alg_overrun.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file v1_interest_validation_alg_overrun.h + * @brief Interest with CRC validation + * + * This is an error packet. The length of the Validation TLV runs past the end of the packet. + * + */ + +#ifndef testdata_v1_interest_validation_alg_overrun +#define testdata_v1_interest_validation_alg_overrun + +/** + * A well formed interest with only a name + */ + +#include +#include + +__attribute__((unused)) +static uint8_t v1_interest_validation_alg_overrun[] = { + 0x01, 0x00, 0x00, 65, // ver = 1, type = interest, length = 65 + 0x20, 0x00, 0x00, 24, // HopLimit = 32, reserved = 0, header length = 24 + // ------------------------ + 0x00, 0x03, 0x00, 12, // Interest Fragment + 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, // fragment 0x0102030405060708 + 0x05, 0xDC, 0x00, 0x00, // MTU 1500, fragcnt 0, fragnum 0 + // ------------------------ + 0x00, 0x01, 0x00, 0x15, // type = interest, length = 21 + // ------------------------ + 0x00, 0x00, 0x00, 0x11, // type = name, length = 17 + 0x00, 0x03, 0x00, 0x05, // type = binary, length = 5 + 'h', 'e', 'l', 'l', // "hello" + 'o', + 0xF0, 0x00, 0x00, 0x04, // type = app, length = 4 + 'o', 'u', 'c', 'h', // "ouch" + // ------------------------ + 0x00, 0x03, 0x00, 255, // Validation Alg, length = 255 + 0x00, 0xFF, 0x00, 0x00, // unknown validation alg + // ------------------------ + 0x00, 0x04, 0x00, 4, // validation payload + 0x6A, 0xD7, 0xB1, 0xF2 // 6AD7B1F2 +}; + +__attribute__((unused)) +static TruthTableEntry +TRUTHTABLENAME(v1_interest_validation_alg_overrun)[] = +{ + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_E2EFRAG, .bodyManifest = false, .extent = { 12, 12 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_INTEREST, .bodyManifest = true, .extent = { 24, 25 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_NAME, .bodyManifest = true, .extent = { 32, 17 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_ValidationAlg, .bodyManifest = true, .extent = { 53, 4 } }, + { .wellKnownType = true, .indexOrKey = V1_MANIFEST_INT_ValidationPayload, .bodyManifest = true, .extent = { 61, 4 } }, + { .wellKnownType = false, .indexOrKey = T_INVALID, .extent = { 0, 0 } }, +}; + +#define v1_interest_validation_alg_overrun_truthTable TABLEENTRY(v1_interest_validation_alg_overrun, TLV_ERR_TOO_LONG) + +#endif diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_testrig_truthSet.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_testrig_truthSet.h new file mode 100644 index 00000000..f98de878 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_testrig_truthSet.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Contains tables of all the packets. May be used for automated testing. Also used by write_packets utility. + * + */ + +#include + +#include "v1_interest_nameA.h" +#include "v1_interest_nameA_badcrc32c.h" +#include "v1_interest_nameA_crc32c.h" +#include "v1_interest_bad_validation_alg.h" +#include "v1_interest_validation_alg_overrun.h" + +#include "v1_content_nameA_crc32c.h" +#include "v1_content_nameA_keyid1_rsasha256.h" +#include "v1_content_zero_payload.h" +#include "v1_content_no_payload.h" + +#include "v1_cpi_add_route.h" +#include "v1_cpi_add_route_crc32c.h" + +// terminated with NULL packet entry +__attribute__((unused)) +static TruthTable v1_interests_truthSet [] = { + // tests in alphabetical order + v1_interest_nameA_truthTable, + v1_interest_nameA_badcrc32c_truthTable, + v1_interest_nameA_crc32c_truthTable, + v1_interest_bad_validation_alg_truthTable, + v1_interest_validation_alg_overrun_truthTable, + // the end of table marker + { .packet = NULL, .expectedError= 0, .entry = NULL } +}; + +// terminated with NULL packet entry +__attribute__((unused)) +static TruthTable v1_contentObject_truthSet [] = { + v1_content_nameA_crc32c_truthTable, + v1_content_nameA_keyid1_rsasha256_truthTable, + v1_content_zero_payload_truthTable, + v1_content_no_payload_truthTable, + + // the end of table marker + { .packet = NULL, .expectedError= 0, .entry = NULL } +}; + +__attribute__((unused)) +static TruthTable v1_cpi_truthSet [] = { + v1_cpi_add_route_truthTable, + v1_cpi_add_route_crc32c_truthTable, + // the end of table marker + { .packet = NULL, .expectedError= 0, .entry = NULL } +}; diff --git a/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_testrig_truthTable.h b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_testrig_truthTable.h new file mode 100755 index 00000000..32c954b7 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/testdata/v1_testrig_truthTable.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/* + * testrig_truthTable.h + * TransportRTA + */ + +#ifndef TransportRTA_testrig_truthTable_h +#define TransportRTA_testrig_truthTable_h + +#include +#include +//#include + +#include +#include + +#include + +#endif -- cgit 1.2.3-korg