Coverage Report

Created: 2021-06-10 10:30

/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
113k
   {
23
113k
   auto all_printable = CT::Mask<uint8_t>::set();
24
25
113k
   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
113k
   if(all_printable.is_set())
43
113k
      return ASN1_Type::PrintableString;
44
0
   else
45
0
      return ASN1_Type::Utf8String;
46
113k
   }
47
48
bool is_utf8_subset_string_type(ASN1_Type tag)
49
277k
   {
50
277k
   return (tag == ASN1_Type::NumericString ||
51
264k
           tag == ASN1_Type::PrintableString ||
52
126k
           tag == ASN1_Type::VisibleString ||
53
113k
           tag == ASN1_Type::Ia5String ||
54
106k
           tag == ASN1_Type::Utf8String);
55
277k
   }
56
57
bool is_asn1_string_type(ASN1_Type tag)
58
158k
   {
59
158k
   return (is_utf8_subset_string_type(tag) ||
60
55.8k
           tag == ASN1_Type::TeletexString ||
61
50.0k
           tag == ASN1_Type::BmpString ||
62
43.4k
           tag == ASN1_Type::UniversalString);
63
158k
   }
64
65
}
66
67
//static
68
bool ASN1_String::is_string_type(ASN1_Type tag)
69
46.1k
   {
70
46.1k
   return is_asn1_string_type(tag);
71
46.1k
   }
72
73
ASN1_String::ASN1_String(const std::string& str, ASN1_Type t) : m_utf8_str(str), m_tag(t)
74
117k
   {
75
117k
   if(!is_utf8_subset_string_type(m_tag))
76
4
      {
77
4
      throw Invalid_Argument("ASN1_String only supports encoding to UTF-8 or a UTF-8 subset");
78
4
      }
79
117k
   }
80
81
ASN1_String::ASN1_String(const std::string& str) :
82
   ASN1_String(str, choose_encoding(str))
83
113k
   {}
84
85
/*
86
* DER encode an ASN1_String
87
*/
88
void ASN1_String::encode_into(DER_Encoder& encoder) const
89
1.28k
   {
90
1.28k
   if(m_data.empty())
91
1.28k
      {
92
1.28k
      BOTAN_ASSERT_NOMSG(is_utf8_subset_string_type(tagging()));
93
1.28k
      encoder.add_object(tagging(), ASN1_Class::Universal, m_utf8_str);
94
1.28k
      }
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
1.28k
   }
101
102
/*
103
* Decode a BER encoded ASN1_String
104
*/
105
void ASN1_String::decode_from(BER_Decoder& source)
106
112k
   {
107
112k
   BER_Object obj = source.get_next_object();
108
109
112k
   if(!is_asn1_string_type(obj.type()))
110
521
      {
111
521
      throw Decoding_Error("ASN1_String: Unknown string type " +
112
521
                           std::to_string(static_cast<uint32_t>(obj.type())));
113
521
      }
114
115
112k
   m_tag = obj.type();
116
112k
   m_data.assign(obj.bits(), obj.bits() + obj.length());
117
118
112k
   if(m_tag == ASN1_Type::BmpString)
119
5.53k
      {
120
5.53k
      m_utf8_str = ucs2_to_utf8(m_data.data(), m_data.size());
121
5.53k
      }
122
106k
   else if(m_tag == ASN1_Type::UniversalString)
123
2.73k
      {
124
2.73k
      m_utf8_str = ucs4_to_utf8(m_data.data(), m_data.size());
125
2.73k
      }
126
103k
   else if(m_tag == ASN1_Type::TeletexString)
127
5.15k
      {
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.15k
      m_utf8_str = latin1_to_utf8(m_data.data(), m_data.size());
133
5.15k
      }
134
98.6k
   else
135
98.6k
      {
136
      // All other supported string types are UTF-8 or some subset thereof
137
98.6k
      m_utf8_str = ASN1::to_string(obj);
138
98.6k
      }
139
112k
   }
140
141
}