scclib
Stable Cloud Computing C++ Library
der.cc
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 <stdexcept>
33 #include <ostream>
34 #include <sstream>
35 #include <iomanip>
36 #include <vector>
37 #include <functional>
38 #include <stack>
39 #include <ctime>
40 #include <cstring>
41 #include <fstream>
42 #include <encode/base64.h>
43 #include <encode/hex.h>
44 
45 static void throw_err(const std::string& msg)
46 {
47  throw std::runtime_error(msg);
48 }
49 
50 using namespace scc::crypto;
51 using scc::encode::Hex;
53 
54 std::ostream& operator<<(std::ostream& os, const DerBase& b)
55 {
56  return os.write(b.str().c_str(), b.str().size());
57 }
58 
59 BasePtr DerBase::create(int tag)
60 {
61  auto id = tag & DerBase::id_mask;
62  auto cls = tag & DerBase::class_mask;
63 
64  if (cls != 0) // application, context or private
65  {
66  return BasePtr(new DerBase(tag));
67  }
68 
69  // universal object
70  switch (id)
71  {
72  case DerBase::type_sequence:
73  return BasePtr(new DerSequence(tag));
74  case DerBase::type_set:
75  return BasePtr(new DerSet(tag));
76  case DerBase::type_integer:
77  return BasePtr(new DerInteger(tag));
78  case DerBase::type_bit_string:
79  return BasePtr(new DerBitString(tag));
80  case DerBase::type_octet_string:
81  return BasePtr(new DerOctetString(tag));
82  case DerBase::type_utf8_string:
83  return BasePtr(new DerUtf8String(tag));
84  case DerBase::type_printable_string:
85  return BasePtr(new DerPrintableString(tag));
86  case DerBase::type_ia5_string:
87  return BasePtr(new DerIa5String(tag));
88  case DerBase::type_bmp_string:
89  return BasePtr(new DerBmpString(tag));
90  case DerBase::type_universal_string:
91  return BasePtr(new DerUniversalString(tag));
92  case DerBase::type_teletex_string:
93  return BasePtr(new DerTeletexString(tag));
94  case DerBase::type_null:
95  return BasePtr(new DerNull(tag));
96  case DerBase::type_boolean:
97  return BasePtr(new DerBoolean(tag));
98  case DerBase::type_utc_time:
99  return BasePtr(new DerUtcTime(tag));
100  case DerBase::type_generalized_time:
101  return BasePtr(new DerGeneralizedTime(tag));
102  case DerBase::type_object_identifier:
103  return BasePtr(new DerObjectIdentifier(tag));
104  }
105 
106  return BasePtr(new DerBase(tag));
107 }
108 
109 size_t DerBase::pre_len() const
110 {
111  size_t ret = 1;// tag
112  if ((m_tag & DerBase::id_mask) == DerBase::id_mask)
113  {
114  uint32_t id = m_id;
115  do
116  {
117  ret++;
118  id >>= 7; // base 128 per byte
119  }
120  while (id);
121  }
122 
123  size_t l= len();
124  if (l < 128)
125  {
126  ret++;
127  }
128  else
129  {
130  ret++; // the length byte
131 
132  do
133  {
134  ret++;
135  l >>= 8; // base 256 per byte
136  }
137  while (l);
138  }
139 
140  return ret;
141 }
142 
143 void DerBase::dump_pre(std::vector<char>& v) const
144 {
145  if (v.size() < pre_len()) throw_err("dump_pre vector too small");
146 
147  int idx=0;
148  v[idx] = m_tag;
149 
150  if ((m_tag & DerBase::id_mask) == DerBase::id_mask)
151  {
152  uint32_t i = m_id;
153  std::stack<uint8_t> bs;
154  do
155  {
156  bs.push(i & ~0x80); // put the bottom 7 bits on the stack
157  i >>= 7; // base 128 per byte
158  }
159  while (i);
160 
161  while (!bs.empty())
162  {
163  auto b = bs.top();
164  bs.pop();
165 
166  if (!bs.empty()) b |= 0x80; // set the 8th bit on (meaning there is more to come)
167 
168  v[++idx] = b;
169  }
170  }
171 
172  size_t l = len();
173 
174  if (l < 128)
175  {
176  v[++idx] = l;
177  }
178  else
179  {
180  std::stack<uint8_t> bs;
181  do
182  {
183  bs.push(l & 0xff);
184  l >>= 8; // base 256 per byte
185  }
186  while (l);
187 
188  v[++idx] = 0x80 | bs.size(); // number of bytes
189 
190  while (!bs.empty())
191  {
192  auto b = bs.top();
193  bs.pop();
194 
195  v[++idx] = b;
196  }
197  }
198 }
199 
200 void DerBase::dump_data(std::vector<char>& v) const
201 {
202  if (v.size() < m_dat.size()) throw_err("dump_data vector too small");
203 
204  for (size_t i = 0; i < m_dat.size(); i++)
205  {
206  v[i] = static_cast<char>(m_dat[i]);
207  }
208 }
209 
210 bool DerBase::is_seq() const
211 {
212  return typeid(*this) == typeid(DerSequence);
213 }
214 
215 bool DerBase::is_set() const
216 {
217  return typeid(*this) == typeid(DerSet);
218 }
219 
220 std::vector<BasePtr>& DerBase::contain()
221 {
222  if (!is_contain()) throw_err("invalid cast attempt to container");
223 
224  return *dynamic_cast<std::vector<BasePtr>*>(this);
225 }
226 
228 {
229  return typeid(*this) == typeid(DerInteger);
230 }
231 
233 {
234  if (!is_integer()) throw_err("invalid cast attempt to integer");
235 
236  return dynamic_cast<DerInteger*>(this)->data();
237 }
238 
240 {
241  return typeid(*this) == typeid(DerBitString);
242 }
243 
245 {
246  if (!is_bit_string()) throw_err("invalid cast attempt to bit string");
247 
248  return *dynamic_cast<BitString*>(this);
249 }
250 
252 {
253  return typeid(*this) == typeid(DerOctetString);
254 }
255 
257 {
258  return typeid(*this) == typeid(DerPrintableString);
259 }
260 
262 {
263  return typeid(*this) == typeid(DerUtf8String);
264 }
265 
267 {
268  return typeid(*this) == typeid(DerIa5String);
269 }
270 
272 {
273  return typeid(*this) == typeid(DerBmpString);
274 }
275 
277 {
278  return typeid(*this) == typeid(DerUniversalString);
279 }
280 
282 {
283  return typeid(*this) == typeid(DerTeletexString);
284 }
285 
287 {
288  return typeid(*this) == typeid(DerVisibleString);
289 }
290 
291 std::string DerBase::string()
292 {
293  if (!is_string()) throw_err("invalid cast attempt to string");
294 
295  return dynamic_cast<DerStringBase*>(this)->string();
296 }
297 
298 void DerBase::string(const std::string& s)
299 {
300  if (!is_string()) throw_err("invalid cast attempt to string");
301 
302  dynamic_cast<DerStringBase*>(this)->set(s);
303 }
304 
305 void DerBase::string_set(const std::vector<uint8_t>& s)
306 {
307  if (!is_string()) throw_err("invalid cast attempt to string");
308 
309  dynamic_cast<DerStringBase*>(this)->set(s);
310 }
311 
312 void DerBase::string_set(const std::vector<char>& s)
313 {
314  if (!is_string()) throw_err("invalid cast attempt to string");
315 
316  dynamic_cast<DerStringBase*>(this)->set(s);
317 }
318 
319 void DerBase::string_get(std::vector<uint8_t>& s)
320 {
321  if (!is_string()) throw_err("invalid cast attempt to string");
322 
323  dynamic_cast<DerStringBase*>(this)->get(s);
324 }
325 
326 void DerBase::string_get(std::vector<char>& s)
327 {
328  if (!is_string()) throw_err("invalid cast attempt to string");
329 
330  dynamic_cast<DerStringBase*>(this)->get(s);
331 }
332 
333 bool DerBase::is_null() const
334 {
335  return typeid(*this) == typeid(DerNull);
336 }
337 
339 {
340  return typeid(*this) == typeid(DerBoolean);
341 }
342 
344 {
345  if (!is_boolean()) throw_err("invalid cast attempt to boolean");
346 
347  return dynamic_cast<DerBoolean*>(this)->get();
348 }
349 
350 void DerBase::boolean(bool v)
351 {
352  if (!is_boolean()) throw_err("invalid cast attempt to boolean");
353 
354  return dynamic_cast<DerBoolean*>(this)->set(v);
355 }
356 
358 {
359  return typeid(*this) == typeid(DerUtcTime);
360 }
361 
363 {
364  return typeid(*this) == typeid(DerGeneralizedTime);
365 }
366 
368 {
369  if (!is_time()) throw_err("invalid cast attempt to time");
370 
371  return dynamic_cast<DerTimeBase*>(this)->epoch();
372 }
373 
375 {
376  return typeid(*this) == typeid(DerObjectIdentifier);
377 }
378 
380 {
381  if (!is_object_id()) throw_err("invalid cast attempt to object id");
382 
383  return dynamic_cast<DerObjectIdentifier*>(this)->data();
384 }
385 
386 void DerBase::object_id(const oid_value& v)
387 {
388  if (!is_object_id()) throw_err("invalid cast attempt to object id");
389 
390  return dynamic_cast<DerObjectIdentifier*>(this)->set(v);
391 }
392 
393 std::string DerBase::id_str() const
394 {
395  if (! uni_class())
396  {
397  return class_str() + "_id"; // id is used by application
398  }
399 
400  switch (id())
401  {
402  case type_boolean:
403  return "type_boolean";
404  case type_integer:
405  return "type_integer";
406  case type_bit_string:
407  return "type_bit_string";
408  case type_octet_string:
409  return "type_octet_string";
410  case type_null:
411  return "type_null";
412  case type_object_identifier:
413  return "type_object_identifier";
414  case type_utf8_string:
415  return "type_utf8_string";
416  case type_sequence:
417  return "type_sequence";
418  case type_set:
419  return "type_set";
420  case type_printable_string:
421  return "type_printable_string";
422  case type_ia5_string:
423  return "type_ia5_string";
424  case type_utc_time:
425  return "type_utc_time";
426  case type_generalized_time:
427  return "type_generalized_time";
428  case type_bmp_string:
429  return "type_bmp_string";
430  }
431  return "unknown";
432 }
433 
434 std::string DerBase::class_str() const
435 {
436  switch (type_class())
437  {
438  case 0:
439  return "class_universal";
440  case class_application:
441  return "class_application";
442  case class_context:
443  return "class_context";
444  case class_private:
445  return "class_private";
446  }
447  return "unknown";
448 }
449 
450 std::string DerBase::construct_str() const
451 {
452  if (constructed())
453  {
454  return "constructed";
455  }
456  return "primitive";
457 }
458 
459 std::string DerBase::str(uint32_t max_line) const
460 {
461  std::stringstream s;
462 
463  s << "id " << id_str() << "(" << id() << ") " << construct_str() << " len " << len() << data_str();
464 
465  return s.str();
466 }
467 
468 DerContainerBase::~DerContainerBase()
469 {
470 }
471 
472 size_t DerContainerBase::len() const
473 {
474  size_t r = 0;
475  for (auto& i : *this)
476  {
477  r += i->pre_len();
478  r += i->len();
479  }
480  return r;
481 }
482 
483 std::string DerContainerBase::data_str() const
484 {
485  std::stringstream s;
486 
487  s << " items " << size();
488 
489  return s.str();
490 }
491 
492 static std::string bin_print(const void* xloc, size_t len, size_t max=12)
493 {
494  char* loc = (char*)xloc;
495  std::stringstream s;
496 
497  while (len)
498  {
499  if (!max)
500  {
501  s << " +more";
502  break;
503  }
504  if (isprint(*loc))
505  {
506  s << *loc;
507  }
508  else
509  {
510  s << ".";
511  }
512  loc++;
513  len--;
514  max--;
515  }
516 
517  return s.str();
518 }
519 
520 static std::string bn_print(const Bignum& bn, unsigned max=8)
521 {
522  std::vector<char> v(bn.len_2sc(), '\0');
523 
524  bn.get_2sc((char*)v.data(), v.size());
525 
526  return Hex::bin_to_hexstr(v.data(), v.size(), ":", max);
527 }
528 
529 std::string DerBase::data_str() const
530 {
531  std::stringstream s;
532 
533  s << " str " << bin_print(m_dat.data(), m_dat.size());
534 
535  s << " hex " << Hex::bin_to_hexstr(m_dat.data(), m_dat.size(), ":", 8);
536 
537  return s.str();
538 }
539 
540 std::string DerObjectIdentifier::oid_str() const
541 {
542  std::stringstream s;
543 
544  if (!m_v.size()) return "(empty oid)";
545 
546  s << m_v;
547 
548  return s.str();
549 }
550 
551 std::ostream& operator<<(std::ostream& s, const std::vector<uint32_t>& oid)
552 {
553  std::stringstream outs;
554 
555  for (auto i = oid.begin(); i != oid.end(); ++i)
556  {
557  if (i != oid.begin()) s << ".";
558  s << *i;
559  }
560  return s;
561 }
562 
563 void DerObjectIdentifier::parse(const std::vector<uint8_t>& v)
564 {
565  if (v.size() == 0) throw_err("oid parse error no data");
566 
567  m_v.resize(2);
568  m_v[0] = v[0]/40;
569  m_v[1] = v[0]%40;
570 
571  size_t i = 1;
572  while (i < v.size())
573  {
574  std::stack<uint8_t> bs;
575  while (i < v.size()) // parse base 128 multilength byte
576  {
577  auto x = v[i++];
578  bs.push(x & ~0x80);
579  if ((x & 0x80) == 0) break; // finished when first bit is 0
580  }
581  uint32_t nxt = 0;
582  uint32_t mult = 1;
583  while (!bs.empty())
584  {
585  nxt += bs.top()*mult;
586  bs.pop();
587  mult <<= 7;
588  }
589  m_v.push_back(nxt);
590  }
591 }
592 
593 std::string DerObjectIdentifier::data_str() const
594 {
595  std::stringstream s;
596 
597  s << " oid ";
598  for (size_t i = 0; i < m_v.size(); i++)
599  {
600  s << m_v[i];
601  if (i != m_v.size()-1) s << ".";
602  }
603 
604  return s.str();
605 }
606 
608 {
609  int len = 1;
610  for (size_t i = 2; i < m_v.size(); i++)
611  {
612  auto nxt = m_v[i];
613  do
614  {
615  nxt >>= 7; // base 128
616  len++;
617  }
618  while (nxt);
619  }
620  return len;
621 }
622 
623 void DerObjectIdentifier::dump_data(std::vector<char>& v) const
624 {
625  v[0] = m_v[0]*40 + m_v[1];
626 
627  int idx = 1;
628  for (size_t i = 2; i < m_v.size(); i++)
629  {
630  auto nxt = m_v[i];
631  std::stack<uint8_t> bs;
632  do
633  {
634  bs.push(nxt & 0x7f); // 7 bits
635  nxt >>= 7; // base 128
636  }
637  while (nxt);
638 
639  while (!bs.empty())
640  {
641  auto x = bs.top() | 0x80; // set continuation bit
642  bs.pop();
643  if (bs.empty()) x &= ~0x80;
644  v[idx++] = x;
645  }
646  }
647 }
648 
649 void DerObjectIdentifier::set(const oid_value& v)
650 {
651  if (v.size() < 2) throw_err("oid missing v1 and v2 values");
652  if (v[0] > 2) throw_err("oid v1 out of range");
653  if (v[1] > 39) throw_err("oid v2 out of range");
654  m_v = v;
655 }
656 
657 #include <iostream>
658 
659 // set time in the utc timezone (with an offset from utc time)
660 void DerTimeBase::set_time(int year, int month, int day, int hour, int minute, int second, int tzmins)
661 {
662  std::tm tm;
663  memset(&tm, 0, sizeof(tm));
664 
665  tm.tm_year = year - 1900;
666  tm.tm_mon = month - 1;
667  tm.tm_mday = day;
668  tm.tm_hour = hour;
669  tm.tm_min = minute - tzmins;
670  tm.tm_sec = second;
671  tm.tm_isdst = -1;
672 
673  m_t = timegm(&tm);
674 }
675 
676 // set time in the local timezone
677 void DerTimeBase::set_time(int year, int month, int day, int hour, int minute, int second)
678 {
679  std::tm tm;
680  memset(&tm, 0, sizeof(tm));
681 
682  tm.tm_year = year - 1900;
683  tm.tm_mon = month - 1;
684  tm.tm_mday = day;
685  tm.tm_hour = hour;
686  tm.tm_min = minute;
687  tm.tm_sec = second;
688  tm.tm_isdst = -1;
689 
690  m_t = mktime(&tm);
691 }
692 
693 std::string DerTimeBase::data_str() const
694 {
695  std::stringstream s;
696 
697  std::tm tm;
698  auto t = m_t;
699  localtime_r(&t, &tm);
700  s << " local " << std::put_time(&tm, "%F %T %Z");
701  gmtime_r(&t, &tm);
702  s << " utc " << std::put_time(&tm, "%F %T UTC");
703  return s.str();
704 }
705 
706 // return true if tz postfix found
707 // set tzval with value and tzsize with the size of the postfix
708 static bool parse_tz(std::string& v, int& tzval, int& tzsize)
709 {
710  auto p = v.find_last_of("+-Z");
711 
712  if (p == std::string::npos) return false;
713 
714  tzsize = v.size()-p;
715 
716  if (v[p] == 'Z')
717  {
718  if (tzsize > 1) throw std::runtime_error(std::string("timezone parse error on ")+v);
719 
720  v.resize(p);
721  tzval = 0;
722  return true;
723  }
724 
725  if (v[p] != '+' && v[p] != '-') throw std::runtime_error(std::string("timezone parse error on ")+v);
726 
727  int sign = 1, hh, mm = 0;
728  if (v[p] == '-') sign = -1;
729 
730  int n = sscanf(&v[p+1], "%02d%02d", &hh, &mm);
731 
732  if (n < 1) throw std::runtime_error(std::string("timezone parse error on ")+v);
733 
734  v.resize(p);
735  tzval = sign*(hh*60+mm);
736  return true;
737 }
738 
739 void DerUtcTime::parse(const std::vector<uint8_t>& vin)
740 {
741  std::string v(&vin[0], &vin[0]+vin.size());
742 
743  int tzmins, tzsize;
744 
745  if (!parse_tz(v, tzmins, tzsize)) throw_err("utc time no timezone found");
746 
747  if (tzsize > 1 && tzsize < 5) throw_err("utc time requires Z or +/-HHMM format");
748 
749  unsigned yy, mm, dd, h, m, s = 0;
750 
751  if (v.size() != 10 && v.size() != 12) throw_err("utc time parse error YYMMDDhhmm[ss] wrong size");
752 
753  int n = sscanf(&v[0], "%02u%02u%02u%02u%02u%02u", &yy, &mm, &dd, &h, &m, &s);
754  if (n < 5) throw_err("utc time parse error YYMMDDhhmm[ss]");
755 
756  set_time(yy < 70 ? yy + 2000 : yy + 1900, mm, dd, h, m, s, tzmins);
757 }
758 
759 void DerUtcTime::dump_data(std::vector<char>& v) const
760 {
761  std::tm tm;
762  time_t t = m_t;
763  gmtime_r(&t, &tm);
764 
765  sprintf(&v[0], "%02d%02d%02d%02d%02d",
766  tm.tm_year < 70 ? tm.tm_year : tm.tm_year-100,
767  tm.tm_mon + 1,
768  tm.tm_mday,
769  tm.tm_hour,
770  tm.tm_min);
771 
772  int idx = 10;
773  if (tm.tm_sec)
774  {
775  sprintf(&v[idx], "%02d", tm.tm_sec);
776  idx += 2;
777  }
778  v[idx] = 'Z';
779 }
780 
781 size_t DerUtcTime::len() const
782 {
783  int ret = 11; // yymmddhhmmZ
784 
785  if (m_t%60)
786  {
787  ret += 2; // ss
788  }
789  return ret;
790 }
791 
792 // parse fracional part , or . as decimal followed by digits
793 // if found, trims string to remove
794 static double parse_frac(std::string& v)
795 {
796  auto p = v.find_last_of(",.");
797  if (p == std::string::npos) return 0.0;
798 
799  v[p] = '.'; // change comma to a "fullstop"
800 
801  double ret;
802  int n = sscanf(&v[p], "%lf", &ret);
803 
804  if (n < 1) return -1.0;
805 
806  v.resize(p);
807  return ret;
808 }
809 
810 void DerGeneralizedTime::parse(const std::vector<uint8_t>& vin)
811 {
812  std::string v(&vin[0], &vin[0]+vin.size());
813 
814  int tzmins, tzsize;
815 
816  bool tzpost = parse_tz(v, tzmins, tzsize); // parse tz, expecting nothing or Z|+-hh[mm]
817 
818  double frac = parse_frac(v);
819  if (frac < 0.0) throw_err("generalized time parse error fractional part");
820 
821  if (v.size() < 10) throw_err("generalized time parse error YYYYMMDDhh wrong size");
822 
823  unsigned yy, mm, dd, h, m=0, s=0;
824 
825  int n = sscanf(&v[0], "%4u%02u%02u%02u", &yy, &mm, &dd, &h);
826  if (n < 4) throw_err("generalized time parse error YYYYMMDDhh");
827 
828  if (v.size() == 10)
829  {
830  if (frac > 0.0) // fractional hours
831  {
832  m += frac*60.0;
833  }
834  }
835  else if (v.size() == 12)
836  {
837  n = sscanf(&v[10], "%02u", &m);
838  if (n < 1) throw_err("generalized time parse error mm");
839 
840  if (frac > 0.0) // fractional minutes
841  {
842  s += frac*60.0;
843  }
844  }
845  else if (v.size() == 14)
846  {
847  n = sscanf(&v[10], "%02u%02u", &m, &s);
848  if (n < 2) throw_err("generalized time parse error mmss");
849 
850  // ignore fractional seconds
851  }
852  else
853  {
854  throw_err("generalized time parse error YYYYMMDDhh wrong size");
855  }
856 
857  if (tzpost)
858  {
859  set_time(yy, mm, dd, h, m, s, tzmins);
860  }
861  else
862  {
863  set_time(yy, mm, dd, h, m, s);
864  }
865 }
866 
867 void DerGeneralizedTime::dump_data(std::vector<char>& v) const
868 {
869  std::tm tm;
870  time_t t = m_t;
871  gmtime_r(&t, &tm);
872 
873  sprintf(&v[0], "%4d%02d%02d%02d",
874  tm.tm_year + 1900,
875  tm.tm_mon + 1,
876  tm.tm_mday,
877  tm.tm_hour);
878 
879  int idx = 10;
880  if (tm.tm_min)
881  {
882  sprintf(&v[idx], "%02d", tm.tm_min);
883  idx += 2;
884  }
885  if (tm.tm_sec)
886  {
887  sprintf(&v[idx], "%02d", tm.tm_sec);
888  idx += 2;
889  }
890  v[idx] = 'Z';
891 }
892 
894 {
895  int ret = 11; //yyyymmddhhZ
896 
897  if (m_t%60)
898  {
899  ret += 4; // mmss
900  }
901  else if (m_t%3600)
902  {
903  ret += 2; // mm
904  }
905  return ret;
906 }
907 
908 void DerStringBase::parse(const std::vector<uint8_t>& v)
909 {
910  m_val.resize(v.size());
911 
912  for (size_t i = 0; i < v.size(); i++)
913  {
914  m_val[i] = v[i];
915  }
916 }
917 
918 std::string DerStringBase::data_str() const
919 {
920  std::stringstream s;
921 
922  s << " str " << bin_print(m_val.data(), m_val.size(), 80);
923 
924  return s.str();
925 }
926 
927 void DerStringBase::dump_data(std::vector<char>& v) const
928 {
929 
930  for (size_t i = 0; i < m_val.size(); i++)
931  {
932  v[i] = m_val[i];
933  }
934 }
935 
936 void DerBoolean::parse(const std::vector<uint8_t>& v)
937 {
938  m_bool = v[0] == 0 ? false : true;
939 }
940 
941 void DerBoolean::dump_data(std::vector<char>& v) const
942 {
943  v[0] = m_bool ? 1 : 0;
944 }
945 
946 void DerInteger::parse(const std::vector<uint8_t>& v)
947 {
948  m_bn.set_2sc(&v[0], v.size()); // twos complement input
949 }
950 
951 std::string DerInteger::data_str() const
952 {
953  std::stringstream s;
954 
955  s << " width " << m_bn.width();
956 
957  if (m_bn <= 0xffffffff)
958  {
959  s << " dec " << m_bn;
960  }
961 
962  s << " hex " << bn_print(m_bn);
963 
964  return s.str();
965 }
966 
967 size_t DerInteger::len() const
968 {
969  return m_bn.len_2sc();
970 }
971 
972 void DerInteger::dump_data(std::vector<char>& v) const
973 {
974  m_bn.get_2sc(&v[0], v.size());
975 }
976 
977 void DerBitString::parse(const std::vector<uint8_t>& v)
978 {
979  if (v.size() == 0)
980  {
981  width(0);
982  return;
983  }
984 
985  uint8_t pad = v[0]; // number of 0 bits added to the end (unused bits)
986 
987  if (pad > 7) throw_err("bit string parse error pad bits too high");
988 
989  m_data.clear();
990  width((v.size()-1)*8 - pad); // set the bit width (remaining array size - pad)
991 
992  // the BitString is now v.size()-1 in length
993 
994  for (size_t i = 1; i < v.size(); i++)
995  {
996  m_data.at(i-1)= v[i];
997  }
998 }
999 
1000 std::string DerBitString::data_str() const
1001 {
1002  if (m_data.size() < len()-1) throw_err("bitstring data_str invalid size");
1003 
1004  std::stringstream s;
1005 
1006  s << " width " << width() << " pad bits " << pad_bits();
1007 
1008  s << " hex " << Hex::bin_to_hexstr(m_data.data(), m_data.size(), ":", 12);
1009 
1010  s << " bits";
1011 
1012  int max = 3;
1013  uint32_t w = width();
1014  for (uint32_t i = 0; i < w; i++)
1015  {
1016  if (i%8 == 0)
1017  {
1018  if (max == 0)
1019  {
1020  s << " +more";
1021  break;
1022  }
1023  s << " ";
1024  max--;
1025  }
1026 
1027  s << (is_bit_set(w-1-i) ? "1" : "0"); // print out most significant first
1028  }
1029 
1030  return s.str();
1031 }
1032 
1033 size_t DerBitString::len() const
1034 {
1035  return m_data.size() + 1; // bit data + pad byte
1036 }
1037 
1038 void DerBitString::dump_data(std::vector<char>& v) const
1039 {
1040  v[0] = pad_bits();
1041 
1042  for (size_t i = 1; i < v.size(); i++)
1043  {
1044  v[i] = m_data.at(i-1);
1045  }
1046 }
1047 
1048 BasePtr DerBase::context_to_explicit(const BasePtr& ctx)
1049 {
1050  if (!ctx->context_class() || !ctx->constructed()) throw_err("context_to_explicit() element must be constructed and context-class");
1051 
1052  BasePtr base = DerDocument::parse_element(ctx->m_dat); // return a new element using the DER-encoded data
1053 
1054  return base;
1055 }
1056 
1057 BasePtr DerBase::explicit_to_context(const BasePtr& orig, uint32_t id)
1058 {
1059  // NOTE: dump rework is next
1060 
1061  std::vector<uint8_t> v;
1062  DerDocument::dump_element(orig, v);
1063 
1064  BasePtr base = DerBase::create(DerBase::construct_mask|DerBase::class_context);
1065  base->id(id);
1066  base->parse(v); // set the dumped data into the element
1067 
1068  return base;
1069 }
1070 
1071 
1072 BasePtr DerBase::context_to_implicit(const BasePtr& ctx, uint32_t id)
1073 {
1074  if (id >= DerBase::id_mask) throw_err("context_to_implicit() invalid id");
1075  if (ctx->id() >= DerBase::id_mask) throw_err("context_to_implicit() context multi-byte id not supported");
1076  if (!ctx->context_class()) throw_err("context_to_implicit() context element must be context-class");
1077 
1078  std::vector<uint8_t> v;
1079  DerDocument::dump_element(ctx, v);
1080 
1081  v[0] = (v[0] & ~DerBase::id_mask) | id; // set the id
1082  // constructed flag stays the same
1083  v[0] &= ~class_mask; // clear the class to set the universal class 0
1084 
1085  BasePtr base = DerDocument::parse_element(v); // return a new element from the modified element binary
1086 
1087  return base;
1088 }
1089 
1090 BasePtr DerBase::implicit_to_context(const BasePtr& orig, uint32_t id)
1091 {
1092  if (id >= DerBase::id_mask) throw_err("implicit_to_context() invalid id");
1093  if (orig->id() >= DerBase::id_mask) throw_err("implicit_to_context() original multi-byte id not supported");
1094  if (!orig->uni_class()) throw_err("implicit_to_context() original element must be universal class");
1095 
1096  std::vector<uint8_t> v;
1097  DerDocument::dump_element(orig, v);
1098 
1099  v[0] = (v[0] & ~DerBase::id_mask) | id; // set the id
1100  v[0] |= class_context; // set class context
1101 
1102  BasePtr base = DerDocument::parse_element(v); // return a new element from the modified element binary
1103 
1104  return base;
1105 }
1106 
1107 BasePtr DerBase::create(const std::vector<uint8_t>& v, size_t off)
1108 {
1109  if (off == v.size()) throw_err("create() no tag byte");
1110 
1111  BasePtr base = DerBase::create(v[off]);
1112 
1113  base->m_eloff = off;
1114  base->m_hdrsz = 1;
1115 
1116  if ((v[off] & DerBase::id_mask) == DerBase::id_mask) // this is a high-tag id
1117  {
1118  std::stack<uint8_t> idb;
1119  do
1120  {
1121  if (++off == v.size()) throw_err("create() no id byte");
1122  base->m_hdrsz++;
1123  idb.push(v[off] & 0x7f); // bits 1-7 are the id value (base 128, high byte first)
1124  }
1125  while ((v[off] & 0x80) == 0x80); // while 8th bit is 1, there is another id byte coming
1126 
1127  uint32_t id = 0;
1128  uint32_t mult = 1;
1129 
1130  while (!idb.empty()) // build up the base 128 id
1131  {
1132  auto b = idb.top();
1133  idb.pop();
1134  id += mult*b;
1135  mult *= 128;
1136  }
1137 
1138  base->id(id);
1139  }
1140 
1141  if (++off == v.size()) throw_err("create() no length byte");
1142  base->m_hdrsz++;
1143 
1144  if (v[off] & DerBase::length_multi_mask)
1145  {
1146  size_t lensz = v[off] & DerBase::length_bytes_mask;
1147 
1148  if (lensz == 0)
1149  {
1150  // len = 0x80 means indefinite-sized
1151  // i.e. ended with octets 00 00
1152  // DER requires that elements be definite-sized
1153  throw_err("create() indefinite-sized elements not supported by DER");
1154  }
1155 
1156  for (size_t i = 0; i < lensz; i++)
1157  {
1158  if (++off == v.size()) throw_err("create() insufficient extended length bytes");
1159  base->m_hdrsz++;
1160  base->m_elsz += ((size_t)v[off] << (lensz-i-1)*8); // base 256, high byte first
1161  }
1162  }
1163  else
1164  {
1165  base->m_elsz = v[off];
1166  }
1167 
1168  return base;
1169 }
1170 
1171 BasePtr DerDocument::parse_element(const std::vector<uint8_t>& binv, size_t off)
1172 {
1173  BasePtr base;
1174 
1175  base = DerBase::create(binv, off);
1176 
1177  if (!base->is_contain())
1178  {
1179  if (off+base->hdrsz()+base->elsz() > binv.size()) throw_err(base->name()+" parse_element binary size mismatch");
1180 
1181  // NOTE: at some point, should rework to avoid object creation
1182  base->parse(std::vector<uint8_t>(&binv[off+base->hdrsz()], &binv[off+base->hdrsz()+base->elsz()]));
1183 
1184  return base;
1185  }
1186 
1187  // if this is a container, parse and store the sub-elements as constructed data
1188 
1189  off += base->hdrsz(); // move offset to the beginning of data
1190  size_t elsz = off+base->elsz(); // keep track of the container size
1191 
1192  while (off < elsz)
1193  {
1194  BasePtr nxt = parse_element(binv, off);
1195  base->contain().emplace_back(nxt);
1196  off += nxt->hdrsz() + nxt->elsz();
1197  }
1198 
1199  // sanity check, size of container element must match sizes of contained elements
1200 
1201  size_t allsz = 0;
1202  for (auto& e : base->contain())
1203  {
1204  allsz += e->hdrsz()+e->elsz();
1205  }
1206  if (allsz != base->elsz()) throw_err("parse_element() container/element size mismatch");
1207 
1208  return base;
1209 }
1210 
1211 void DerDocument::parse_bin()
1212 {
1213  m_root.reset();
1214  if (!m_bin.empty()) m_root = parse_element(m_bin); // the offsets are now correct
1215 }
1216 
1217 void DerDocument::parse(const std::vector<char>& v)
1218 {
1219  m_bin.clear();
1220  m_bin.insert(m_bin.begin(), v.begin(), v.end());
1221  parse_bin();
1222 }
1223 
1224 void DerDocument::parse(std::istream& s)
1225 {
1226  m_bin.clear();
1227  s >> m_bin;
1228  parse_bin();
1229 }
1230 
1231 void DerDocument::dump_element(const BasePtr& base, std::vector<uint8_t>& vout)
1232 {
1233  if (base == nullptr) return;
1234 
1235  std::vector<char> v(base->pre_len());
1236  base->dump_pre(v);
1237  vout.insert(vout.end(), v.begin(), v.end()); // append prefix bytes
1238 
1239  if (base->is_contain())
1240  {
1241  for (auto& x : base->contain())
1242  {
1243  if (base == nullptr) throw_err("dump_element() container element with null object");
1244 
1245  dump_element(x, vout);
1246  }
1247  }
1248  else // dump data if this is not a container
1249  {
1250  v.resize(base->len());
1251  base->dump_data(v);
1252  vout.insert(vout.end(), v.begin(), v.end()); // append data bytes
1253  }
1254 }
1255 
1256 bool DerDocument::equal(const DerDocument& other) const
1257 {
1258  if (m_root == nullptr && other.m_root == nullptr)
1259  {
1260  return true;
1261  }
1262 
1263  std::vector<char> d1, d2;
1264 
1265  dump_element(m_root, d1);
1266  dump_element(other.m_root, d2);
1267 
1268  bool ret = (d1 == d2);
1269 
1270  explicit_bzero(d1.data(), d1.size());
1271  explicit_bzero(d2.data(), d2.size());
1272 
1273  return ret;
1274 }
1275 
1276 void DerDocument::dump(std::vector<char>& vout)
1277 {
1278  if (m_root == nullptr) throw_err("dump() called on empty document");
1279 
1280  dump_bin();
1281  vout.insert(vout.end(), m_bin.begin(), m_bin.end());
1282 }
1283 
1284 void DerDocument::dump_bin()
1285 {
1286  m_bin.clear();
1287  dump_element(m_root, m_bin);
1288  parse_bin(); // the offsets are now correct
1289 }
1290 
1291 void DerDocument::dump(std::ostream& s)
1292 {
1293  dump_bin();
1294  s << m_bin;
1295 }
1296 
1298 {
1299  if (m_root == nullptr) throw_err("root() called on empty document");
1300 
1301  return *m_root;
1302 }
1303 
1304 struct PHelp
1305 {
1306  bool debug;
1307  std::string indent;
1308  std::stringstream s;
1309 };
1310 
1311 static void print_helper(PHelp& ph, BasePtr base, int level)
1312 {
1313  if (base == nullptr)
1314  {
1315  ph.s << "<empty>";
1316  return;
1317  }
1318 
1319  for (int i = 0; i < level; i++) ph.s << ph.indent;
1320 
1321  if (ph.debug) ph.s << "(" << base->eloff() << "," << base->elsz() << "," << base->hdrsz() << ") ";
1322 
1323  ph.s << *base;
1324 
1325  if (base->is_contain())
1326  {
1327  level++;
1328  for (auto& x : base->contain())
1329  {
1330  ph.s << std::endl;
1331  print_helper(ph, x, level);
1332  }
1333  }
1334 }
1335 
1336 std::string DerDocument::print_element(const BasePtr& base, bool debug, const std::string& indent)
1337 {
1338  PHelp ph;
1339  ph.debug = debug;
1340  ph.indent = indent;
1341 
1342  print_helper(ph, base, 0);
1343 
1344  return ph.s.str();
1345 }
1346 
1347 std::string DerDocument::str(bool debug) const
1348 {
1349  std::stringstream s;
1350 
1351  if (debug) s << "bin_sz(" << m_bin.size() << ") " << std::endl;
1352 
1353  return s.str()+print_element(m_root, debug);
1354 }
1355 
1356 std::ostream& operator<<(std::ostream& os, const DerDocument& b)
1357 {
1358  return os.write(b.str().c_str(), b.str().size());
1359 }
1360 
1361 void PemDocument::parse(const std::vector<char>& v)
1362 {
1363  std::stringstream sst;
1364  sst.write(v.data(), v.size());
1365  parse(sst);
1366  explicit_bzero(sst.str().data(), sst.str().size());
1367 }
1368 
1369 void PemDocument::parse(std::istream& sst)
1370 {
1371  std::string l;
1372  const auto np = std::string::npos;
1373 
1374  // read forward until begin line is found
1375  while (1)
1376  {
1377  if (!std::getline(sst, l)) throw_err("PEM input end of stream before BEGIN");
1378  auto p = l.find("-----BEGIN ");
1379 
1380  if (p != np) break; // found begin line
1381  }
1382 
1383  auto ep = l.rfind("-----");
1384  if (ep == np) throw_err("PEM input BEGIN line does not end with -----");
1385 
1386  m_label = l.substr(11, l.size()-16);
1387 
1388  if (m_label.empty()) throw_err("PEM input zero length label");
1389 
1390  std::string b64;
1391  m_chars_per_line = 0;
1392  while (std::getline(sst, l))
1393  {
1394  auto p = l.find("-----END ");
1395  if (p != np)
1396  {
1397  ep = l.rfind("-----");
1398  if (ep == np) throw_err("PEM input END does not end with -----");
1399 
1400  auto elabel = l.substr(9, l.size()-14);
1401 
1402  if (m_label != elabel) throw_err("PEM input BEGIN and END labels do not match");
1403 
1404  if (!Base64::base64_decode(b64, m_bin)) throw_err("PEM input invalid base64 data");
1405 
1406  explicit_bzero(b64.data(), b64.size());
1407 
1408  parse_bin();
1409  return;
1410  }
1411  b64.insert(b64.end(), l.begin(), l.end());
1412  if (m_chars_per_line < l.size())
1413  {
1414  m_chars_per_line = l.size();
1415  }
1416  }
1417 
1418  // if we got here, there was no end found
1419  throw_err("PEM input no ----END found");
1420 }
1421 
1422 void PemDocument::dump(std::vector<char>& v)
1423 {
1424  if (m_chars_per_line == 0) throw_err("PEM output cannot have 0 chars per line");
1425  if (m_label.empty()) throw_err("PEM output zero length label");
1426 
1427  DerDocument::dump_bin(); // dump the binary document
1428 
1429  std::string b64;
1430  Base64::base64_encode(m_bin, b64);
1431 
1432  std::string l;
1433  l = "-----BEGIN "+m_label+"-----\n";
1434  v.insert(v.end(), l.begin(), l.end());
1435 
1436  size_t sz = b64.size(), towrite = sz;
1437  while (towrite)
1438  {
1439  size_t lw = towrite > m_chars_per_line ? m_chars_per_line : towrite;
1440  v.insert(v.end(), &b64[sz-towrite], &b64[sz-towrite]+lw);
1441  towrite -= lw;
1442  v.insert(v.end(), '\n');
1443  }
1444 
1445  l = "-----END "+m_label+"-----\n";
1446  v.insert(v.end(), l.begin(), l.end());
1447 
1448  explicit_bzero(b64.data(), b64.size());
1449 }
1450 
1451 void PemDocument::dump(std::ostream& s)
1452 {
1453  SecVecChar v;
1454  dump(v);
1455  s << v;
1456 }
Big number.
Definition: bignum.h:59
void set_2sc(const void *, int)
Set integer from twos complement input stream.
void get_2sc(void *, int) const
Octal (byte) output, in two's complement form.
int width() const
Number of significant bits.
int len_2sc() const
Get the length of octal output in twos complement form.
Bit string.
Definition: der.h:82
bool is_bit_set(uint32_t bit) const
Is the bit set? First bit is bit 0.
Definition: der.h:127
uint32_t pad_bits() const
Number of padding bits (0 bits at the end of the last byte).
Definition: der.h:94
uint32_t width() const
Bit width.
Definition: der.h:91
ASN.1 base.
Definition: der.h:175
scc::crypto::Bignum & integer()
Return reference to a scc::crypto::Bignum.
Definition: der.cc:232
bool is_utf8_string() const
Is this a utf8 (ascii) string?
Definition: der.cc:261
BitString & bit_string()
Return reference to bit string.
Definition: der.cc:244
bool is_teletex_string() const
Is this a teletex (ascii) string?
Definition: der.cc:281
virtual void dump_pre(std::vector< char > &) const
Dump prefix data.
Definition: der.cc:143
time_t time_epoch()
Epoch time.
Definition: der.cc:367
virtual std::string data_str() const
Print vizualized data.
Definition: der.cc:529
static BasePtr explicit_to_context(const BasePtr &BasePtr, uint32_t)
Convert explicit to context.
Definition: der.cc:1057
static BasePtr implicit_to_context(const BasePtr &BasePtr, uint32_t)
Convert implicit to context.
Definition: der.cc:1090
bool is_bit_string() const
Is this a DerBitString?
Definition: der.cc:239
bool is_universal_string() const
Is this a univeral (ascii) string?
Definition: der.cc:276
bool is_visible_string() const
Is this a visible (ascii) string?
Definition: der.cc:286
DerBase(uint8_t tag=0)
Construct a base object.
Definition: der.h:220
oid_value object_id()
Return the object identifier value.
Definition: der.cc:379
static BasePtr context_to_explicit(const BasePtr &)
Change a context element to explicit.
Definition: der.cc:1048
bool is_boolean() const
Is this a boolean type?
Definition: der.cc:338
bool is_utc_time() const
Is this a utc time type?
Definition: der.cc:357
bool is_contain() const
Is this a container type?
Definition: der.h:376
bool boolean()
Return boolean value.
Definition: der.cc:343
bool is_octet_string() const
Is this an octet string (8 bit chars)?
Definition: der.cc:251
static BasePtr create(int)
Create a base pointer, using only the tag byte.
Definition: der.cc:59
size_t pre_len() const
The length of prefix bytes (tag/id, and length).
Definition: der.cc:109
bool is_seq() const
Is this a sequence type?
Definition: der.cc:210
bool is_string() const
Is this a generic ascii string?
Definition: der.h:411
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
std::string string()
Return string.
Definition: der.cc:291
void string_set(const std::vector< char > &)
Set string vector.
Definition: der.cc:312
std::vector< BasePtr > & contain()
Return container, or throw an error if this is not a container.
Definition: der.cc:220
bool constructed() const
Constructed flag (bit 6).
Definition: der.h:364
std::string class_str() const
String version of the classification.
Definition: der.cc:434
bool is_ia5_string() const
Is this an ia5 (ascii) string?
Definition: der.cc:266
virtual void dump_data(std::vector< char > &) const
Dump data.
Definition: der.cc:200
uint8_t type_class() const
Classification of the type (bits 7-8)
Definition: der.h:347
static BasePtr context_to_implicit(const BasePtr &, uint32_t)
Change a context element to implicit.
Definition: der.cc:1072
bool is_bmp_string() const
Is this a bmp (ascii) string?
Definition: der.cc:271
bool is_null() const
Is this a null type?
Definition: der.cc:333
bool is_printable_string() const
Is this a printable string?
Definition: der.cc:256
bool is_set() const
Is this a set type?
Definition: der.cc:215
void string_get(std::vector< char > &)
Get string vector.
Definition: der.cc:326
bool is_integer() const
Is this a DerInteger?
Definition: der.cc:227
bool is_object_id() const
Is this an object identifier?
Definition: der.cc:374
std::string construct_str() const
String version of the construct flag.
Definition: der.cc:450
virtual std::string str(uint32_t=100) const
Print summary line to maximum width.
Definition: der.cc:459
std::string id_str() const
String version of the id.
Definition: der.cc:393
virtual size_t len() const
Length of the data.
Definition: der.h:286
bool is_generalized_time() const
Is this as generalized time type?
Definition: der.cc:362
uint32_t id() const
Tag id of the type.
Definition: der.h:325
virtual void parse(const std::vector< uint8_t > &)
Parse raw data into the object.
Definition: der.cc:977
virtual std::string data_str() const
Print vizualized data.
Definition: der.cc:1000
virtual size_t len() const
Length of the data.
Definition: der.cc:1033
virtual void dump_data(std::vector< char > &v) const
Dump data.
Definition: der.cc:1038
virtual void dump_data(std::vector< char > &v) const
Dump data.
Definition: der.cc:941
virtual void parse(const std::vector< uint8_t > &)
Parse raw data into the object.
Definition: der.cc:936
virtual size_t len() const
Length of the data.
Definition: der.cc:472
virtual std::string data_str() const
Print vizualized data.
Definition: der.cc:483
DER document.
Definition: der.h:824
bool equal(const DerDocument &) const
Compare binary data.
Definition: der.cc:1256
std::string str(bool=false) const
Debug string dump.
Definition: der.cc:1347
virtual void dump(std::vector< char > &)
Dump and append to a buffer.
Definition: der.cc:1276
static std::string print_element(const BasePtr &, bool=false, const std::string &=" |")
Print an element and any sub-elements to a string.
Definition: der.cc:1336
static void dump_element(const BasePtr &, std::vector< uint8_t > &)
Dump an element to a data vector.
Definition: der.cc:1231
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
static BasePtr parse_element(const std::vector< uint8_t > &, size_t=0)
Parse an element from a data vector.
Definition: der.cc:1171
Generalized time.
Definition: der.h:645
virtual void dump_data(std::vector< char > &v) const
Dump data.
Definition: der.cc:867
virtual void parse(const std::vector< uint8_t > &)
Parse raw data into the object.
Definition: der.cc:810
virtual size_t len() const
Length of the data.
Definition: der.cc:893
virtual std::string data_str() const
Print vizualized data.
Definition: der.cc:951
virtual void dump_data(std::vector< char > &) const
Dump data.
Definition: der.cc:972
virtual size_t len() const
Length of the data.
Definition: der.cc:967
virtual void parse(const std::vector< uint8_t > &)
Parse raw data into the object.
Definition: der.cc:946
Object identifier class.
Definition: der.h:555
virtual void dump_data(std::vector< char > &v) const
Dump data.
Definition: der.cc:623
virtual void parse(const std::vector< uint8_t > &)
Parse raw data into the object.
Definition: der.cc:563
void set(const oid_value &v)
Set oid values.
Definition: der.cc:649
virtual std::string data_str() const
Print vizualized data.
Definition: der.cc:593
virtual size_t len() const
Length of the data.
Definition: der.cc:607
An ASN.1 SEQUENCE or SEQUENCE OF type.
Definition: der.h:487
An ASN.1 SET or SET OF type.
Definition: der.h:502
All strings derive from simple string base class.
Definition: der.h:661
virtual void dump_data(std::vector< char > &v) const
Dump data.
Definition: der.cc:927
virtual void parse(const std::vector< uint8_t > &)
Parse raw data into the object.
Definition: der.cc:908
virtual std::string data_str() const
Print vizualized data.
Definition: der.cc:918
Time base class.
Definition: der.h:596
virtual std::string data_str() const
Print vizualized data.
Definition: der.cc:693
void set_time(int year, int month, int day, int hour, int minute, int second)
Set time in the local time zone.
Definition: der.cc:677
virtual void parse(const std::vector< uint8_t > &)
Parse raw data into the object.
Definition: der.cc:739
virtual void dump_data(std::vector< char > &v) const
Dump data.
Definition: der.cc:759
virtual size_t len() const
Length of the data.
Definition: der.cc:781
virtual void parse(std::istream &)
Parse document from an input stream.
Definition: der.cc:1369
virtual void dump(std::vector< char > &)
PEM-formatted dump to a buffer.
Definition: der.cc:1422
void clear() noexcept
Zero the original vector and clear it.
Definition: secvec.cc:52
Distinguished encoding rules (DER).
Binary to hex string converter.
std::ostream & operator<<(std::ostream &, const scc::net::InetAddr &)
Print the socket address details to an output stream.
Definition: inet.cc:320