Coverage Report

Created: 2022-01-14 08:07

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