Coverage Report

Created: 2021-11-25 09:31

/src/botan/src/lib/asn1/asn1_str.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* Simple ASN.1 String Types
3
* (C) 1999-2007,2020 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7
8
#include <botan/asn1_obj.h>
9
#include <botan/der_enc.h>
10
#include <botan/ber_dec.h>
11
#include <botan/internal/charset.h>
12
#include <botan/internal/ct_utils.h>
13
14
namespace Botan {
15
16
namespace {
17
18
/*
19
* Choose an encoding for the string
20
*/
21
ASN1_Type choose_encoding(const std::string& str)
22
109k
   {
23
109k
   auto all_printable = CT::Mask<uint8_t>::set();
24
25
109k
   for(size_t i = 0; i != str.size(); ++i)
26
0
      {
27
0
      const uint8_t c = static_cast<uint8_t>(str[i]);
28
29
0
      auto is_alpha_lower = CT::Mask<uint8_t>::is_within_range(c, 'a', 'z');
30
0
      auto is_alpha_upper = CT::Mask<uint8_t>::is_within_range(c, 'A', 'Z');
31
0
      auto is_decimal = CT::Mask<uint8_t>::is_within_range(c, '0', '9');
32
33
0
      auto is_print_punc = CT::Mask<uint8_t>::is_any_of(c, {
34
0
            ' ', '(', ')', '+', ',', '=', ',', '-', '.', '/',
35
0
            ':', '=', '?'});
36
37
0
      auto is_printable = is_alpha_lower | is_alpha_upper | is_decimal | is_print_punc;
38
39
0
      all_printable &= is_printable;
40
0
      }
41
42
109k
   if(all_printable.is_set())
43
109k
      return ASN1_Type::PrintableString;
44
0
   else
45
0
      return ASN1_Type::Utf8String;
46
109k
   }
47
48
bool is_utf8_subset_string_type(ASN1_Type tag)
49
264k
   {
50
264k
   return (tag == ASN1_Type::NumericString ||
51
264k
           tag == ASN1_Type::PrintableString ||
52
264k
           tag == ASN1_Type::VisibleString ||
53
264k
           tag == ASN1_Type::Ia5String ||
54
264k
           tag == ASN1_Type::Utf8String);
55
264k
   }
56
57
bool is_asn1_string_type(ASN1_Type tag)
58
149k
   {
59
149k
   return (is_utf8_subset_string_type(tag) ||
60
149k
           tag == ASN1_Type::TeletexString ||
61
149k
           tag == ASN1_Type::BmpString ||
62
149k
           tag == ASN1_Type::UniversalString);
63
149k
   }
64
65
}
66
67
//static
68
bool ASN1_String::is_string_type(ASN1_Type tag)
69
41.3k
   {
70
41.3k
   return is_asn1_string_type(tag);
71
41.3k
   }
72
73
ASN1_String::ASN1_String(const std::string& str, ASN1_Type t) : m_utf8_str(str), m_tag(t)
74
113k
   {
75
113k
   if(!is_utf8_subset_string_type(m_tag))
76
19
      {
77
19
      throw Invalid_Argument("ASN1_String only supports encoding to UTF-8 or a UTF-8 subset");
78
19
      }
79
113k
   }
80
81
ASN1_String::ASN1_String(const std::string& str) :
82
   ASN1_String(str, choose_encoding(str))
83
109k
   {}
84
85
/*
86
* DER encode an ASN1_String
87
*/
88
void ASN1_String::encode_into(DER_Encoder& encoder) const
89
945
   {
90
945
   if(m_data.empty())
91
945
      {
92
945
      BOTAN_ASSERT_NOMSG(is_utf8_subset_string_type(tagging()));
93
945
      encoder.add_object(tagging(), ASN1_Class::Universal, m_utf8_str);
94
945
      }
95
0
   else
96
0
      {
97
      // If this string was decoded, reserialize using original encoding
98
0
      encoder.add_object(tagging(), ASN1_Class::Universal, m_data.data(), m_data.size());
99
0
      }
100
945
   }
101
102
/*
103
* Decode a BER encoded ASN1_String
104
*/
105
void ASN1_String::decode_from(BER_Decoder& source)
106
108k
   {
107
108k
   BER_Object obj = source.get_next_object();
108
109
108k
   if(!is_asn1_string_type(obj.type()))
110
532
      {
111
532
      throw Decoding_Error("ASN1_String: Unknown string type " +
112
532
                           std::to_string(static_cast<uint32_t>(obj.type())));
113
532
      }
114
115
108k
   m_tag = obj.type();
116
108k
   m_data.assign(obj.bits(), obj.bits() + obj.length());
117
118
108k
   if(m_tag == ASN1_Type::BmpString)
119
4.27k
      {
120
4.27k
      m_utf8_str = ucs2_to_utf8(m_data.data(), m_data.size());
121
4.27k
      }
122
103k
   else if(m_tag == ASN1_Type::UniversalString)
123
2.99k
      {
124
2.99k
      m_utf8_str = ucs4_to_utf8(m_data.data(), m_data.size());
125
2.99k
      }
126
100k
   else if(m_tag == ASN1_Type::TeletexString)
127
5.41k
      {
128
      /*
129
      TeletexString is nominally ITU T.61 not ISO-8859-1 but it seems
130
      the majority of implementations actually used that charset here.
131
      */
132
5.41k
      m_utf8_str = latin1_to_utf8(m_data.data(), m_data.size());
133
5.41k
      }
134
95.3k
   else
135
95.3k
      {
136
      // All other supported string types are UTF-8 or some subset thereof
137
95.3k
      m_utf8_str = ASN1::to_string(obj);
138
95.3k
      }
139
108k
   }
140
141
}