blob: 048ddeb91a38e71ada9b2e6d3dbd53d1f6dff6c9 [file] [log] [blame]
/*
*
* Copyright (c) 2020-2021 Project CHIP Authors
* Copyright (c) 2013-2017 Nest Labs, Inc.
* All rights reserved.
*
* 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
* This file implements a process to effect a functional test for
* the CHIP Abstract Syntax Notifcation One (ASN1) encode and
* decode interfaces.
*
*/
#include <nlunit-test.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <lib/asn1/ASN1.h>
#include <lib/asn1/ASN1Macros.h>
#include <lib/core/CHIPTLV.h>
#include <lib/support/UnitTestRegistration.h>
using namespace chip;
using namespace chip::ASN1;
using namespace chip::TLV;
enum
{
kTestVal_01_Bool = false,
kTestVal_02_Bool = true,
kTestVal_03_BitString = 0x0,
kTestVal_04_BitString = 0x1,
kTestVal_05_BitString = 0x3,
kTestVal_06_BitString = 0x17,
kTestVal_07_BitString = 0x37,
kTestVal_08_BitString = 0x187,
kTestVal_09_BitString = 0x3E7,
kTestVal_10_Int = 0,
kTestVal_11_Int = 1,
kTestVal_12_Int = -1,
kTestVal_13_Int = 0xFF00FF,
kTestVal_14_Int = -0xFF00FF,
kTestVal_15_Int = INT32_MAX,
kTestVal_16_Int = INT32_MIN,
kTestVal_17_Int = INT64_MAX,
kTestVal_18_Int = INT64_MIN,
kTestVal_19_OID = kOID_AttributeType_OrganizationName,
kTestVal_23_OID = kOID_AttributeType_CommonName,
kTestVal_24_Int = 42,
};
// clang-format off
static uint8_t kTestVal_09_BitString_AsOctetString[] = { 0xE7, 0xC0 };
static uint8_t kTestVal_20_OctetString[] = { 0x01, 0x03, 0x05, 0x07, 0x10, 0x30, 0x50, 0x70, 0x00 };
static const char * kTestVal_21_PrintableString = "Sudden death in Venice";
static const char * kTestVal_22_UTFString = "Ond bra\xCC\x8A""d do\xCC\x88""d i Venedig";
// clang-format on
// Manually copied from ASN1OID.h for testing.
static const uint8_t sOID_AttributeType_ChipNodeId[] = { 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0xA2, 0x7C, 0x01, 0x01 };
static const uint8_t sOID_SigAlgo_ECDSAWithSHA256[] = { 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02 };
static const uint8_t sOID_EllipticCurve_prime256v1[] = { 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07 };
static const uint8_t sOID_Extension_AuthorityKeyIdentifier[] = { 0x55, 0x1D, 0x23 };
static const uint8_t sOID_Extension_BasicConstraints[] = { 0x55, 0x1D, 0x13 };
static const uint8_t sOID_KeyPurpose_ServerAuth[] = { 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01 };
uint8_t TestASN1_EncodedData[] = {
0x30, 0x81, 0xBA, 0x01, 0x01, 0x00, 0x01, 0x01, 0xFF, 0x31, 0x00, 0x03, 0x01, 0x00, 0x03, 0x02, 0x07, 0x80, 0x03, 0x02, 0x06,
0xC0, 0x30, 0x16, 0x30, 0x0F, 0x30, 0x08, 0x03, 0x02, 0x03, 0xE8, 0x03, 0x02, 0x02, 0xEC, 0x03, 0x03, 0x07, 0xE1, 0x80, 0x03,
0x03, 0x06, 0xE7, 0xC0, 0x02, 0x01, 0x00, 0x02, 0x01, 0x01, 0x02, 0x01, 0xFF, 0x02, 0x04, 0x00, 0xFF, 0x00, 0xFF, 0x02, 0x04,
0xFF, 0x00, 0xFF, 0x01, 0x02, 0x04, 0x7F, 0xFF, 0xFF, 0xFF, 0x02, 0x04, 0x80, 0x00, 0x00, 0x00, 0x02, 0x08, 0x7F, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x02, 0x08, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x04,
0x09, 0x01, 0x03, 0x05, 0x07, 0x10, 0x30, 0x50, 0x70, 0x00, 0x04, 0x01, 0x01, 0x04, 0x00, 0x1B, 0x00, 0x13, 0x16, 0x53, 0x75,
0x64, 0x64, 0x65, 0x6E, 0x20, 0x64, 0x65, 0x61, 0x74, 0x68, 0x20, 0x69, 0x6E, 0x20, 0x56, 0x65, 0x6E, 0x69, 0x63, 0x65, 0x0C,
0x1A, 0x4F, 0x6E, 0x64, 0x20, 0x62, 0x72, 0x61, 0xCC, 0x8A, 0x64, 0x20, 0x64, 0x6F, 0xCC, 0x88, 0x64, 0x20, 0x69, 0x20, 0x56,
0x65, 0x6E, 0x65, 0x64, 0x69, 0x67, 0x04, 0x0D, 0x30, 0x0B, 0x06, 0x03, 0x55, 0x04, 0x03, 0x03, 0x04, 0x00, 0x02, 0x01, 0x2A
};
static CHIP_ERROR EncodeASN1TestData(ASN1Writer & writer)
{
CHIP_ERROR err = CHIP_NO_ERROR;
ASN1_START_SEQUENCE
{
ASN1_ENCODE_BOOLEAN(kTestVal_01_Bool);
ASN1_ENCODE_BOOLEAN(kTestVal_02_Bool);
ASN1_START_SET {}
ASN1_END_SET;
ASN1_ENCODE_BIT_STRING(kTestVal_03_BitString);
ASN1_ENCODE_BIT_STRING(kTestVal_04_BitString);
ASN1_ENCODE_BIT_STRING(kTestVal_05_BitString);
ASN1_START_SEQUENCE
{
ASN1_START_SEQUENCE
{
ASN1_START_SEQUENCE
{
ASN1_ENCODE_BIT_STRING(kTestVal_06_BitString);
ASN1_ENCODE_BIT_STRING(kTestVal_07_BitString);
}
ASN1_END_SEQUENCE;
ASN1_ENCODE_BIT_STRING(kTestVal_08_BitString);
}
ASN1_END_SEQUENCE;
ASN1_ENCODE_BIT_STRING(kTestVal_09_BitString);
}
ASN1_END_SEQUENCE;
ASN1_ENCODE_INTEGER(kTestVal_10_Int);
ASN1_ENCODE_INTEGER(kTestVal_11_Int);
ASN1_ENCODE_INTEGER(kTestVal_12_Int);
ASN1_ENCODE_INTEGER(kTestVal_13_Int);
ASN1_ENCODE_INTEGER(kTestVal_14_Int);
ASN1_ENCODE_INTEGER(kTestVal_15_Int);
ASN1_ENCODE_INTEGER(kTestVal_16_Int);
ASN1_ENCODE_INTEGER(kTestVal_17_Int);
ASN1_ENCODE_INTEGER(kTestVal_18_Int);
ASN1_ENCODE_OBJECT_ID(kTestVal_19_OID);
ASN1_ENCODE_OCTET_STRING(kTestVal_20_OctetString, sizeof(kTestVal_20_OctetString));
ASN1_ENCODE_OCTET_STRING(kTestVal_20_OctetString, 1);
ASN1_ENCODE_OCTET_STRING(kTestVal_20_OctetString, 0);
ASN1_ENCODE_STRING(kASN1UniversalTag_GeneralString, "", 0);
ASN1_ENCODE_STRING(kASN1UniversalTag_PrintableString, kTestVal_21_PrintableString, strlen(kTestVal_21_PrintableString));
ASN1_ENCODE_STRING(kASN1UniversalTag_UTF8String, kTestVal_22_UTFString, strlen(kTestVal_22_UTFString));
ASN1_START_OCTET_STRING_ENCAPSULATED
{
ASN1_START_SEQUENCE
{
ASN1_ENCODE_OBJECT_ID(kTestVal_23_OID);
ASN1_START_BIT_STRING_ENCAPSULATED { ASN1_ENCODE_INTEGER(kTestVal_24_Int); }
ASN1_END_ENCAPSULATED;
}
ASN1_END_SEQUENCE;
}
ASN1_END_ENCAPSULATED;
}
ASN1_END_SEQUENCE;
exit:
return err;
}
static void TestASN1_Encode(nlTestSuite * inSuite, void * inContext)
{
CHIP_ERROR err;
static uint8_t buf[2048];
ASN1Writer writer;
uint16_t encodedLen;
writer.Init(buf);
err = EncodeASN1TestData(writer);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
encodedLen = writer.GetLengthWritten();
NL_TEST_ASSERT(inSuite, encodedLen == sizeof(TestASN1_EncodedData));
NL_TEST_ASSERT(inSuite, memcmp(buf, TestASN1_EncodedData, sizeof(TestASN1_EncodedData)) == 0);
#define DUMP_HEX 0
#if DUMP_HEX
for (uint16_t i = 0; i < encodedLen; i++)
{
if (i != 0 && i % 16 == 0)
printf("\n");
printf("0x%02X, ", buf[i]);
}
printf("\n");
#endif
}
static void TestASN1_Decode(nlTestSuite * inSuite, void * inContext)
{
CHIP_ERROR err = CHIP_NO_ERROR;
ASN1Reader reader;
bool boolVal;
uint32_t bitStringVal;
int64_t intVal;
OID oidVal;
reader.Init(TestASN1_EncodedData);
ASN1_PARSE_ENTER_SEQUENCE
{
ASN1_PARSE_BOOLEAN(boolVal);
NL_TEST_ASSERT(inSuite, boolVal == kTestVal_01_Bool);
ASN1_PARSE_BOOLEAN(boolVal);
NL_TEST_ASSERT(inSuite, boolVal == kTestVal_02_Bool);
ASN1_PARSE_ENTER_SET {}
ASN1_EXIT_SET;
ASN1_PARSE_BIT_STRING(bitStringVal);
NL_TEST_ASSERT(inSuite, bitStringVal == kTestVal_03_BitString);
ASN1_PARSE_BIT_STRING(bitStringVal);
NL_TEST_ASSERT(inSuite, bitStringVal == kTestVal_04_BitString);
ASN1_PARSE_BIT_STRING(bitStringVal);
NL_TEST_ASSERT(inSuite, bitStringVal == kTestVal_05_BitString);
ASN1_PARSE_ENTER_SEQUENCE
{
ASN1_PARSE_ENTER_SEQUENCE
{
ASN1_PARSE_ENTER_SEQUENCE
{
ASN1_PARSE_BIT_STRING(bitStringVal);
NL_TEST_ASSERT(inSuite, bitStringVal == kTestVal_06_BitString);
ASN1_PARSE_BIT_STRING(bitStringVal);
NL_TEST_ASSERT(inSuite, bitStringVal == kTestVal_07_BitString);
}
ASN1_EXIT_SEQUENCE;
ASN1_PARSE_BIT_STRING(bitStringVal);
NL_TEST_ASSERT(inSuite, bitStringVal == kTestVal_08_BitString);
}
ASN1_EXIT_SEQUENCE;
ASN1_PARSE_BIT_STRING(bitStringVal);
NL_TEST_ASSERT(inSuite, bitStringVal == kTestVal_09_BitString);
}
ASN1_EXIT_SEQUENCE;
ASN1_PARSE_INTEGER(intVal);
NL_TEST_ASSERT(inSuite, intVal == kTestVal_10_Int);
ASN1_PARSE_INTEGER(intVal);
NL_TEST_ASSERT(inSuite, intVal == kTestVal_11_Int);
ASN1_PARSE_INTEGER(intVal);
NL_TEST_ASSERT(inSuite, intVal == kTestVal_12_Int);
ASN1_PARSE_INTEGER(intVal);
NL_TEST_ASSERT(inSuite, intVal == kTestVal_13_Int);
ASN1_PARSE_INTEGER(intVal);
NL_TEST_ASSERT(inSuite, intVal == kTestVal_14_Int);
ASN1_PARSE_INTEGER(intVal);
NL_TEST_ASSERT(inSuite, intVal == kTestVal_15_Int);
ASN1_PARSE_INTEGER(intVal);
NL_TEST_ASSERT(inSuite, intVal == kTestVal_16_Int);
ASN1_PARSE_INTEGER(intVal);
NL_TEST_ASSERT(inSuite, intVal == kTestVal_17_Int);
ASN1_PARSE_INTEGER(intVal);
NL_TEST_ASSERT(inSuite, intVal == kTestVal_18_Int);
ASN1_PARSE_OBJECT_ID(oidVal);
NL_TEST_ASSERT(inSuite, oidVal == kTestVal_19_OID);
ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_OctetString);
NL_TEST_ASSERT(inSuite, reader.GetValueLen() == sizeof(kTestVal_20_OctetString));
NL_TEST_ASSERT(inSuite, memcmp(reader.GetValue(), kTestVal_20_OctetString, sizeof(kTestVal_20_OctetString)) == 0);
ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_OctetString);
NL_TEST_ASSERT(inSuite, reader.GetValueLen() == 1);
NL_TEST_ASSERT(inSuite, reader.GetValue()[0] == kTestVal_20_OctetString[0]);
ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_OctetString);
NL_TEST_ASSERT(inSuite, reader.GetValueLen() == 0);
ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_GeneralString);
NL_TEST_ASSERT(inSuite, reader.GetValueLen() == 0);
ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_PrintableString);
NL_TEST_ASSERT(inSuite, reader.GetValueLen() == strlen(kTestVal_21_PrintableString));
NL_TEST_ASSERT(inSuite, memcmp(reader.GetValue(), kTestVal_21_PrintableString, strlen(kTestVal_21_PrintableString)) == 0);
ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_UTF8String);
NL_TEST_ASSERT(inSuite, reader.GetValueLen() == strlen(kTestVal_22_UTFString));
NL_TEST_ASSERT(inSuite, memcmp(reader.GetValue(), kTestVal_22_UTFString, strlen(kTestVal_22_UTFString)) == 0);
ASN1_PARSE_ENTER_ENCAPSULATED(kASN1TagClass_Universal, kASN1UniversalTag_OctetString)
{
ASN1_PARSE_ENTER_SEQUENCE
{
ASN1_PARSE_OBJECT_ID(oidVal);
NL_TEST_ASSERT(inSuite, oidVal == kTestVal_23_OID);
ASN1_PARSE_ENTER_ENCAPSULATED(kASN1TagClass_Universal, kASN1UniversalTag_BitString)
{
ASN1_PARSE_INTEGER(intVal);
NL_TEST_ASSERT(inSuite, intVal == kTestVal_24_Int);
}
ASN1_EXIT_ENCAPSULATED;
}
ASN1_EXIT_SEQUENCE;
}
ASN1_EXIT_ENCAPSULATED;
}
ASN1_EXIT_SEQUENCE;
exit:
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
}
static void TestASN1_NullWriter(nlTestSuite * inSuite, void * inContext)
{
CHIP_ERROR err;
ASN1Writer writer;
uint16_t encodedLen;
writer.InitNullWriter();
err = EncodeASN1TestData(writer);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
encodedLen = writer.GetLengthWritten();
NL_TEST_ASSERT(inSuite, encodedLen == 0);
}
static void TestASN1_ASN1UniversalTime(nlTestSuite * inSuite, void * inContext)
{
struct ASN1TimeTestCase
{
ASN1UniversalTime asn1Time;
const char * asn1TimeStr;
};
struct ASN1TimeErrorTestCase
{
const char * asn1TimeStr;
CHIP_ERROR mExpectedResult;
};
// clang-format off
static ASN1TimeTestCase sASN1TimeTestCases[] = {
// ASN1 Universal Time ASN1_TIME String
// ====================================================
{ { 2020, 10, 15, 14, 23, 43 }, "201015142343Z" },
{ { 2020, 12, 1, 2, 34, 0 }, "201201023400Z" },
{ { 1979, 1, 30, 12, 0, 0 }, "790130120000Z" },
{ { 2079, 1, 30, 12, 0, 0 }, "20790130120000Z" },
{ { 2049, 3, 31, 23, 59, 59 }, "490331235959Z" },
{ { 1949, 3, 31, 23, 59, 59 }, "19490331235959Z" },
{ { 1950, 3, 31, 23, 59, 59 }, "500331235959Z" },
};
// clang-format on
// clang-format off
static ASN1TimeErrorTestCase sASN1TimeErrorTestCases[] = {
// ASN1_TIME String Expected Result
// =======================================================
{ "201015142343z", ASN1_ERROR_UNSUPPORTED_ENCODING },
{ "20105142343Z", ASN1_ERROR_UNSUPPORTED_ENCODING },
{ "2010115142343Z", ASN1_ERROR_UNSUPPORTED_ENCODING },
{ "201014415142343Z", ASN1_ERROR_UNSUPPORTED_ENCODING },
{ "201O15142343Z", ASN1_ERROR_INVALID_ENCODING },
{ "200015142343Z", ASN1_ERROR_INVALID_ENCODING },
{ "201315142343Z", ASN1_ERROR_INVALID_ENCODING },
{ "201000142343Z", ASN1_ERROR_INVALID_ENCODING },
{ "201032142343Z", ASN1_ERROR_INVALID_ENCODING },
{ "201015242343Z", ASN1_ERROR_INVALID_ENCODING },
{ "201015146043Z", ASN1_ERROR_INVALID_ENCODING },
{ "201015142360Z", ASN1_ERROR_INVALID_ENCODING },
};
// clang-format on
for (auto & testCase : sASN1TimeTestCases)
{
CharSpan testStr = CharSpan(testCase.asn1TimeStr, strlen(testCase.asn1TimeStr));
ASN1UniversalTime result;
NL_TEST_ASSERT(inSuite, result.ImportFrom_ASN1_TIME_string(testStr) == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite,
result.Year == testCase.asn1Time.Year && result.Month == testCase.asn1Time.Month &&
result.Day == testCase.asn1Time.Day && result.Hour == testCase.asn1Time.Hour &&
result.Minute == testCase.asn1Time.Minute && result.Second == testCase.asn1Time.Second);
char buf[ASN1UniversalTime::kASN1TimeStringMaxLength];
MutableCharSpan resultTimeStr(buf);
NL_TEST_ASSERT(inSuite, result.ExportTo_ASN1_TIME_string(resultTimeStr) == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, resultTimeStr.data_equal(testStr));
}
for (auto & testCase : sASN1TimeErrorTestCases)
{
CharSpan testStr = CharSpan(testCase.asn1TimeStr, strlen(testCase.asn1TimeStr));
ASN1UniversalTime result;
NL_TEST_ASSERT(inSuite, result.ImportFrom_ASN1_TIME_string(testStr) == testCase.mExpectedResult);
}
}
static void TestASN1_ObjectID(nlTestSuite * inSuite, void * inContext)
{
CHIP_ERROR err;
static uint8_t buf[2048];
ASN1Writer writer;
ASN1Reader reader;
uint16_t encodedLen;
writer.Init(buf, sizeof(buf));
ASN1_START_SEQUENCE
{
ASN1_ENCODE_OBJECT_ID(kOID_AttributeType_MatterNodeId);
ASN1_ENCODE_OBJECT_ID(kOID_SigAlgo_ECDSAWithSHA256);
ASN1_ENCODE_OBJECT_ID(kOID_EllipticCurve_prime256v1);
ASN1_ENCODE_OBJECT_ID(kOID_Extension_AuthorityKeyIdentifier);
ASN1_ENCODE_OBJECT_ID(kOID_Extension_BasicConstraints);
ASN1_ENCODE_OBJECT_ID(kOID_KeyPurpose_ServerAuth);
}
ASN1_END_SEQUENCE;
encodedLen = writer.GetLengthWritten();
NL_TEST_ASSERT(inSuite, encodedLen > 0);
reader.Init(buf, encodedLen);
// Parse and check OIDs as actual ASN1 encoded values.
ASN1_PARSE_ENTER_SEQUENCE
{
ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_ObjectId);
NL_TEST_ASSERT(inSuite, reader.GetValueLen() == sizeof(sOID_AttributeType_ChipNodeId));
NL_TEST_ASSERT(inSuite,
memcmp(reader.GetValue(), sOID_AttributeType_ChipNodeId, sizeof(sOID_AttributeType_ChipNodeId)) == 0);
ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_ObjectId);
NL_TEST_ASSERT(inSuite, reader.GetValueLen() == sizeof(sOID_SigAlgo_ECDSAWithSHA256));
NL_TEST_ASSERT(inSuite, memcmp(reader.GetValue(), sOID_SigAlgo_ECDSAWithSHA256, sizeof(sOID_SigAlgo_ECDSAWithSHA256)) == 0);
ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_ObjectId);
NL_TEST_ASSERT(inSuite, reader.GetValueLen() == sizeof(sOID_EllipticCurve_prime256v1));
NL_TEST_ASSERT(inSuite,
memcmp(reader.GetValue(), sOID_EllipticCurve_prime256v1, sizeof(sOID_EllipticCurve_prime256v1)) == 0);
ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_ObjectId);
NL_TEST_ASSERT(inSuite, reader.GetValueLen() == sizeof(sOID_Extension_AuthorityKeyIdentifier));
NL_TEST_ASSERT(
inSuite,
memcmp(reader.GetValue(), sOID_Extension_AuthorityKeyIdentifier, sizeof(sOID_Extension_AuthorityKeyIdentifier)) == 0);
ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_ObjectId);
NL_TEST_ASSERT(inSuite, reader.GetValueLen() == sizeof(sOID_Extension_BasicConstraints));
NL_TEST_ASSERT(inSuite,
memcmp(reader.GetValue(), sOID_Extension_BasicConstraints, sizeof(sOID_Extension_BasicConstraints)) == 0);
ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_ObjectId);
NL_TEST_ASSERT(inSuite, reader.GetValueLen() == sizeof(sOID_KeyPurpose_ServerAuth));
NL_TEST_ASSERT(inSuite, memcmp(reader.GetValue(), sOID_KeyPurpose_ServerAuth, sizeof(sOID_KeyPurpose_ServerAuth)) == 0);
}
ASN1_EXIT_SEQUENCE;
exit:
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
}
static void TestASN1_FromTLVReader(nlTestSuite * inSuite, void * inContext)
{
CHIP_ERROR err;
static uint8_t tlvBuf[128];
static uint8_t asn1Buf1[128];
static uint8_t asn1Buf2[128];
TLVWriter tlvWriter;
TLVReader tlvReader;
ASN1Writer writer;
ASN1Reader reader;
MutableByteSpan tlvEncodedData(tlvBuf);
MutableByteSpan asn1EncodedData1(asn1Buf1);
MutableByteSpan asn1EncodedData2(asn1Buf2);
TLVType outerContainerType;
// Construct TLV Encoded Structure.
{
tlvWriter.Init(tlvEncodedData);
err = tlvWriter.StartContainer(AnonymousTag(), kTLVType_Structure, outerContainerType);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
err = tlvWriter.PutBytes(TLV::ContextTag(1), kTestVal_20_OctetString, sizeof(kTestVal_20_OctetString));
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
err = tlvWriter.PutBytes(TLV::ContextTag(2), kTestVal_09_BitString_AsOctetString,
sizeof(kTestVal_09_BitString_AsOctetString));
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
err = tlvWriter.PutString(TLV::ContextTag(3), kTestVal_21_PrintableString);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
err = tlvWriter.EndContainer(outerContainerType);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
err = tlvWriter.Finalize();
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
}
// Construct first ASN1 SEQUESNCE using values.
writer.Init(asn1EncodedData1);
ASN1_START_SEQUENCE
{
ASN1_ENCODE_OCTET_STRING(kTestVal_20_OctetString, sizeof(kTestVal_20_OctetString));
ASN1_ENCODE_BIT_STRING(kTestVal_09_BitString);
err = writer.PutValue(kASN1TagClass_Universal, kASN1UniversalTag_PrintableString, false,
reinterpret_cast<const uint8_t *>(kTestVal_21_PrintableString), strlen(kTestVal_21_PrintableString));
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
}
ASN1_END_SEQUENCE;
asn1EncodedData1.reduce_size(writer.GetLengthWritten());
// Construct second ASN1 SEQUENCE from TLVReader.
tlvReader.Init(tlvEncodedData);
writer.Init(asn1EncodedData2);
ASN1_START_SEQUENCE
{
err = tlvReader.Next(kTLVType_Structure, AnonymousTag());
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
err = tlvReader.EnterContainer(outerContainerType);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
err = tlvReader.Next(kTLVType_ByteString, ContextTag(1));
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
err = writer.PutOctetString(kASN1TagClass_Universal, kASN1UniversalTag_OctetString, tlvReader);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
err = tlvReader.Next(kTLVType_ByteString, ContextTag(2));
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
err = writer.PutBitString(6, tlvReader);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
err = tlvReader.Next(kTLVType_UTF8String, ContextTag(3));
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
err = writer.PutValue(kASN1TagClass_Universal, kASN1UniversalTag_PrintableString, false, tlvReader);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
err = tlvReader.ExitContainer(outerContainerType);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
}
ASN1_END_SEQUENCE;
asn1EncodedData2.reduce_size(writer.GetLengthWritten());
// Compare two ASN1 SEQUENCEs.
NL_TEST_ASSERT(inSuite, asn1EncodedData2.data_equal(asn1EncodedData1));
// Initialize ASN1Reader and test data.
reader.Init(asn1EncodedData2);
ASN1_PARSE_ENTER_SEQUENCE
{
ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_OctetString);
NL_TEST_ASSERT(inSuite, reader.GetValue() != nullptr);
NL_TEST_ASSERT(inSuite, reader.GetValueLen() == sizeof(kTestVal_20_OctetString));
NL_TEST_ASSERT(inSuite, memcmp(reader.GetValue(), kTestVal_20_OctetString, sizeof(kTestVal_20_OctetString)) == 0);
uint32_t val;
ASN1_PARSE_BIT_STRING(val);
NL_TEST_ASSERT(inSuite, val == kTestVal_09_BitString);
ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_PrintableString);
NL_TEST_ASSERT(inSuite, reader.GetValue() != nullptr);
NL_TEST_ASSERT(inSuite, reader.GetValueLen() == strlen(kTestVal_21_PrintableString));
NL_TEST_ASSERT(inSuite, memcmp(reader.GetValue(), kTestVal_21_PrintableString, strlen(kTestVal_21_PrintableString)) == 0);
}
ASN1_EXIT_SEQUENCE;
exit:
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
}
/**
* Test Suite. It lists all the test functions.
*/
// clang-format off
static const nlTest sTests[] =
{
NL_TEST_DEF("Test ASN1 encoding macros", TestASN1_Encode),
NL_TEST_DEF("Test ASN1 decoding macros", TestASN1_Decode),
NL_TEST_DEF("Test ASN1 NULL writer", TestASN1_NullWriter),
NL_TEST_DEF("Test ASN1 universal time", TestASN1_ASN1UniversalTime),
NL_TEST_DEF("Test ASN1 Object IDs", TestASN1_ObjectID),
NL_TEST_DEF("Test ASN1 Init with ByteSpan", TestASN1_FromTLVReader),
NL_TEST_SENTINEL()
};
// clang-format on
int TestASN1(void)
{
nlTestSuite theSuite = { "Support-ASN1", &sTests[0], nullptr, nullptr };
nlTestRunner(&theSuite, nullptr);
return (nlTestRunnerStats(&theSuite));
}
CHIP_REGISTER_TEST_SUITE(TestASN1);