scclib
Stable Cloud Computing C++ Library
der.cc
Go to the documentation of this file.
1 /*
2 BSD 3-Clause License
3 
4 Copyright (c) 2022, Stable Cloud Computing, Inc.
5 
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8 
9 1. Redistributions of source code must retain the above copyright notice, this
10  list of conditions and the following disclaimer.
11 
12 2. Redistributions in binary form must reproduce the above copyright notice,
13  this list of conditions and the following disclaimer in the documentation
14  and/or other materials provided with the distribution.
15 
16 3. Neither the name of the copyright holder nor the names of its
17  contributors may be used to endorse or promote products derived from
18  this software without specific prior written permission.
19 
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31 #include <crypto/der.h>
32 #include <gtest/gtest.h>
33 #include <string>
34 #include <chrono>
35 #include <ctime>
36 #include <system_error>
37 #include <encode/hex.h>
38 #include <util/fs.h>
39 
52 using std::cout;
53 using std::endl;
54 using std::string;
55 using std::runtime_error;
56 using scc::encode::Hex;
72 using scc::crypto::BasePtr; // a shared pointer
73 
74 using CharVec = std::vector<char>;
75 
76 TEST(DerTest, sanity)
77 {
78  DerBase b;
79  cout << "** base dump ***" << endl;
80  cout << b << endl;
81 
82  DerInteger i;
83  cout << "** integer dump ***" << endl;
84  cout << i << endl;
85 
86  DerSequence seq;
87  cout << "** sequence dump ***" << endl;
88  cout << seq << endl;
89 
90  DerSet set;
91  cout << "** set dump ***" << endl;
92  cout << set << endl;
93 }
94 
95 TEST(DerTest, low_tag_len_3)
96 {
97  // class-context, id is 10, length 3
98  CharVec inv = {'\x8a','\x03'};
99  for (int i = 0; i < 3; i++) inv.push_back((char)i);
100 
101  DerDocument d;
102  d.parse(inv);
103 
104  cout << "** class, id 10, length 3 dump:" << endl;
105  cout << d << endl;
106 
107  auto r = d.root();
108 
109  ASSERT_TRUE(r.context_class());
110  ASSERT_EQ(r.id(), 10);
111  ASSERT_EQ(r.pre_len(), 2);
112  ASSERT_EQ(r.len(), 3);
113  for (int i = 0; i < 3; i++)
114  {
115  ASSERT_EQ((int)(r.data()[i]), i%256);
116  }
117 
118  CharVec prev(r.pre_len());
119  r.dump_pre(prev);
120 
121  for (size_t i = 0; i < prev.size(); i++)
122  {
123  ASSERT_EQ(inv[i], prev[i]);
124  }
125 
126  CharVec alld;
127  d.dump(alld);
128 
129  cout << "doc before: " << Hex::bin_to_hex(inv) << endl;
130  cout << "doc after: " << Hex::bin_to_hex(alld) << endl;
131 
132  ASSERT_EQ(inv, alld);
133 }
134 
135 TEST(DerTest, high_tag_length_257)
136 {
137  // class-context, 2 byte id (128 + 1 = 129), length 257 (two bytes 128 + 1)
138  CharVec inv = {'\x9f','\x81','\x01','\x82','\x01','\x01'};
139  for (int i = 0; i < 257; i++) inv.push_back((char)(i%256));
140 
141  DerDocument d;
142  d.parse(inv);
143 
144  cout << "** class, id 129, length 3 dump:" << endl;
145  cout << d << endl;
146 
147  auto r = d.root();
148 
149  ASSERT_TRUE(r.context_class());
150  ASSERT_EQ(r.id(), 129);
151  ASSERT_EQ(r.len(), 257);
152  ASSERT_EQ(r.pre_len(), 6);
153  for (int i = 0; i < 257; i++)
154  {
155  ASSERT_EQ((int)(r.data()[i]), i%256);
156  }
157 
158  CharVec prev(r.pre_len());
159  r.dump_pre(prev);
160 
161  for (size_t i = 0; i < prev.size(); i++)
162  {
163  ASSERT_EQ(inv[i], prev[i]);
164  }
165 
166  CharVec alld;
167  d.dump(alld);
168 
169  cout << "doc before: " << Hex::bin_to_hex(inv) << endl;
170  cout << "doc after: " << Hex::bin_to_hex(alld) << endl;
171 
172  ASSERT_EQ(inv, alld);
173 }
174 
175 TEST(DerTest, failure)
176 {
177  DerDocument d;
178 
179  CharVec inv = CharVec({'\x8a'}); // no length byte
180  ASSERT_THROW(d.parse(inv), runtime_error);
181 
182  inv = CharVec({'\x8a','\x03','\xa1','\xa2'}); // len 3, short data
183  ASSERT_THROW(d.parse(inv), runtime_error);
184 
185  inv = CharVec({'\x8a','\x82','\x01','\x01','\xab'}); // multbyte length 257, short data
186  ASSERT_THROW(d.parse(inv), runtime_error);
187 
188  inv = CharVec({'\x8a','\x80'}); // multbyte length malformed
189  ASSERT_THROW(d.parse(inv), runtime_error);
190 
191  inv = CharVec({'\x8a','\x82','\x01'}); // multibyte insufficient length bytes
192  ASSERT_THROW(d.parse(inv), runtime_error);
193 }
194 
195 TEST(DerTest, container_and_integers)
196 {
197  CharVec inv;
198 
199  inv = CharVec({
200  '\x30', '\x1d', // container
201  '\x8a','\x03','X','Y','Z', // context id 10
202  '\x02','\x01','\x00', // 0
203  '\x02','\x01','\x7f', // 127
204  '\x02','\x02','\x00','\x80', // 128
205  '\x02','\x02','\x01','\x00', // 256
206  '\x02','\x01','\x80', // -128
207  '\x02','\x02','\xff','\x7f', // -129
208  '\x02','\x01','\xff' // -1
209  });
210 
211  DerDocument d;
212  d.parse(inv);
213 
214  cout << "** container dump:" << endl;
215  cout << d << endl;
216 
217  ASSERT_TRUE(d.root().is_seq());
218  ASSERT_TRUE(d.root().is_contain());
219  ASSERT_FALSE(d.root().is_set());
220  auto& c = d.root().contain();
221  ASSERT_EQ(c.size(), 8);
222  ASSERT_FALSE(c[0]->is_integer());
223  ASSERT_FALSE(c[0]->is_contain());
224  ASSERT_TRUE(c[1]->is_integer());
225  ASSERT_TRUE(c[2]->is_integer());
226  ASSERT_TRUE(c[3]->is_integer());
227  ASSERT_TRUE(c[4]->is_integer());
228  ASSERT_TRUE(c[5]->is_integer());
229  ASSERT_TRUE(c[6]->is_integer());
230  ASSERT_TRUE(c[7]->is_integer());
231 
233  ASSERT_EQ(c[1]->integer(), bn);
234  bn = 127;
235  ASSERT_EQ(c[2]->integer(), bn);
236  bn = 128;
237  ASSERT_EQ(c[3]->integer(), bn);
238  bn = 256;
239  ASSERT_EQ(c[4]->integer(), bn);
240  bn = 0;
241  bn -= 128;
242  ASSERT_EQ(c[5]->integer(), bn);
243  bn = 0;
244  bn -= 129;
245  ASSERT_EQ(c[6]->integer(), bn);
246  bn = 0;
247  bn -= 1;
248  ASSERT_EQ(c[7]->integer(), bn);
249 
250  CharVec alld;
251  d.dump(alld);
252 
253  cout << "doc before: " << Hex::bin_to_hex(inv) << endl;
254  cout << "doc after: " << Hex::bin_to_hex(alld) << endl;
255 
256  ASSERT_EQ(inv, alld);
257 
258  // construct test
259 
260  DerSequence* x = new DerSequence;
261  BasePtr valptr(x);
262 
263  DerBase* b = new DerBase(DerBase::class_context|0x0a);
264  b->data() = std::vector<uint8_t>({'X','Y','Z'});
265  x->push_back(BasePtr(b));
266 
267  DerInteger* i = new DerInteger;
268  x->push_back(BasePtr(i));
269 
270  i = new DerInteger;
271  i->data() = 127;
272  x->push_back(BasePtr(i));
273 
274  i = new DerInteger;
275  i->data() = 128;
276  x->push_back(BasePtr(i));
277 
278  i = new DerInteger;
279  i->data() = 256;
280  x->push_back(BasePtr(i));
281 
282  i = new DerInteger;
283  i->data() -= 128;
284  x->push_back(BasePtr(i));
285 
286  i = new DerInteger;
287  i->data() -= 129;
288  x->push_back(BasePtr(i));
289 
290  i = new DerInteger;
291  i->data() -= 1;
292  x->push_back(BasePtr(i));
293 
294  cout << endl << "contructed doc:\n" << DerDocument::print_element(valptr) << endl;
295 
296  CharVec valv;
297  DerDocument::dump_element(valptr, valv);
298 
299  ASSERT_EQ(alld, valv);
300 
301  // bad data test
302  inv = CharVec({'\x03','\x04','\x08','\x6e','\x5d','\xc0'}); // pad 8, must be < 8
303  ASSERT_THROW(d.parse(inv), runtime_error);
304 }
305 
306 TEST(DerTest, bit_string)
307 {
308  // tag 03 len 4 pad 6 bytes 01101110 (6e) 01011101 (5d) 11 (c0) (bits 18, padding 6)
309  auto inv = CharVec({'\x03','\x04','\x06','\x6e','\x5d','\xc0'});
310 
311  auto outv = CharVec({'\x6e','\x5d','\xc0'});
312 
313  DerDocument d;
314  d.parse(inv);
315 
316  cout << "** bitstring dump:" << endl;
317  cout << d << endl;
318 
319  auto& r = d.root();
320  ASSERT_TRUE(r.is_bit_string());
321  auto& bs = r.bit_string();
322 
323  ASSERT_EQ(bs.width(), 18);
324  ASSERT_EQ(bs.pad_bits(), 6);
325 
326  ASSERT_FALSE(bs.is_bit_set(0));
327  ASSERT_TRUE(bs.is_bit_set(1));
328  ASSERT_TRUE(bs.is_bit_set(2));
329  ASSERT_FALSE(bs.is_bit_set(3));
330  ASSERT_TRUE(bs.is_bit_set(4));
331  ASSERT_TRUE(bs.is_bit_set(5));
332  ASSERT_TRUE(bs.is_bit_set(6));
333  ASSERT_FALSE(bs.is_bit_set(7));
334  ASSERT_FALSE(bs.is_bit_set(8));
335  ASSERT_TRUE(bs.is_bit_set(9));
336  ASSERT_FALSE(bs.is_bit_set(10));
337  ASSERT_TRUE(bs.is_bit_set(11));
338  ASSERT_TRUE(bs.is_bit_set(12));
339  ASSERT_TRUE(bs.is_bit_set(13));
340  ASSERT_FALSE(bs.is_bit_set(14));
341  ASSERT_TRUE(bs.is_bit_set(15));
342  ASSERT_TRUE(bs.is_bit_set(16));
343  ASSERT_TRUE(bs.is_bit_set(17));
344  ASSERT_FALSE(bs.is_bit_set(18));
345  ASSERT_FALSE(bs.is_bit_set(19));
346  ASSERT_FALSE(bs.is_bit_set(20));
347  ASSERT_FALSE(bs.is_bit_set(21));
348  ASSERT_FALSE(bs.is_bit_set(22));
349  ASSERT_FALSE(bs.is_bit_set(23));
350  ASSERT_FALSE(bs.is_bit_set(24));
351 
352  CharVec dumpvec;
353  bs.get(dumpvec);
354 
355  cout << " dump: " << Hex::bin_to_hexstr(dumpvec.data(), dumpvec.size(), ":", 12) << endl;
356  cout << " outv: " << Hex::bin_to_hexstr(outv.data(), outv.size(), ":", 12) << endl;
357 
358  ASSERT_EQ(dumpvec, outv);
359 
360  // ensure that bitstream set/get works
361  auto newv = CharVec({'\x6e','\x5d','\xff'}); // all 1s
362 
364  b.set(newv, 18); // last 6 bits should be set to 0
365 
366  CharVec t;
367  b.get(t);
368 
369  ASSERT_EQ(outv, t);
370 
371  // bad data test
372  inv = CharVec({'\x03','\x04','\x08','\x6e','\x5d','\xc0'}); // pad 8, must be < 8
373  ASSERT_THROW(d.parse(inv), runtime_error);
374 }
375 
376 TEST(DerTest, strings)
377 {
378  CharVec inv;
379 
380  inv = CharVec({
381  '\x31', '\x2c', // set length 34 + 10 = 44
382  '\x04', '\x08', 'o','c','t','e','t','[','\x00',']', // len 8
383  '\x0c', '\x04', 'u','t','f','8', // len 4
384  '\x13', '\x10', 'p','r','i','n','t','a','b','l','e',' ','s','t','r','i','n','g', // len 16
385  '\x16', '\x03', 'i','a','5', // len 3
386  '\x1e', '\x03', 'b','m','p' // len 3
387  });
388 
389  DerDocument d;
390  d.parse(inv);
391 
392  cout << "** strings dump:" << endl;
393  cout << d << endl;
394 
395  ASSERT_TRUE(d.root().is_set());
396  ASSERT_TRUE(d.root().is_contain());
397  ASSERT_FALSE(d.root().is_seq());
398  auto& c = d.root().contain();
399  ASSERT_EQ(c.size(), 5);
400 
401  for (int i = 0; i < 5; i++)
402  {
403  ASSERT_TRUE(c[i]->is_string());
404  }
405  ASSERT_TRUE(c[0]->is_octet_string());
406  ASSERT_TRUE(c[1]->is_utf8_string());
407  ASSERT_TRUE(c[2]->is_printable_string());
408  ASSERT_TRUE(c[3]->is_ia5_string());
409  ASSERT_TRUE(c[4]->is_bmp_string());
410 
411  ASSERT_EQ(c[2]->string(), string("printable string"));
412 
413  CharVec alld;
414  d.dump(alld);
415 
416  cout << "doc before: " << Hex::bin_to_hex(inv) << endl;
417  cout << "doc after: " << Hex::bin_to_hex(alld) << endl;
418 
419  ASSERT_EQ(inv, alld);
420 
421  // construct test
422 
423  DerSet* x = new DerSet;
424  BasePtr valptr(x);
425 
426  auto s1 = new DerOctetString;
427  s1->set(CharVec({'o','c','t','e','t','[','\x00',']'}));
428  x->push_back(BasePtr(s1));
429  auto s2 = new DerUtf8String;
430  s2->set("utf8");
431  x->push_back(BasePtr(s2));
432  auto s3 = new DerPrintableString;
433  s3->set("printable string");
434  x->push_back(BasePtr(s3));
435  auto s4 = new DerIa5String;
436  s4->set("ia5");
437  x->push_back(BasePtr(s4));
438  auto s5 = new DerBmpString;
439  s5->set("bmp");
440  x->push_back(BasePtr(s5));
441 
442  cout << endl << "contructed doc:\n" << DerDocument::print_element(valptr) << endl;
443 
444  CharVec valv;
445  DerDocument::dump_element(valptr, valv);
446 
447  cout << "val after: ";
448  for (auto c : valv)
449  {
450  if (isprint(c)) cout << c;
451  else cout << "<" << std::hex << (int)c << std::dec << ">";
452  }
453  cout << endl;
454 
455  ASSERT_EQ(alld, valv);
456 }
457 
458 TEST(DerTest, null_and_bool)
459 {
460  CharVec inv;
461 
462  inv = CharVec({
463  '\x30', '\x08', // sequence
464  '\x05', '\x00', // null
465  '\x01', '\x01', '\x00', // false
466  '\x01', '\x01', '\x01' // true
467  });
468 
469  DerDocument d;
470  d.parse(inv);
471 
472  cout << "** null and bool dump:" << endl;
473  cout << d << endl;
474 
475  ASSERT_TRUE(d.root().is_seq());
476  ASSERT_TRUE(d.root().is_contain());
477  ASSERT_FALSE(d.root().is_set());
478  auto& c = d.root().contain();
479  ASSERT_EQ(c.size(), 3);
480 
481  ASSERT_TRUE(c[0]->is_null());
482  ASSERT_TRUE(c[1]->is_boolean());
483  ASSERT_TRUE(c[2]->is_boolean());
484  ASSERT_FALSE(c[1]->boolean());
485  ASSERT_TRUE(c[2]->boolean());
486 
487  CharVec alld;
488  d.dump(alld);
489 
490  cout << "doc before: " << Hex::bin_to_hex(inv) << endl;
491  cout << "doc after: " << Hex::bin_to_hex(alld) << endl;
492 
493  ASSERT_EQ(inv, alld);
494 
495  // construct test
496 
497  DerSequence* x = new DerSequence;
498  BasePtr valptr(x);
499 
500  x->push_back(BasePtr(new DerNull));
501 
502  DerBoolean* b = new DerBoolean;
503  b->set(false);
504  x->push_back(BasePtr(b));
505 
506  b = new DerBoolean;
507  b->set(true);
508  x->push_back(BasePtr(b));
509 
510  cout << endl << "contructed doc:\n" << DerDocument::print_element(valptr) << endl;
511 
512  CharVec valv;
513  DerDocument::dump_element(valptr, valv);
514 
515  cout << "val after: ";
516  for (auto c : valv)
517  {
518  if (isprint(c)) cout << c;
519  else cout << "<" << std::hex << (int)c << std::dec << ">";
520  }
521  cout << endl;
522 
523  ASSERT_EQ(alld, valv);
524 }
525 
526 struct Timetest : public testing::Test
527 {
528  Timetest() {}
529  virtual ~Timetest() {}
530 
531  DerDocument doc;
532  void verify(int id, const string& v, const string& verify="")
533  {
534  CharVec inv;
535  inv.push_back(id);
536  inv.push_back(v.size());
537  inv.insert(inv.end(), v.begin(), v.end());
538  doc.parse(inv);
539 
540  cout << "*** value raw: " << v << endl;
541  cout << doc << endl;
542 
543  DerBase& r = doc.root();
544 
545  ASSERT_TRUE(r.is_time());
546  ASSERT_EQ(r.id(), id);
547  ASSERT_TRUE(r.uni_class());
548  ASSERT_FALSE(r.constructed());
549 
550  CharVec outv;
551  doc.dump(outv);
552  ASSERT_GT(outv.size(), 2);
553  ASSERT_EQ(outv[0], (char)id);
554  int sz = (int)outv[1];
555  ASSERT_EQ(outv.size(), sz+2);
556  string ts;
557  auto i = outv.begin();
558  ++i;
559  ++i;
560  ts.insert(ts.begin(), i, outv.end());
561  cout << "output ts: " << ts << endl << endl;
562 
563  if (verify.size())
564  {
565  ASSERT_EQ(ts, verify);
566  }
567  else
568  {
569  ASSERT_EQ(ts, v);
570  }
571  }
572  time_t make_time(int year, int month, int day, int hour, int minute, int second)
573  {
574  std::tm tm;
575  memset(&tm, 0, sizeof(tm));
576 
577  tm.tm_year = year - 1900;
578  tm.tm_mon = month - 1;
579  tm.tm_mday = day;
580  tm.tm_hour = hour;
581  tm.tm_min = minute;
582  tm.tm_sec = second;
583  tm.tm_isdst = -1;
584 
585  return mktime(&tm);
586  }
587 };
588 
589 // NOTE: using a parsed value such as yymmddhhmmss+0000 will not dump to same value
590 TEST_F(Timetest, time)
591 {
592  ASSERT_THROW(verify(DerBase::type_utc_time, "030201120102"), runtime_error);
593  ASSERT_THROW(verify(DerBase::type_utc_time, "030201120102+04"), runtime_error);
594  ASSERT_THROW(verify(DerBase::type_utc_time, "03020112+04"), runtime_error);
595 
596  verify(DerBase::type_utc_time, "030201120102Z");
597  verify(DerBase::type_utc_time, "0302011201Z");
598 
599  verify(DerBase::type_utc_time, "030201120102+0000", "030201120102Z");
600  verify(DerBase::type_utc_time, "0302011201+0000", "0302011201Z");
601 
602  verify(DerBase::type_utc_time, "030201120102-0430", "030201163102Z");
603  verify(DerBase::type_utc_time, "0302011201-0430", "0302011631Z");
604 
605  verify(DerBase::type_utc_time, "030201120102+0430", "030201073102Z");
606  verify(DerBase::type_utc_time, "0302011201+0430", "0302010731Z");
607 
608  ASSERT_THROW(verify(DerBase::type_generalized_time, "20030201Z"), runtime_error);
609 
610  verify(DerBase::type_generalized_time, "20030201120102Z");
611  verify(DerBase::type_generalized_time, "200302011201Z");
612  verify(DerBase::type_generalized_time, "2003020112Z");
613 
614  verify(DerBase::type_generalized_time, "20030201120102-0430", "20030201163102Z");
615  verify(DerBase::type_generalized_time, "200302011201-0430", "200302011631Z");
616  verify(DerBase::type_generalized_time, "2003020112-0430", "200302011630Z");
617 
618  verify(DerBase::type_generalized_time, "20030201120102+0430", "20030201073102Z");
619  verify(DerBase::type_generalized_time, "200302011201+0430", "200302010731Z");
620  verify(DerBase::type_generalized_time, "2003020112+0430", "200302010730Z");
621 
622  verify(DerBase::type_generalized_time, "20030201120102-04", "20030201160102Z");
623  verify(DerBase::type_generalized_time, "200302011201-04", "200302011601Z");
624  verify(DerBase::type_generalized_time, "2003020112-04", "2003020116Z");
625 
626  verify(DerBase::type_generalized_time, "20030201120102+04", "20030201080102Z");
627  verify(DerBase::type_generalized_time, "200302011201+04", "200302010801Z");
628  verify(DerBase::type_generalized_time, "2003020112+04", "2003020108Z");
629 
630  verify(DerBase::type_generalized_time, "20030201120102.5Z", "20030201120102Z"); // no fractional seconds
631  verify(DerBase::type_generalized_time, "200302011201.5Z", "20030201120130Z");
632  verify(DerBase::type_generalized_time, "2003020112.5Z", "200302011230Z");
633 
634  // set the current timezone to pacific time, so we can test local time
635  setenv("TZ", "/usr/share/zoneinfo/America/Los_Angeles", 1);
636  auto t = make_time(2020, 3, 8, 1, 59, 59); // standard time UTC-8
637  verify(DerBase::type_generalized_time, "20200308015959", "20200308095959Z");
638  ASSERT_EQ(t, doc.root().time_epoch());
639 
640  ASSERT_NE(getenv("TZ"), nullptr);
641  ASSERT_EQ(string(getenv("TZ")), "/usr/share/zoneinfo/America/Los_Angeles"); // the APIs should not have modified the time zone
642 
643  unsetenv("TZ");
644  tzset();
645 }
646 
647 struct Oidtest : public testing::Test
648 {
649  Oidtest() {}
650  virtual ~Oidtest() {}
651 
652  CharVec inv;
653  DerDocument doc;
654 
655  void parse(CharVec v)
656  {
657  inv.clear();
658  inv.push_back(DerBase::type_object_identifier);
659  inv.push_back(v.size());
660  inv.insert(inv.end(), v.begin(), v.end());
661  doc.parse(inv);
662 
663  cout << endl << "***\n" << doc << endl;
664 
665  DerBase& r = doc.root();
666 
667  ASSERT_TRUE(r.is_object_id());
668  ASSERT_TRUE(r.uni_class());
669  ASSERT_FALSE(r.constructed());
670 
671  CharVec outv;
672  doc.dump(outv);
673  ASSERT_EQ(inv, outv);
674  }
675  void validate(std::vector<uint32_t> v)
676  {
677  ASSERT_EQ(v, doc.root().object_id());
678 
680  x->set(v);
681 
682  // construct test
683 
684  BasePtr valptr(x);
685 
686  cout << endl << "contructed doc:\n" << DerDocument::print_element(valptr) << endl;
687 
688  CharVec valv;
689  DerDocument::dump_element(valptr, valv);
690  ASSERT_EQ(inv, valv);
691  }
692 };
693 
694 TEST_F(Oidtest, oid)
695 {
696  parse({'\x2a','\x00','\x01','\x02'}); // 1.2.0.1.2 RSA Data Security, Inc. PKCS
697  validate({1,2,0,1,2});
698 
699  parse({'\x2a','\x86','\x48','\x86','\xf7','\x0d','\x01'}); // 1.2.840.113549.1 RSA Data Security, Inc. PKCS
700  validate({1,2,840,113549,1});
701 
702  // failure test
703 
704  using OidVec = std::vector<uint32_t>;
705 
707  ASSERT_THROW(x.set(OidVec({})), runtime_error);
708  ASSERT_THROW(x.set(OidVec({1})), runtime_error);
709  ASSERT_THROW(x.set(OidVec({0,50})), runtime_error);
710  ASSERT_THROW(x.set(OidVec({3,1})), runtime_error);
711 }
Big number.
Definition: bignum.h:59
Bit string.
Definition: der.h:82
ASN.1 base.
Definition: der.h:175
time_t time_epoch()
Epoch time.
Definition: der.cc:367
oid_value object_id()
Return the object identifier value.
Definition: der.cc:379
bool is_time() const
Is this a time type?
Definition: der.h:445
bool uni_class() const
Universal class.
Definition: der.h:352
std::vector< uint8_t > & data()
Underlying data.
Definition: der.h:304
bool constructed() const
Constructed flag (bit 6).
Definition: der.h:364
bool is_object_id() const
Is this an object identifier?
Definition: der.cc:374
uint32_t id() const
Tag id of the type.
Definition: der.h:325
DER document.
Definition: der.h:824
void clear()
Clear the document.
Definition: der.h:940
virtual void dump(std::vector< char > &)
Dump and append to a buffer.
Definition: der.cc:1276
virtual void parse(const std::vector< char > &)
Parse a buffer from a binary DER-formatted vector.
Definition: der.cc:1217
DerBase & root()
Root DerBase.
Definition: der.cc:1297
scc::crypto::Bignum & data()
Return the integer (an scc::crypto::Bignum)
Definition: der.h:798
Object identifier class.
Definition: der.h:555
void set(const oid_value &v)
Set oid values.
Definition: der.cc:649
An ASN.1 SEQUENCE or SEQUENCE OF type.
Definition: der.h:487
An ASN.1 SET or SET OF type.
Definition: der.h:502
PEM formatted DER document.
Definition: der.h:951
Distinguished encoding rules (DER).
Common file system utilities.
Binary to hex string converter.
TEST(inet_example, client_server_stream_test)
[Inet client server]
Definition: inet.cc:521