Coverage Report

Created: 2021-02-21 07:20

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