• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 5134090420

31 May 2023 03:12PM UTC coverage: 91.721% (-0.3%) from 91.995%
5134090420

push

github

randombit
Merge GH #3565 Disable noisy/pointless pylint warnings

76048 of 82912 relevant lines covered (91.72%)

11755290.1 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.96
/src/tests/test_asn1.cpp
1
/*
2
* (C) 2017 Jack Lloyd
3
*
4
* Botan is released under the Simplified BSD License (see license.txt)
5
*/
6

7
#include "tests.h"
8

9
#if defined(BOTAN_HAS_ASN1)
10
   #include <botan/asn1_print.h>
11
   #include <botan/ber_dec.h>
12
   #include <botan/der_enc.h>
13
#endif
14

15
namespace Botan_Tests {
16

17
#if defined(BOTAN_HAS_ASN1)
18

19
namespace {
20

21
Test::Result test_ber_stack_recursion() {
1✔
22
   Test::Result result("BER stack recursion");
1✔
23

24
   // OSS-Fuzz #813 GitHub #989
25

26
   try {
1✔
27
      const std::vector<uint8_t> in(10000000, 0);
1✔
28
      Botan::DataSource_Memory input(in.data(), in.size());
1✔
29
      Botan::BER_Decoder dec(input);
1✔
30

31
      while(dec.more_items()) {
2✔
32
         Botan::BER_Object obj;
1✔
33
         dec.get_next(obj);
1✔
34
      }
1✔
35
   } catch(Botan::Decoding_Error&) {}
3✔
36

37
   result.test_success("No crash");
1✔
38

39
   return result;
1✔
40
}
×
41

42
Test::Result test_ber_eoc_decoding_limits() {
1✔
43
   Test::Result result("BER nested indefinite length");
1✔
44

45
   // OSS-Fuzz #4353
46

47
   Botan::ASN1_Pretty_Printer printer;
1✔
48

49
   size_t max_eoc_allowed = 0;
1✔
50

51
   for(size_t len = 1; len < 1024; ++len) {
17✔
52
      std::vector<uint8_t> buf(4 * len);
17✔
53

54
      /*
55
      This constructs a len deep sequence of SEQUENCES each with
56
      an indefinite length
57
      */
58
      for(size_t i = 0; i != 2 * len; i += 2) {
170✔
59
         buf[i] = 0x30;
153✔
60
         buf[i + 1] = 0x80;
153✔
61
      }
62
      // remainder of values left as zeros (EOC markers)
63

64
      try {
17✔
65
         printer.print(buf);
33✔
66
      } catch(Botan::BER_Decoding_Error&) {
1✔
67
         max_eoc_allowed = len - 1;
1✔
68
         break;
1✔
69
      }
1✔
70
   }
17✔
71

72
   result.test_eq("EOC limited to prevent stack exhaustion", max_eoc_allowed, 16);
1✔
73

74
   return result;
1✔
75
}
1✔
76

77
Test::Result test_asn1_utf8_ascii_parsing() {
1✔
78
   Test::Result result("ASN.1 ASCII parsing");
1✔
79

80
   try {
1✔
81
      // \x13 - ASN1 tag for 'printable string'
82
      // \x06 - 6 characters of payload
83
      // ...  - UTF-8 encoded (ASCII chars only) word 'Moscow'
84
      const std::string moscow = "\x13\x06\x4D\x6F\x73\x63\x6F\x77";
1✔
85
      const std::string moscow_plain = "Moscow";
1✔
86
      Botan::DataSource_Memory input(moscow);
1✔
87
      Botan::BER_Decoder dec(input);
1✔
88

89
      Botan::ASN1_String str;
1✔
90
      str.decode_from(dec);
1✔
91

92
      result.test_eq("value()", str.value(), moscow_plain);
1✔
93
   } catch(const Botan::Decoding_Error& ex) {
2✔
94
      result.test_failure(ex.what());
×
95
   }
×
96

97
   return result;
1✔
98
}
×
99

100
Test::Result test_asn1_utf8_parsing() {
1✔
101
   Test::Result result("ASN.1 UTF-8 parsing");
1✔
102

103
   try {
1✔
104
      // \x0C - ASN1 tag for 'UTF8 string'
105
      // \x0C - 12 characters of payload
106
      // ...  - UTF-8 encoded russian word for Moscow in cyrillic script
107
      const std::string moscow = "\x0C\x0C\xD0\x9C\xD0\xBE\xD1\x81\xD0\xBA\xD0\xB2\xD0\xB0";
1✔
108
      const std::string moscow_plain = "\xD0\x9C\xD0\xBE\xD1\x81\xD0\xBA\xD0\xB2\xD0\xB0";
1✔
109
      Botan::DataSource_Memory input(moscow);
1✔
110
      Botan::BER_Decoder dec(input);
1✔
111

112
      Botan::ASN1_String str;
1✔
113
      str.decode_from(dec);
1✔
114

115
      result.test_eq("value()", str.value(), moscow_plain);
1✔
116
   } catch(const Botan::Decoding_Error& ex) {
2✔
117
      result.test_failure(ex.what());
×
118
   }
×
119

120
   return result;
1✔
121
}
×
122

123
Test::Result test_asn1_ucs2_parsing() {
1✔
124
   Test::Result result("ASN.1 BMP string (UCS-2) parsing");
1✔
125

126
   try {
1✔
127
      // \x1E     - ASN1 tag for 'BMP (UCS-2) string'
128
      // \x0C     - 12 characters of payload
129
      // ...      - UCS-2 encoding for Moscow in cyrillic script
130
      const std::string moscow = "\x1E\x0C\x04\x1C\x04\x3E\x04\x41\x04\x3A\x04\x32\x04\x30";
1✔
131
      const std::string moscow_plain = "\xD0\x9C\xD0\xBE\xD1\x81\xD0\xBA\xD0\xB2\xD0\xB0";
1✔
132

133
      Botan::DataSource_Memory input(moscow);
1✔
134
      Botan::BER_Decoder dec(input);
1✔
135

136
      Botan::ASN1_String str;
1✔
137
      str.decode_from(dec);
1✔
138

139
      result.test_eq("value()", str.value(), moscow_plain);
1✔
140
   } catch(const Botan::Decoding_Error& ex) {
2✔
141
      result.test_failure(ex.what());
×
142
   }
×
143

144
   return result;
1✔
145
}
×
146

147
Test::Result test_asn1_ucs4_parsing() {
1✔
148
   Test::Result result("ASN.1 universal string (UCS-4) parsing");
1✔
149

150
   try {
1✔
151
      // \x1C - ASN1 tag for 'universal string'
152
      // \x18 - 24 characters of payload
153
      // ...  - UCS-4 encoding for Moscow in cyrillic script
154
      const uint8_t moscow[] =
1✔
155
         "\x1C\x18\x00\x00\x04\x1C\x00\x00\x04\x3E\x00\x00\x04\x41\x00\x00\x04\x3A\x00\x00\x04\x32\x00\x00\x04\x30";
156
      const std::string moscow_plain = "\xD0\x9C\xD0\xBE\xD1\x81\xD0\xBA\xD0\xB2\xD0\xB0";
2✔
157
      Botan::DataSource_Memory input(moscow, sizeof(moscow));
1✔
158
      Botan::BER_Decoder dec(input);
1✔
159

160
      Botan::ASN1_String str;
1✔
161
      str.decode_from(dec);
1✔
162

163
      result.test_eq("value()", str.value(), moscow_plain);
1✔
164
   } catch(const Botan::Decoding_Error& ex) {
2✔
165
      result.test_failure(ex.what());
×
166
   }
×
167

168
   return result;
1✔
169
}
×
170

171
Test::Result test_asn1_ascii_encoding() {
1✔
172
   Test::Result result("ASN.1 ASCII encoding");
1✔
173

174
   try {
1✔
175
      // UTF-8 encoded (ASCII chars only) word 'Moscow'
176
      const std::string moscow = "\x4D\x6F\x73\x63\x6F\x77";
1✔
177
      Botan::ASN1_String str(moscow);
1✔
178

179
      Botan::DER_Encoder enc;
1✔
180

181
      str.encode_into(enc);
1✔
182
      auto encodingResult = enc.get_contents();
1✔
183

184
      // \x13 - ASN1 tag for 'printable string'
185
      // \x06 - 6 characters of payload
186
      const auto moscowEncoded = Botan::hex_decode("13064D6F73636F77");
1✔
187
      result.test_eq("encoding result", encodingResult, moscowEncoded);
1✔
188

189
      result.test_success("No crash");
2✔
190
   } catch(const std::exception& ex) {
2✔
191
      result.test_failure(ex.what());
×
192
   }
×
193

194
   return result;
1✔
195
}
×
196

197
Test::Result test_asn1_utf8_encoding() {
1✔
198
   Test::Result result("ASN.1 UTF-8 encoding");
1✔
199

200
   try {
1✔
201
      // UTF-8 encoded russian word for Moscow in cyrillic script
202
      const std::string moscow = "\xD0\x9C\xD0\xBE\xD1\x81\xD0\xBA\xD0\xB2\xD0\xB0";
1✔
203
      Botan::ASN1_String str(moscow);
1✔
204

205
      Botan::DER_Encoder enc;
1✔
206

207
      str.encode_into(enc);
1✔
208
      auto encodingResult = enc.get_contents();
1✔
209

210
      // \x0C - ASN1 tag for 'UTF8 string'
211
      // \x0C - 12 characters of payload
212
      const auto moscowEncoded = Botan::hex_decode("0C0CD09CD0BED181D0BAD0B2D0B0");
1✔
213
      result.test_eq("encoding result", encodingResult, moscowEncoded);
1✔
214

215
      result.test_success("No crash");
2✔
216
   } catch(const std::exception& ex) {
2✔
217
      result.test_failure(ex.what());
×
218
   }
×
219

220
   return result;
1✔
221
}
×
222

223
Test::Result test_asn1_tag_underlying_type() {
1✔
224
   Test::Result result("ASN.1 class and type underlying type");
1✔
225

226
   if constexpr(std::is_same_v<std::underlying_type_t<Botan::ASN1_Class>, std::underlying_type_t<Botan::ASN1_Type>>) {
1✔
227
      if constexpr(!std::is_same_v<std::underlying_type_t<Botan::ASN1_Class>,
1✔
228
                                   std::invoke_result_t<decltype(&Botan::BER_Object::tagging), Botan::BER_Object>>) {
229
         result.test_failure(
230
            "Return type of BER_Object::tagging() is different than the underlying type of ASN1_Class");
231
      } else {
232
         result.test_success("Same types");
1✔
233
      }
234
   } else {
235
      result.test_failure("ASN1_Class and ASN1_Type have different underlying types");
236
   }
237

238
   return result;
1✔
239
}
×
240

241
}  // namespace
242

243
class ASN1_Tests final : public Test {
×
244
   public:
245
      std::vector<Test::Result> run() override {
1✔
246
         std::vector<Test::Result> results;
1✔
247

248
         results.push_back(test_ber_stack_recursion());
2✔
249
         results.push_back(test_ber_eoc_decoding_limits());
2✔
250
         results.push_back(test_asn1_utf8_ascii_parsing());
2✔
251
         results.push_back(test_asn1_utf8_parsing());
2✔
252
         results.push_back(test_asn1_ucs2_parsing());
2✔
253
         results.push_back(test_asn1_ucs4_parsing());
2✔
254
         results.push_back(test_asn1_ascii_encoding());
2✔
255
         results.push_back(test_asn1_utf8_encoding());
2✔
256
         results.push_back(test_asn1_tag_underlying_type());
2✔
257

258
         return results;
1✔
259
      }
×
260
};
261

262
BOTAN_REGISTER_TEST("asn1", "asn1_encoding", ASN1_Tests);
263

264
class ASN1_Time_Parsing_Tests final : public Text_Based_Test {
×
265
   public:
266
      ASN1_Time_Parsing_Tests() : Text_Based_Test("asn1_time.vec", "Tspec") {}
2✔
267

268
      Test::Result run_one_test(const std::string& tag_str, const VarMap& vars) override {
25✔
269
         Test::Result result("ASN.1 date parsing");
25✔
270

271
         const std::string tspec = vars.get_req_str("Tspec");
25✔
272

273
         if(tag_str != "UTC" && tag_str != "UTC.invalid" && tag_str != "Generalized" &&
25✔
274
            tag_str != "Generalized.invalid") {
11✔
275
            throw Test_Error("Invalid tag value in ASN1 date parsing test");
×
276
         }
277

278
         const Botan::ASN1_Type tag = (tag_str == "UTC" || tag_str == "UTC.invalid")
24✔
279
                                         ? Botan::ASN1_Type::UtcTime
25✔
280
                                         : Botan::ASN1_Type::GeneralizedTime;
25✔
281

282
         const bool valid = tag_str.find(".invalid") == std::string::npos;
25✔
283

284
         if(valid) {
25✔
285
            Botan::ASN1_Time time(tspec, tag);
13✔
286
            result.test_success("Accepted valid time");
26✔
287
         } else {
13✔
288
            result.test_throws("Invalid time rejected", [=]() { Botan::ASN1_Time time(tspec, tag); });
108✔
289
         }
290

291
         return result;
25✔
292
      }
25✔
293
};
294

295
BOTAN_REGISTER_TEST("asn1", "asn1_time", ASN1_Time_Parsing_Tests);
296

297
class ASN1_Printer_Tests final : public Test {
×
298
   public:
299
      std::vector<Test::Result> run() override {
1✔
300
         Test::Result result("ASN1_Pretty_Printer");
1✔
301

302
         Botan::ASN1_Pretty_Printer printer;
1✔
303

304
         const size_t num_tests = 6;
1✔
305

306
         for(size_t i = 1; i <= num_tests; ++i) {
7✔
307
            std::string i_str = std::to_string(i);
6✔
308
            const std::vector<uint8_t> input1 = Test::read_binary_data_file("asn1_print/input" + i_str + ".der");
12✔
309
            const std::string expected1 = Test::read_data_file("asn1_print/output" + i_str + ".txt");
12✔
310

311
            result.test_eq("Test " + i_str, printer.print(input1), expected1);
18✔
312
         }
12✔
313

314
         return {result};
2✔
315
      }
1✔
316
};
317

318
BOTAN_REGISTER_TEST("asn1", "asn1_printer", ASN1_Printer_Tests);
319

320
#endif
321

322
}  // namespace Botan_Tests
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc