LCOV - code coverage report
Current view: top level - lib/asn1 - ASN1Reader.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 142 237 59.9 %
Date: 2024-02-15 08:20:41 Functions: 17 19 89.5 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2020-2022 Project CHIP Authors
       4             :  *    Copyright (c) 2013-2017 Nest Labs, Inc.
       5             :  *    All rights reserved.
       6             :  *
       7             :  *    Licensed under the Apache License, Version 2.0 (the "License");
       8             :  *    you may not use this file except in compliance with the License.
       9             :  *    You may obtain a copy of the License at
      10             :  *
      11             :  *        http://www.apache.org/licenses/LICENSE-2.0
      12             :  *
      13             :  *    Unless required by applicable law or agreed to in writing, software
      14             :  *    distributed under the License is distributed on an "AS IS" BASIS,
      15             :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      16             :  *    See the License for the specific language governing permissions and
      17             :  *    limitations under the License.
      18             :  */
      19             : 
      20             : /**
      21             :  *    @file
      22             :  *      This file implements an object for reading Abstract Syntax
      23             :  *      Notation One (ASN.1) encoded data.
      24             :  *
      25             :  */
      26             : 
      27             : #include <ctype.h>
      28             : #include <stdint.h>
      29             : #include <stdio.h>
      30             : #include <stdlib.h>
      31             : 
      32             : #include <lib/asn1/ASN1.h>
      33             : #include <lib/core/CHIPEncoding.h>
      34             : #include <lib/support/SafeInt.h>
      35             : 
      36             : namespace chip {
      37             : namespace ASN1 {
      38             : 
      39             : using namespace chip::Encoding;
      40             : 
      41         395 : void ASN1Reader::Init(const uint8_t * buf, size_t len)
      42             : {
      43         395 :     ResetElementState();
      44         395 :     mBuf              = buf;
      45         395 :     mBufEnd           = buf + len;
      46         395 :     mElemStart        = buf;
      47         395 :     mContainerEnd     = mBufEnd;
      48         395 :     mNumSavedContexts = 0;
      49         395 : }
      50             : 
      51       16940 : CHIP_ERROR ASN1Reader::Next()
      52             : {
      53       16940 :     ReturnErrorCodeIf(EndOfContents, ASN1_END);
      54       16940 :     ReturnErrorCodeIf(IndefiniteLen, ASN1_ERROR_UNSUPPORTED_ENCODING);
      55             : 
      56             :     // Note: avoid using addition assignment operator (+=), which may result in integer overflow
      57             :     // in the right hand side of an assignment (mHeadLen + ValueLen).
      58       16940 :     mElemStart = mElemStart + mHeadLen + ValueLen;
      59             : 
      60       16940 :     ResetElementState();
      61             : 
      62       16940 :     ReturnErrorCodeIf(mElemStart == mContainerEnd, ASN1_END);
      63             : 
      64       10682 :     return DecodeHead();
      65             : }
      66             : 
      67        4882 : CHIP_ERROR ASN1Reader::EnterConstructedType()
      68             : {
      69        4882 :     ReturnErrorCodeIf(!Constructed, ASN1_ERROR_INVALID_STATE);
      70             : 
      71        4882 :     return EnterContainer(0);
      72             : }
      73             : 
      74        4632 : CHIP_ERROR ASN1Reader::ExitConstructedType()
      75             : {
      76        4632 :     return ExitContainer();
      77             : }
      78             : 
      79         461 : CHIP_ERROR ASN1Reader::GetConstructedType(const uint8_t *& val, uint32_t & valLen)
      80             : {
      81         461 :     ReturnErrorCodeIf(!Constructed, ASN1_ERROR_INVALID_STATE);
      82             : 
      83         461 :     val    = mElemStart;
      84         461 :     valLen = mHeadLen + ValueLen;
      85             : 
      86         461 :     return CHIP_NO_ERROR;
      87             : }
      88         554 : CHIP_ERROR ASN1Reader::EnterEncapsulatedType()
      89             : {
      90         554 :     VerifyOrReturnError(Class == kASN1TagClass_Universal &&
      91             :                             (Tag == kASN1UniversalTag_OctetString || Tag == kASN1UniversalTag_BitString),
      92             :                         ASN1_ERROR_INVALID_STATE);
      93             : 
      94         554 :     ReturnErrorCodeIf(Constructed, ASN1_ERROR_UNSUPPORTED_ENCODING);
      95             : 
      96         554 :     return EnterContainer((Tag == kASN1UniversalTag_BitString) ? 1 : 0);
      97             : }
      98             : 
      99         531 : CHIP_ERROR ASN1Reader::ExitEncapsulatedType()
     100             : {
     101         531 :     return ExitContainer();
     102             : }
     103             : 
     104        5436 : CHIP_ERROR ASN1Reader::EnterContainer(uint32_t offset)
     105             : {
     106        5436 :     ReturnErrorCodeIf(mNumSavedContexts == kMaxContextDepth, ASN1_ERROR_MAX_DEPTH_EXCEEDED);
     107             : 
     108        5436 :     mSavedContexts[mNumSavedContexts].ElemStart     = mElemStart;
     109        5436 :     mSavedContexts[mNumSavedContexts].HeadLen       = mHeadLen;
     110        5436 :     mSavedContexts[mNumSavedContexts].ValueLen      = ValueLen;
     111        5436 :     mSavedContexts[mNumSavedContexts].IndefiniteLen = IndefiniteLen;
     112        5436 :     mSavedContexts[mNumSavedContexts].ContainerEnd  = mContainerEnd;
     113        5436 :     mNumSavedContexts++;
     114             : 
     115        5436 :     mElemStart = Value + offset;
     116        5436 :     if (!IndefiniteLen)
     117             :     {
     118        5436 :         VerifyOrReturnError(CanCastTo<uint32_t>(mBufEnd - Value), ASN1_ERROR_VALUE_OVERFLOW);
     119        5436 :         VerifyOrReturnError(static_cast<uint32_t>(mBufEnd - Value) >= ValueLen, ASN1_ERROR_VALUE_OVERFLOW);
     120        5436 :         mContainerEnd = Value + ValueLen;
     121             :     }
     122             : 
     123        5436 :     ResetElementState();
     124             : 
     125        5436 :     return CHIP_NO_ERROR;
     126             : }
     127             : 
     128        5163 : CHIP_ERROR ASN1Reader::ExitContainer()
     129             : {
     130        5163 :     ReturnErrorCodeIf(mNumSavedContexts == 0, ASN1_ERROR_INVALID_STATE);
     131             : 
     132        5163 :     ASN1ParseContext & prevContext = mSavedContexts[--mNumSavedContexts];
     133             : 
     134        5163 :     ReturnErrorCodeIf(prevContext.IndefiniteLen, ASN1_ERROR_UNSUPPORTED_ENCODING);
     135             : 
     136        5163 :     mElemStart = prevContext.ElemStart + prevContext.HeadLen + prevContext.ValueLen;
     137             : 
     138        5163 :     mContainerEnd = prevContext.ContainerEnd;
     139             : 
     140        5163 :     ResetElementState();
     141             : 
     142        5163 :     return CHIP_NO_ERROR;
     143             : }
     144             : 
     145           0 : bool ASN1Reader::IsContained() const
     146             : {
     147           0 :     return mNumSavedContexts > 0;
     148             : }
     149             : 
     150         425 : CHIP_ERROR ASN1Reader::GetInteger(int64_t & val)
     151             : {
     152         425 :     uint8_t encodedVal[sizeof(int64_t)] = { 0 };
     153         425 :     size_t valPaddingLen                = sizeof(int64_t) - ValueLen;
     154             : 
     155         425 :     ReturnErrorCodeIf(Value == nullptr, ASN1_ERROR_INVALID_STATE);
     156         425 :     ReturnErrorCodeIf(ValueLen < 1, ASN1_ERROR_INVALID_ENCODING);
     157         425 :     ReturnErrorCodeIf(ValueLen > sizeof(int64_t), ASN1_ERROR_VALUE_OVERFLOW);
     158         425 :     ReturnErrorCodeIf(mElemStart + mHeadLen + ValueLen > mContainerEnd, ASN1_ERROR_UNDERRUN);
     159             : 
     160         425 :     if ((*Value & 0x80) == 0x80)
     161             :     {
     162          19 :         for (size_t i = 0; i < valPaddingLen; i++)
     163             :         {
     164          15 :             encodedVal[i] = 0xFF;
     165             :         }
     166             :     }
     167         425 :     memcpy(&encodedVal[valPaddingLen], Value, ValueLen);
     168             : 
     169         425 :     val = static_cast<int64_t>(BigEndian::Get64(encodedVal));
     170             : 
     171         425 :     return CHIP_NO_ERROR;
     172             : }
     173             : 
     174         323 : CHIP_ERROR ASN1Reader::GetBoolean(bool & val)
     175             : {
     176         323 :     ReturnErrorCodeIf(Value == nullptr, ASN1_ERROR_INVALID_STATE);
     177         323 :     ReturnErrorCodeIf(ValueLen != 1, ASN1_ERROR_INVALID_ENCODING);
     178         323 :     ReturnErrorCodeIf(mElemStart + mHeadLen + ValueLen > mContainerEnd, ASN1_ERROR_UNDERRUN);
     179         323 :     VerifyOrReturnError(Value[0] == 0 || Value[0] == 0xFF, ASN1_ERROR_INVALID_ENCODING);
     180             : 
     181         323 :     val = (Value[0] != 0);
     182             : 
     183         323 :     return CHIP_NO_ERROR;
     184             : }
     185             : 
     186         251 : CHIP_ERROR ASN1Reader::GetUTCTime(ASN1UniversalTime & outTime)
     187             : {
     188             :     // Supported Encoding: YYMMDDHHMMSSZ
     189         251 :     ReturnErrorCodeIf(Value == nullptr, ASN1_ERROR_INVALID_STATE);
     190         251 :     ReturnErrorCodeIf(ValueLen < 1, ASN1_ERROR_INVALID_ENCODING);
     191         251 :     ReturnErrorCodeIf(mElemStart + mHeadLen + ValueLen > mContainerEnd, ASN1_ERROR_UNDERRUN);
     192         251 :     VerifyOrReturnError(ValueLen == 13 && Value[12] == 'Z', ASN1_ERROR_UNSUPPORTED_ENCODING);
     193             : 
     194         251 :     return outTime.ImportFrom_ASN1_TIME_string(CharSpan(reinterpret_cast<const char *>(Value), ValueLen));
     195             : }
     196             : 
     197           4 : CHIP_ERROR ASN1Reader::GetGeneralizedTime(ASN1UniversalTime & outTime)
     198             : {
     199             :     // Supported Encoding: YYYYMMDDHHMMSSZ
     200           4 :     ReturnErrorCodeIf(Value == nullptr, ASN1_ERROR_INVALID_STATE);
     201           4 :     ReturnErrorCodeIf(ValueLen < 1, ASN1_ERROR_INVALID_ENCODING);
     202           4 :     ReturnErrorCodeIf(mElemStart + mHeadLen + ValueLen > mContainerEnd, ASN1_ERROR_UNDERRUN);
     203           4 :     VerifyOrReturnError(ValueLen == 15 && Value[14] == 'Z', ASN1_ERROR_UNSUPPORTED_ENCODING);
     204             : 
     205           4 :     return outTime.ImportFrom_ASN1_TIME_string(CharSpan(reinterpret_cast<const char *>(Value), ValueLen));
     206             : }
     207             : 
     208         108 : static uint8_t ReverseBits(uint8_t v)
     209             : {
     210             :     // swap adjacent bits
     211         108 :     v = static_cast<uint8_t>(static_cast<uint8_t>((v >> 1) & 0x55) | static_cast<uint8_t>((v & 0x55) << 1));
     212             :     // swap adjacent bit pairs
     213         108 :     v = static_cast<uint8_t>(static_cast<uint8_t>((v >> 2) & 0x33) | static_cast<uint8_t>((v & 0x33) << 2));
     214             :     // swap nibbles
     215         108 :     v = static_cast<uint8_t>(static_cast<uint8_t>(v >> 4) | static_cast<uint8_t>(v << 4));
     216         108 :     return v;
     217             : }
     218             : 
     219         106 : CHIP_ERROR ASN1Reader::GetBitString(uint32_t & outVal)
     220             : {
     221             :     // NOTE: only supports DER encoding.
     222         106 :     ReturnErrorCodeIf(Value == nullptr, ASN1_ERROR_INVALID_STATE);
     223         106 :     ReturnErrorCodeIf(ValueLen < 1, ASN1_ERROR_INVALID_ENCODING);
     224         106 :     ReturnErrorCodeIf(ValueLen > 5, ASN1_ERROR_UNSUPPORTED_ENCODING);
     225         106 :     ReturnErrorCodeIf(mElemStart + mHeadLen + ValueLen > mContainerEnd, ASN1_ERROR_UNDERRUN);
     226             : 
     227         106 :     if (ValueLen == 1)
     228             :     {
     229           1 :         outVal = 0;
     230             :     }
     231             :     else
     232             :     {
     233         105 :         outVal    = ReverseBits(Value[1]);
     234         105 :         int shift = 8;
     235         108 :         for (uint32_t i = 2; i < ValueLen; i++, shift += 8)
     236             :         {
     237           3 :             outVal |= static_cast<uint32_t>(ReverseBits(Value[i]) << shift);
     238             :         }
     239             :     }
     240             : 
     241         106 :     return CHIP_NO_ERROR;
     242             : }
     243             : 
     244       10682 : CHIP_ERROR ASN1Reader::DecodeHead()
     245             : {
     246       10682 :     const uint8_t * p = mElemStart;
     247       10682 :     ReturnErrorCodeIf(p >= mBufEnd, ASN1_ERROR_UNDERRUN);
     248             : 
     249       10682 :     Class       = *p & 0xC0;
     250       10682 :     Constructed = (*p & 0x20) != 0;
     251       10682 :     Tag         = *p & 0x1F;
     252             : 
     253             :     // Only tags < 31 supported. The implication of this is that encoded tags are exactly 1 byte long.
     254       10682 :     VerifyOrReturnError(Tag < 0x1F, ASN1_ERROR_UNSUPPORTED_ENCODING);
     255             : 
     256       10676 :     p++;
     257       10676 :     ReturnErrorCodeIf(p >= mBufEnd, ASN1_ERROR_UNDERRUN);
     258             : 
     259       10676 :     if ((*p & 0x80) == 0)
     260             :     {
     261        9717 :         ValueLen      = *p & 0x7F;
     262        9717 :         IndefiniteLen = false;
     263        9717 :         p++;
     264             :     }
     265         959 :     else if (*p == 0x80)
     266             :     {
     267           0 :         ValueLen      = 0;
     268           0 :         IndefiniteLen = true;
     269           0 :         p++;
     270             :     }
     271             :     else
     272             :     {
     273         959 :         ValueLen       = 0;
     274         959 :         uint8_t lenLen = *p & 0x7F;
     275         959 :         p++;
     276        2278 :         for (; lenLen > 0; lenLen--, p++)
     277             :         {
     278        1319 :             ReturnErrorCodeIf(p >= mBufEnd, ASN1_ERROR_UNDERRUN);
     279        1319 :             ReturnErrorCodeIf((ValueLen & 0xFF000000) != 0, ASN1_ERROR_LENGTH_OVERFLOW);
     280        1319 :             ValueLen = (ValueLen << 8) | *p;
     281             :         }
     282         959 :         IndefiniteLen = false;
     283             :     }
     284             : 
     285       10676 :     VerifyOrReturnError(CanCastTo<uint32_t>(mBufEnd - p), ASN1_ERROR_VALUE_OVERFLOW);
     286       10676 :     VerifyOrReturnError(static_cast<uint32_t>(mBufEnd - p) >= ValueLen, ASN1_ERROR_VALUE_OVERFLOW);
     287       10676 :     VerifyOrReturnError(CanCastTo<uint32_t>(p - mElemStart), ASN1_ERROR_VALUE_OVERFLOW);
     288       10676 :     mHeadLen = static_cast<uint32_t>(p - mElemStart);
     289             : 
     290       10676 :     EndOfContents = (Class == kASN1TagClass_Universal && Tag == 0 && !Constructed && ValueLen == 0);
     291             : 
     292       10676 :     Value = p;
     293             : 
     294       10676 :     return CHIP_NO_ERROR;
     295             : }
     296             : 
     297       27934 : void ASN1Reader::ResetElementState()
     298             : {
     299       27934 :     Class         = 0;
     300       27934 :     Tag           = 0;
     301       27934 :     Value         = nullptr;
     302       27934 :     ValueLen      = 0;
     303       27934 :     Constructed   = false;
     304       27934 :     IndefiniteLen = false;
     305       27934 :     EndOfContents = false;
     306       27934 :     mHeadLen      = 0;
     307       27934 : }
     308             : 
     309           0 : CHIP_ERROR DumpASN1(ASN1Reader & asn1Parser, const char * prefix, const char * indent)
     310             : {
     311           0 :     CHIP_ERROR err = CHIP_NO_ERROR;
     312             : 
     313           0 :     if (indent == nullptr)
     314           0 :         indent = "  ";
     315             : 
     316           0 :     int nestLevel = 0;
     317             :     while (true)
     318             :     {
     319           0 :         err = asn1Parser.Next();
     320           0 :         if (err != CHIP_NO_ERROR)
     321             :         {
     322           0 :             if (err == ASN1_END)
     323             :             {
     324           0 :                 if (asn1Parser.IsContained())
     325             :                 {
     326           0 :                     err = asn1Parser.ExitConstructedType();
     327           0 :                     if (err != CHIP_NO_ERROR)
     328             :                     {
     329           0 :                         printf("ASN1Reader::ExitConstructedType() failed: %" CHIP_ERROR_FORMAT "\n", err.Format());
     330           0 :                         return err;
     331             :                     }
     332           0 :                     nestLevel--;
     333           0 :                     continue;
     334             :                 }
     335           0 :                 break;
     336             :             }
     337           0 :             printf("ASN1Reader::Next() failed: %" CHIP_ERROR_FORMAT "\n", err.Format());
     338           0 :             return err;
     339             :         }
     340           0 :         if (prefix != nullptr)
     341           0 :             printf("%s", prefix);
     342           0 :         for (int i = nestLevel; i; i--)
     343           0 :             printf("%s", indent);
     344           0 :         if (asn1Parser.IsEndOfContents())
     345           0 :             printf("END-OF-CONTENTS ");
     346           0 :         else if (asn1Parser.GetClass() == kASN1TagClass_Universal)
     347           0 :             switch (asn1Parser.GetTag())
     348             :             {
     349           0 :             case kASN1UniversalTag_Boolean:
     350           0 :                 printf("BOOLEAN ");
     351           0 :                 break;
     352           0 :             case kASN1UniversalTag_Integer:
     353           0 :                 printf("INTEGER ");
     354           0 :                 break;
     355           0 :             case kASN1UniversalTag_BitString:
     356           0 :                 printf("BIT STRING ");
     357           0 :                 break;
     358           0 :             case kASN1UniversalTag_OctetString:
     359           0 :                 printf("OCTET STRING ");
     360           0 :                 break;
     361           0 :             case kASN1UniversalTag_Null:
     362           0 :                 printf("NULL ");
     363           0 :                 break;
     364           0 :             case kASN1UniversalTag_ObjectId:
     365           0 :                 printf("OBJECT IDENTIFIER ");
     366           0 :                 break;
     367           0 :             case kASN1UniversalTag_ObjectDesc:
     368           0 :                 printf("OBJECT DESCRIPTOR ");
     369           0 :                 break;
     370           0 :             case kASN1UniversalTag_External:
     371           0 :                 printf("EXTERNAL ");
     372           0 :                 break;
     373           0 :             case kASN1UniversalTag_Real:
     374           0 :                 printf("REAL ");
     375           0 :                 break;
     376           0 :             case kASN1UniversalTag_Enumerated:
     377           0 :                 printf("ENUMERATED ");
     378           0 :                 break;
     379           0 :             case kASN1UniversalTag_Sequence:
     380           0 :                 printf("SEQUENCE ");
     381           0 :                 break;
     382           0 :             case kASN1UniversalTag_Set:
     383           0 :                 printf("SET ");
     384           0 :                 break;
     385           0 :             case kASN1UniversalTag_UTF8String:
     386             :             case kASN1UniversalTag_NumericString:
     387             :             case kASN1UniversalTag_PrintableString:
     388             :             case kASN1UniversalTag_T61String:
     389             :             case kASN1UniversalTag_VideotexString:
     390             :             case kASN1UniversalTag_IA5String:
     391             :             case kASN1UniversalTag_GraphicString:
     392             :             case kASN1UniversalTag_VisibleString:
     393             :             case kASN1UniversalTag_GeneralString:
     394             :             case kASN1UniversalTag_UniversalString:
     395           0 :                 printf("STRING ");
     396           0 :                 break;
     397           0 :             case kASN1UniversalTag_UTCTime:
     398             :             case kASN1UniversalTag_GeneralizedTime:
     399           0 :                 printf("TIME ");
     400           0 :                 break;
     401           0 :             default:
     402           0 :                 printf("[UNIVERSAL %lu] ", static_cast<unsigned long>(asn1Parser.GetTag()));
     403           0 :                 break;
     404             :             }
     405           0 :         else if (asn1Parser.GetClass() == kASN1TagClass_Application)
     406           0 :             printf("[APPLICATION %lu] ", static_cast<unsigned long>(asn1Parser.GetTag()));
     407           0 :         else if (asn1Parser.GetClass() == kASN1TagClass_ContextSpecific)
     408           0 :             printf("[%lu] ", static_cast<unsigned long>(asn1Parser.GetTag()));
     409           0 :         else if (asn1Parser.GetClass() == kASN1TagClass_Private)
     410           0 :             printf("[PRIVATE %lu] ", static_cast<unsigned long>(asn1Parser.GetTag()));
     411             : 
     412           0 :         if (asn1Parser.IsConstructed())
     413           0 :             printf("(constructed) ");
     414             : 
     415           0 :         if (asn1Parser.IsIndefiniteLen())
     416           0 :             printf("Length = indefinite\n");
     417             :         else
     418           0 :             printf("Length = %ld\n", static_cast<long>(asn1Parser.GetValueLen()));
     419             : 
     420           0 :         if (asn1Parser.IsConstructed())
     421             :         {
     422           0 :             err = asn1Parser.EnterConstructedType();
     423           0 :             if (err != CHIP_NO_ERROR)
     424             :             {
     425           0 :                 printf("ASN1Reader::EnterConstructedType() failed: %" CHIP_ERROR_FORMAT "\n", err.Format());
     426           0 :                 return err;
     427             :             }
     428           0 :             nestLevel++;
     429             :         }
     430           0 :     }
     431             : 
     432           0 :     return err;
     433             : }
     434             : 
     435             : } // namespace ASN1
     436             : } // namespace chip

Generated by: LCOV version 1.14