blob: fd7c51872ab076a049cb48aa5d58c27c6ab52f89 [file] [log] [blame]
/*
*
* Copyright (c) 2020-2022 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 defines types and objects for reading and writing
* Abstract Syntax Notation One (ASN.1) encoded data.
*
*/
#pragma once
#ifndef DOXYGEN_SHOULD_SKIP_THIS
#include <asn1/ASN1OID.h>
#endif
#include <lib/asn1/ASN1Error.h>
#include <lib/support/DLLUtil.h>
#include <lib/support/Span.h>
namespace chip {
namespace TLV {
class TLVReader;
}
} // namespace chip
/**
* @namespace chip::ASN1
*
* @brief
* This namespace includes all interfaces within CHIP for
* working with Abstract Syntax Notation One (ASN.1).
*/
namespace chip {
namespace ASN1 {
static constexpr size_t kMaxConstructedAndEncapsulatedTypesDepth = 10;
enum ASN1TagClasses
{
kASN1TagClass_Universal = 0x00,
kASN1TagClass_Application = 0x40,
kASN1TagClass_ContextSpecific = 0x80,
kASN1TagClass_Private = 0xC0
};
enum ASN1UniversalTags : uint8_t
{
kASN1UniversalTag_Boolean = 1,
kASN1UniversalTag_Integer = 2,
kASN1UniversalTag_BitString = 3,
kASN1UniversalTag_OctetString = 4,
kASN1UniversalTag_Null = 5,
kASN1UniversalTag_ObjectId = 6,
kASN1UniversalTag_ObjectDesc = 7,
kASN1UniversalTag_External = 8,
kASN1UniversalTag_Real = 9,
kASN1UniversalTag_Enumerated = 10,
kASN1UniversalTag_UTF8String = 12,
kASN1UniversalTag_Sequence = 16,
kASN1UniversalTag_Set = 17,
kASN1UniversalTag_NumericString = 18,
kASN1UniversalTag_PrintableString = 19,
kASN1UniversalTag_T61String = 20,
kASN1UniversalTag_VideotexString = 21,
kASN1UniversalTag_IA5String = 22,
kASN1UniversalTag_UTCTime = 23,
kASN1UniversalTag_GeneralizedTime = 24,
kASN1UniversalTag_GraphicString = 25,
kASN1UniversalTag_VisibleString = 26,
kASN1UniversalTag_GeneralString = 27,
kASN1UniversalTag_UniversalString = 28
};
/**
* @struct ASN1UniversalTime
*
* @brief
* A data structure representing ASN1 universal time in a calendar format.
*/
struct ASN1UniversalTime
{
uint16_t Year; /**< Year component. Legal interval is 0..9999. */
uint8_t Month; /**< Month component. Legal interval is 1..12. */
uint8_t Day; /**< Day of month component. Legal interval is 1..31. */
uint8_t Hour; /**< Hour component. Legal interval is 0..23. */
uint8_t Minute; /**< Minute component. Legal interval is 0..59. */
uint8_t Second; /**< Second component. Legal interval is 0..59. */
static constexpr size_t kASN1UTCTimeStringLength = 13;
static constexpr size_t kASN1GeneralizedTimeStringLength = 15;
static constexpr size_t kASN1TimeStringMaxLength = 15;
/**
* @brief Set time from ASN1_TIME string.
* Two string formats are supported:
* YYMMDDHHMMSSZ - for years in the range 1950 - 2049
* YYYYMMDDHHMMSSZ - other years
**/
CHIP_ERROR ImportFrom_ASN1_TIME_string(const CharSpan & asn1_time);
/**
* @brief Encode time as an ASN1_TIME string.
* Two string formats are supported:
* YYMMDDHHMMSSZ - for years in the range 1950 - 2049
* YYYYMMDDHHMMSSZ - other years
**/
CHIP_ERROR ExportTo_ASN1_TIME_string(MutableCharSpan & asn1_time) const;
/**
* @brief Encode time as Unix epoch time.
**/
bool ExportTo_UnixTime(uint32_t & unixEpoch);
};
class DLL_EXPORT ASN1Reader
{
public:
void Init(const uint8_t * buf, size_t len);
void Init(const ByteSpan & data) { Init(data.data(), data.size()); }
template <size_t N>
void Init(const uint8_t (&data)[N])
{
Init(data, N);
}
uint8_t GetClass(void) const { return Class; };
uint8_t GetTag(void) const { return Tag; };
const uint8_t * GetValue(void) const { return Value; };
uint32_t GetValueLen(void) const { return ValueLen; };
bool IsConstructed(void) const { return Constructed; };
bool IsIndefiniteLen(void) const { return IndefiniteLen; };
bool IsEndOfContents(void) const { return EndOfContents; };
CHIP_ERROR Next(void);
CHIP_ERROR EnterConstructedType(void);
CHIP_ERROR ExitConstructedType(void);
CHIP_ERROR GetConstructedType(const uint8_t *& val, uint32_t & valLen);
CHIP_ERROR EnterEncapsulatedType(void);
CHIP_ERROR ExitEncapsulatedType(void);
bool IsContained(void) const;
CHIP_ERROR GetInteger(int64_t & val);
CHIP_ERROR GetBoolean(bool & val);
CHIP_ERROR GetObjectId(OID & oid);
CHIP_ERROR GetUTCTime(ASN1UniversalTime & outTime);
CHIP_ERROR GetGeneralizedTime(ASN1UniversalTime & outTime);
CHIP_ERROR GetBitString(uint32_t & outVal);
private:
static constexpr size_t kMaxContextDepth = kMaxConstructedAndEncapsulatedTypesDepth;
struct ASN1ParseContext
{
const uint8_t * ElemStart;
uint32_t HeadLen;
uint32_t ValueLen;
bool IndefiniteLen;
const uint8_t * ContainerEnd;
};
uint8_t Class;
uint8_t Tag;
const uint8_t * Value;
uint32_t ValueLen;
bool Constructed;
bool IndefiniteLen;
bool EndOfContents;
const uint8_t * mBuf;
const uint8_t * mBufEnd;
const uint8_t * mElemStart;
const uint8_t * mContainerEnd;
uint32_t mHeadLen;
ASN1ParseContext mSavedContexts[kMaxContextDepth];
uint32_t mNumSavedContexts;
CHIP_ERROR DecodeHead(void);
void ResetElementState(void);
CHIP_ERROR EnterContainer(uint32_t offset);
CHIP_ERROR ExitContainer(void);
};
class DLL_EXPORT ASN1Writer
{
public:
void Init(uint8_t * buf, size_t maxLen);
void Init(const MutableByteSpan & data) { Init(data.data(), data.size()); }
template <size_t N>
void Init(uint8_t (&data)[N])
{
Init(data, N);
}
void InitNullWriter(void);
size_t GetLengthWritten(void) const;
CHIP_ERROR PutInteger(int64_t val);
CHIP_ERROR PutBoolean(bool val);
CHIP_ERROR PutObjectId(const uint8_t * val, uint16_t valLen);
CHIP_ERROR PutObjectId(OID oid);
CHIP_ERROR PutString(uint8_t tag, const char * val, uint16_t valLen);
CHIP_ERROR PutOctetString(const uint8_t * val, uint16_t valLen);
CHIP_ERROR PutOctetString(uint8_t cls, uint8_t tag, const uint8_t * val, uint16_t valLen);
CHIP_ERROR PutOctetString(uint8_t cls, uint8_t tag, chip::TLV::TLVReader & tlvReader);
CHIP_ERROR PutBitString(uint32_t val);
CHIP_ERROR PutBitString(uint8_t unusedBits, const uint8_t * val, uint16_t valLen);
CHIP_ERROR PutBitString(uint8_t unusedBits, chip::TLV::TLVReader & tlvReader);
CHIP_ERROR PutTime(const ASN1UniversalTime & val);
CHIP_ERROR PutNull(void);
CHIP_ERROR PutConstructedType(const uint8_t * val, uint16_t valLen);
CHIP_ERROR StartConstructedType(uint8_t cls, uint8_t tag);
CHIP_ERROR EndConstructedType(void);
CHIP_ERROR StartEncapsulatedType(uint8_t cls, uint8_t tag, bool bitStringEncoding);
CHIP_ERROR EndEncapsulatedType(void);
CHIP_ERROR PutValue(uint8_t cls, uint8_t tag, bool isConstructed, const uint8_t * val, uint16_t valLen);
CHIP_ERROR PutValue(uint8_t cls, uint8_t tag, bool isConstructed, chip::TLV::TLVReader & tlvReader);
private:
static constexpr size_t kMaxDeferredLengthDepth = kMaxConstructedAndEncapsulatedTypesDepth;
uint8_t * mBuf;
uint8_t * mBufEnd;
uint8_t * mWritePoint;
uint8_t * mDeferredLengthLocations[kMaxDeferredLengthDepth];
uint8_t mDeferredLengthCount;
CHIP_ERROR EncodeHead(uint8_t cls, uint8_t tag, bool isConstructed, int32_t len);
CHIP_ERROR WriteDeferredLength(void);
static uint8_t BytesForLength(int32_t len);
static void EncodeLength(uint8_t * buf, uint8_t bytesForLen, int32_t lenToEncode);
void WriteData(const uint8_t * p, size_t len);
};
OID ParseObjectID(const uint8_t * encodedOID, uint16_t encodedOIDLen);
bool GetEncodedObjectID(OID oid, const uint8_t *& encodedOID, uint16_t & encodedOIDLen);
OIDCategory GetOIDCategory(OID oid);
const char * GetOIDName(OID oid);
CHIP_ERROR DumpASN1(ASN1Reader & reader, const char * prefix, const char * indent);
inline OID GetOID(OIDCategory category, uint8_t id)
{
return static_cast<OID>(category | id);
}
inline uint8_t GetOIDEnum(OID oid)
{
return static_cast<uint8_t>(oid & kOID_EnumMask);
}
} // namespace ASN1
} // namespace chip