/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 | | } |