LCOV - code coverage report
Current view: top level - core/crypto - SPCryptoAsn1.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 122 182 67.0 %
Date: 2024-05-12 00:16:13 Functions: 16 26 61.5 %

          Line data    Source code
       1             : /**
       2             :  Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
       3             : 
       4             :  Permission is hereby granted, free of charge, to any person obtaining a copy
       5             :  of this software and associated documentation files (the "Software"), to deal
       6             :  in the Software without restriction, including without limitation the rights
       7             :  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       8             :  copies of the Software, and to permit persons to whom the Software is
       9             :  furnished to do so, subject to the following conditions:
      10             : 
      11             :  The above copyright notice and this permission notice shall be included in
      12             :  all copies or substantial portions of the Software.
      13             : 
      14             :  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      17             :  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      18             :  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      19             :  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      20             :  THE SOFTWARE.
      21             :  **/
      22             : 
      23             : #ifndef CORE_CRYPTO_SPCRYPTOASN1_H_
      24             : #define CORE_CRYPTO_SPCRYPTOASN1_H_
      25             : 
      26             : #include "SPCommon.h"
      27             : 
      28             : namespace STAPPLER_VERSIONIZED stappler::crypto {
      29             : 
      30             : template <typename T>
      31             : struct Asn1DecoderTraits {
      32             :         using success = char;
      33             :         using failure = long;
      34             : 
      35             :         InvokerCallTest_MakeCallTest(onBeginSet, success, failure);
      36             :         InvokerCallTest_MakeCallTest(onEndSet, success, failure);
      37             :         InvokerCallTest_MakeCallTest(onBeginSequence, success, failure);
      38             :         InvokerCallTest_MakeCallTest(onEndSequence, success, failure);
      39             :         InvokerCallTest_MakeCallTest(onOid, success, failure);
      40             :         InvokerCallTest_MakeCallTest(onNull, success, failure);
      41             :         InvokerCallTest_MakeCallTest(onInteger, success, failure);
      42             :         InvokerCallTest_MakeCallTest(onBigInteger, success, failure);
      43             :         InvokerCallTest_MakeCallTest(onBoolean, success, failure);
      44             :         InvokerCallTest_MakeCallTest(onBytes, success, failure);
      45             :         InvokerCallTest_MakeCallTest(onString, success, failure);
      46             :         InvokerCallTest_MakeCallTest(onCustom, success, failure);
      47             : };
      48             : 
      49             : template <typename Interface, typename ReaderType, typename Traits = Asn1DecoderTraits<ReaderType>>
      50             : struct Asn1Decoder {
      51             :         using Bytes = typename Interface::BytesType;
      52             :         using StringStream = typename Interface::StringStreamType;
      53             : 
      54             :         enum Type : uint8_t {
      55             :                 Boolean = 0x01,
      56             :                 Integer = 0x02,
      57             :                 BitString = 0x03,
      58             :                 OctetString = 0x04,
      59             :                 Null = 0x05,
      60             :                 Oid = 0x06,
      61             :                 Utf8String = 0x0C,
      62             :                 Sequence = 0x10,
      63             :                 Set = 0x11,
      64             :                 PrintableString = 0x13,
      65             :                 T61String = 0x14,
      66             :                 AsciiString = 0x16,
      67             :                 UtcTime = 0x17,
      68             :                 Time = 0x18,
      69             :                 UniversalString = 0x1C,
      70             :                 BmpString = 0x1E,
      71             :                 HighForm = 0x1F,
      72             :                 Primitive = 0x00,
      73             : 
      74             :                 ConstructedBit = 0x20,
      75             :                 ContextSpecificBit = 0x80,
      76             :         };
      77             : 
      78       13450 :         size_t decodeSize(BytesViewNetwork &r) {
      79       13450 :                 size_t size = 0;
      80       13450 :                 auto sizeByte = r.readUnsigned();
      81       13450 :                 if (sizeByte & 0x80) {
      82        3174 :                         auto count = sizeByte & (~0x80);
      83        3174 :                         switch (count) {
      84        1151 :                         case 1: size = r.readUnsigned(); break;
      85        2023 :                         case 2: size = r.readUnsigned16(); break;
      86           0 :                         case 3: size = r.readUnsigned24(); break;
      87           0 :                         case 4: size = r.readUnsigned32(); break;
      88           0 :                         case 8: size = r.readUnsigned64(); break;
      89           0 :                         default: return 0; break;
      90             :                         }
      91             :                 } else {
      92       10276 :                         size = sizeByte;
      93             :                 }
      94       13450 :                 return size;
      95             :         }
      96             : 
      97       13450 :         bool decodeValue(ReaderType &reader, BytesViewNetwork &r) {
      98       13450 :                 auto b = r.readUnsigned();
      99       13450 :                 Type type = Type(b & 0x1F);
     100       13450 :                 switch (type) {
     101          25 :                 case Primitive:
     102          25 :                         if (b & (ContextSpecificBit | ConstructedBit)) {
     103          25 :                                 return decodeAny(reader, r);
     104             :                         } else {
     105           0 :                                 return decodeUnknown(reader, r, b);
     106             :                         }
     107             :                         break;
     108           0 :                 case Boolean: return decodeBoolean(reader, r); break;
     109        2100 :                 case Integer: return decodeInteger(reader, r); break;
     110        3125 :                 case Oid: return decodeOid(reader, r); break;
     111        5050 :                 case Sequence: return decodeSequence(reader, r); break;
     112         150 :                 case Set: return decodeSet(reader, r); break;
     113        1250 :                 case OctetString: return decodeOctetString(reader, r); break;
     114         825 :                 case Null:
     115         825 :                         r += decodeSize(r);
     116             :                         if constexpr (Traits::onNull) {
     117         825 :                                 reader.onNull(*this);
     118             :                         } else if constexpr (Traits::onCustom) {
     119           0 :                                 reader.onCustom(*this, uint8_t(type), BytesViewNetwork());
     120             :                         }
     121         825 :                         return true;
     122             :                         break;
     123         200 :                 case Utf8String:
     124             :                 case UniversalString:
     125             :                 case AsciiString:
     126             :                 case PrintableString:
     127             :                 case T61String:
     128             :                 case BmpString:
     129             :                 case UtcTime:
     130             :                 case Time:
     131         200 :                         return decodeString(reader, r, type);
     132             :                         break;
     133           0 :                 case HighForm:
     134           0 :                         return false;
     135             :                         break;
     136         725 :                 case BitString:
     137         725 :                         return decodeBitString(reader, r, b & ConstructedBit);
     138             :                         break;
     139           0 :                 default:
     140           0 :                         return decodeUnknown(reader, r, b); break;
     141             :                 }
     142             :                 return false;
     143             :         }
     144             : 
     145        5050 :         bool decodeSequence(ReaderType &reader, BytesViewNetwork &r) {
     146        5050 :                 auto size = decodeSize(r);
     147        5050 :                 if (size == 0) {
     148           0 :                         return false;
     149             :                 }
     150             : 
     151        5050 :                 BytesViewNetwork nextR(r.data(), size);
     152        5050 :                 r += size;
     153             : 
     154        5050 :                 if constexpr (Traits::onBeginSequence) { reader.onBeginSequence(*this); }
     155       16825 :                 while(!nextR.empty()) {
     156       11775 :                         if (!decodeValue(reader, nextR)) {
     157           0 :                                 if constexpr (Traits::onEndSequence) { reader.onEndSequence(*this); }
     158           0 :                                 return false;
     159             :                         }
     160             :                 }
     161        5050 :                 if constexpr (Traits::onEndSequence) { reader.onEndSequence(*this); }
     162             : 
     163        5050 :                 return true;
     164             :         }
     165             : 
     166         150 :         bool decodeSet(ReaderType &reader, BytesViewNetwork &r) {
     167         150 :                 auto size = decodeSize(r);
     168         150 :                 if (size == 0) {
     169           0 :                         return false;
     170             :                 }
     171             : 
     172         150 :                 BytesViewNetwork nextR(r.data(), size);
     173         150 :                 r += size;
     174             : 
     175         150 :                 if constexpr (Traits::onBeginSet) { reader.onBeginSet(*this); }
     176         300 :                 while(!nextR.empty()) {
     177         150 :                         if (!decodeValue(reader, nextR)) {
     178           0 :                                 if constexpr (Traits::onEndSet) { reader.onEndSet(*this); }
     179           0 :                                 return false;
     180             :                         }
     181             :                 }
     182         150 :                 if constexpr (Traits::onEndSet) { reader.onEndSet(*this); }
     183             : 
     184         150 :                 return true;
     185             :         }
     186             : 
     187           0 :         bool decodeUnknown(ReaderType &reader, BytesViewNetwork &r, uint8_t t) {
     188           0 :                 auto size = decodeSize(r);
     189           0 :                 r += size;
     190             : 
     191           0 :                 if constexpr (Traits::onCustom) { reader.onCustom(*this, t, BytesViewNetwork(r.data(), size)); }
     192           0 :                 return true;
     193             :         }
     194             : 
     195          25 :         bool decodeAny(ReaderType &reader, BytesViewNetwork &r) {
     196          25 :                 auto size = decodeSize(r);
     197          25 :                 if (size == 0) {
     198           0 :                         return false;
     199             :                 }
     200             : 
     201          25 :                 BytesViewNetwork nextR(r.data(), size);
     202          25 :                 if (decodeValue(reader, nextR)) {
     203          25 :                         r += size;
     204          25 :                         return true;
     205             :                 }
     206           0 :                 return false;
     207             :         }
     208             : 
     209        3125 :         bool decodeOid(ReaderType &reader, BytesViewNetwork &r) {
     210        3125 :                 auto size = decodeSize(r);
     211        3125 :                 if (size == 0) {
     212           0 :                         return false;
     213             :                 }
     214             : 
     215        3125 :                 StringStream str;
     216             : 
     217        3125 :                 BytesViewNetwork nextR(r.data(), size);
     218             : 
     219        3125 :                 auto first = nextR.readUnsigned();
     220             : 
     221        3125 :                 str << int(first / 40) << "." << int(first % 40);
     222             : 
     223        3125 :                 uint32_t accum = 0;
     224       25875 :                 while (!nextR.empty()) {
     225       22750 :                         auto value = nextR.readUnsigned();
     226       22750 :                         if (value & 0x80) {
     227        6425 :                                 accum = accum << 7 | (value & (~0x80));
     228             :                         } else {
     229       16325 :                                 str << "." << (accum << 7 | value);
     230       16325 :                                 accum = 0;
     231             :                         }
     232             :                 }
     233             : 
     234             : 
     235             :                 if constexpr (Traits::onOid) {
     236        3125 :                         reader.onOid(*this, str.str());
     237             :                 } else if constexpr (Traits::onCustom) {
     238           0 :                         reader.onCustom(*this, uint8_t(Oid), BytesViewNetwork(r.data(), size));
     239             :                 }
     240             : 
     241        3125 :                 r += size;
     242             : 
     243        3125 :                 return true;
     244        3125 :         }
     245             : 
     246        2100 :         bool decodeInteger(ReaderType &reader, BytesViewNetwork &r) {
     247        2100 :                 auto size = decodeSize(r);
     248        2100 :                 if (size == 0) {
     249           0 :                         return false;
     250             :                 }
     251             : 
     252             :                 if constexpr (Traits::onInteger) {
     253        2050 :                         switch(size) {
     254         525 :                         case 1: reader.onInteger(*this, reinterpretValue<int8_t>(r.readUnsigned())); break;
     255         150 :                         case 2: reader.onInteger(*this, reinterpretValue<int16_t>(r.readUnsigned16())); break;
     256         300 :                         case 3: {
     257         300 :                                 auto val = r.readUnsigned24();
     258         300 :                                 if (val <= 0x7FFFFF) {
     259         300 :                                         reader.onInteger(*this, val);
     260             :                                 } else {
     261           0 :                                         reader.onInteger(*this, val - 0x1000000);
     262             :                                 }
     263             :                         }
     264         300 :                                 break;
     265           0 :                         case 4: reader.onInteger(*this, reinterpretValue<int32_t>(r.readUnsigned32())); break;
     266           0 :                         case 8: reader.onInteger(*this, reinterpretValue<int64_t>(r.readUnsigned64())); break;
     267        1075 :                         default:
     268        1075 :                                 if (size >= 8) {
     269             :                                         if constexpr (Traits::onBigInteger) {
     270        1075 :                                                 reader.onBigInteger(*this, BytesViewNetwork(r.data(), size));
     271        1075 :                                                 r += size;
     272             :                                         } else {
     273             :                                                 return false;
     274             :                                         }
     275             :                                 } else {
     276           0 :                                         uint64_t accum = 0;
     277           0 :                                         for (uint32_t i = 0; i < size; ++ i) {
     278           0 :                                                 accum = (accum << 8) | r.readUnsigned();
     279             :                                         }
     280           0 :                                         uint64_t base = 1ULL << (size * 8 - 1);
     281           0 :                                         if (accum > base) {
     282           0 :                                                 reader.onInteger(*this, accum - (1ULL << (size * 8)));
     283             :                                         } else {
     284           0 :                                                 reader.onInteger(*this, accum);
     285             :                                         }
     286             :                                 }
     287             : 
     288        1075 :                                 break;
     289             :                         }
     290             :                 } else if constexpr (Traits::onBigInteger) {
     291          50 :                         reader.onBigInteger(*this, BytesViewNetwork(r.data(), size));
     292          50 :                         r += size;
     293             :                 } else if constexpr (Traits::onCustom) {
     294             :                         reader.onCustom(*this, uint8_t(Integer), BytesViewNetwork(r.data(), size));
     295             :                         r += size;
     296             :                 } else {
     297             :                         r += size;
     298             :                 }
     299             : 
     300        2100 :                 return true;
     301             :         }
     302             : 
     303           0 :         bool decodeBoolean(ReaderType &reader, BytesViewNetwork &r) {
     304           0 :                 auto size = decodeSize(r);
     305           0 :                 if (size == 1) {
     306             :                         if constexpr (Traits::onBoolean) {
     307           0 :                                 auto value = r.readUnsigned();
     308           0 :                                 reader.onBoolean(*this, value != 0);
     309             :                         } else if constexpr (Traits::onCustom) {
     310           0 :                                 reader.onCustom(*this, uint8_t(Boolean), BytesViewNetwork(r.data(), size));
     311           0 :                                 r += size;
     312             :                         }
     313           0 :                         return true;
     314             :                 }
     315             : 
     316           0 :                 return false;
     317             :         }
     318             : 
     319        1250 :         bool decodeOctetString(ReaderType &reader, BytesViewNetwork &r) {
     320        1250 :                 auto size = decodeSize(r);
     321        1250 :                 if (size > 0) {
     322             :                         if constexpr (Traits::onBytes) {
     323        1250 :                                 reader.onBytes(*this, BytesViewNetwork(r.data(), size));
     324             :                         } else if constexpr (Traits::onCustom) {
     325           0 :                                 reader.onCustom(*this, uint8_t(OctetString), BytesViewNetwork(r.data(), size));
     326             :                         }
     327        1250 :                         r += size;
     328        1250 :                         return true;
     329             :                 }
     330             : 
     331           0 :                 return true;
     332             :         }
     333             : 
     334         200 :         bool decodeString(ReaderType &reader, BytesViewNetwork &r, Type t) {
     335         200 :                 auto size = decodeSize(r);
     336             :                 if constexpr (Traits::onString) {
     337         200 :                         reader.onString(*this, BytesViewNetwork(r.data(), size), t);
     338             :                 } else if constexpr (Traits::onCustom) {
     339           0 :                         reader.onCustom(*this, uint8_t(t), BytesViewNetwork(r.data(), size));
     340             :                 }
     341         200 :                 r += size;
     342         200 :                 return true;
     343             :         }
     344             : 
     345         725 :         bool decodeBitString(ReaderType &reader, BytesViewNetwork &r, bool constructed) {
     346         725 :                 auto size = decodeSize(r);
     347             : 
     348         725 :                 if (!constructed) {
     349         700 :                         if (size > 1) {
     350         700 :                                 auto unused = r.readUnsigned();
     351             : 
     352         700 :                                 if (unused > 0 && unused < 8) {
     353           0 :                                         Bytes b; b.resize(size  - 1);
     354           0 :                                         memcpy(b.data(), r.data(), size - 1);
     355             : 
     356           0 :                                         uint8_t mask = 0xFF << unused;
     357           0 :                                         b.back() = b.back() & mask;
     358             : 
     359             :                                         if constexpr (Traits::onBytes) {
     360           0 :                                                 reader.onBytes(*this, BytesViewNetwork(b.data(), b.size()));
     361             :                                         } else if constexpr (Traits::onCustom) {
     362           0 :                                                 reader.onCustom(*this, uint8_t(BitString), BytesViewNetwork(b.data(), b.size()));
     363             :                                         }
     364           0 :                                         r += size - 1;
     365           0 :                                         return true;
     366         700 :                                 } else if (unused == 0) {
     367             :                                         if constexpr (Traits::onBytes) {
     368         700 :                                                 reader.onBytes(*this, BytesViewNetwork(r.data(), size - 1));
     369             :                                         } else if constexpr (Traits::onCustom) {
     370           0 :                                                 reader.onCustom(*this, uint8_t(BitString), BytesViewNetwork(r.data(), size - 1));
     371             :                                         }
     372         700 :                                         r += size - 1;
     373         700 :                                         return true;
     374             :                                 }
     375             :                         }
     376           0 :                         return false;
     377             :                 } else {
     378          25 :                         r += size;
     379          25 :                         return true;
     380             :                 }
     381             :         }
     382             : 
     383             :         bool decode(ReaderType &reader, const Bytes &source) {
     384             :                 return decode(reader, BytesViewNetwork(source));
     385             :         }
     386             : 
     387        1500 :         bool decode(ReaderType &reader, const BytesViewNetwork &source) {
     388        1500 :                 BytesViewNetwork r(source);
     389             : 
     390        3000 :                 while (!r.empty()) {
     391        1500 :                         if (!decodeValue(reader, r)) {
     392           0 :                                 return false;
     393             :                         }
     394             :                 }
     395             : 
     396        1500 :                 return true;
     397             :         }
     398             : };
     399             : 
     400             : }
     401             : 
     402             : #endif /* CORE_CRYPTO_SPCRYPTOASN1_H_ */

Generated by: LCOV version 1.14