Botan 3.12.0
Crypto and TLS for C&
asn1_str.cpp
Go to the documentation of this file.
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
10#include <botan/assert.h>
11#include <botan/ber_dec.h>
12#include <botan/der_enc.h>
13#include <botan/internal/charset.h>
14#include <botan/internal/fmt.h>
15#include <array>
16
17namespace Botan {
18
19namespace {
20
21class ASN1_String_Codepoint_Validator final {
22 public:
23 constexpr ASN1_String_Codepoint_Validator() : m_table(make_table()) {}
24
25 constexpr bool valid_encoding(std::string_view str, ASN1_Type tag) const {
26 const uint8_t mask = mask_for(tag);
27 for(const char c : str) {
28 const uint8_t codepoint = static_cast<uint8_t>(c);
29 const bool is_valid = (m_table[codepoint] & mask) != 0;
30
31 if(!is_valid) {
32 return false;
33 }
34 }
35
36 return true;
37 }
38
39 private:
40 static constexpr uint8_t Numeric_String = 0x01;
41 static constexpr uint8_t Printable_String = 0x02;
42 static constexpr uint8_t IA5_String = 0x04;
43 static constexpr uint8_t Visible_String = 0x08;
44
45 static constexpr uint8_t mask_for(ASN1_Type tag) {
46 switch(tag) {
48 return Numeric_String;
50 return Printable_String;
52 return IA5_String;
54 return Visible_String;
55 default:
56 return 0;
57 }
58 }
59
60 static constexpr std::array<uint8_t, 256> make_table() {
61 std::array<uint8_t, 256> table = {};
62
63 for(size_t i = 0; i != table.size(); ++i) {
64 const auto c = static_cast<uint8_t>(i);
65
66 // Don't allow embedded null in IA5 even if technically valid
67 if(c >= 1 && c <= 0x7F) {
68 table[i] |= IA5_String;
69 }
70
71 if(c >= 0x20 && c <= 0x7E) {
72 table[i] |= Visible_String;
73 }
74
75 if(c == ' ' || (c >= '0' && c <= '9')) {
76 table[i] |= Numeric_String;
77 }
78
79 if((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == ' ' || c == '\'' ||
80 c == '(' || c == ')' || c == '+' || c == ',' || c == '-' || c == '.' || c == '/' || c == ':' ||
81 c == '=' || c == '?') {
82 table[i] |= Printable_String;
83 }
84 }
85
86 return table;
87 }
88
89 std::array<uint8_t, 256> m_table;
90};
91
92constexpr ASN1_String_Codepoint_Validator g_char_validator;
93
94bool is_utf8_subset_string_type(ASN1_Type tag) {
97}
98
99bool is_asn1_string_type(ASN1_Type tag) {
100 return (is_utf8_subset_string_type(tag) || tag == ASN1_Type::TeletexString || tag == ASN1_Type::BmpString ||
102}
103
104bool is_valid_asn1_string_content(const std::string& str, ASN1_Type tag) {
105 BOTAN_ASSERT_NOMSG(is_utf8_subset_string_type(tag));
106
107 switch(tag) {
109 return is_valid_utf8(str);
114 return g_char_validator.valid_encoding(str, tag);
115 default:
116 return false;
117 }
118}
119
120ASN1_Type choose_encoding(std::string_view str) {
121 if(g_char_validator.valid_encoding(str, ASN1_Type::PrintableString)) {
123 } else {
125 }
126}
127
128} // namespace
129
130//static
132 return is_asn1_string_type(tag);
133}
134
135ASN1_String::ASN1_String(std::string_view str, ASN1_Type t) : m_utf8_str(str), m_tag(t) {
136 if(!is_utf8_subset_string_type(m_tag)) {
137 throw Invalid_Argument("ASN1_String only supports encoding to UTF-8 or a UTF-8 subset");
138 }
139
140 if(!is_valid_asn1_string_content(m_utf8_str, m_tag)) {
141 throw Invalid_Argument(fmt("ASN1_String: Invalid {} encoding", asn1_tag_to_string(m_tag)));
142 }
143}
144
145ASN1_String::ASN1_String(std::string_view str) : ASN1_String(str, choose_encoding(str)) {}
146
147/*
148* DER encode an ASN1_String
149*/
151 if(m_data.empty()) {
152 BOTAN_ASSERT_NOMSG(is_utf8_subset_string_type(tagging()));
153 encoder.add_object(tagging(), ASN1_Class::Universal, m_utf8_str);
154 } else {
155 // If this string was decoded, reserialize using original encoding
156 encoder.add_object(tagging(), ASN1_Class::Universal, m_data.data(), m_data.size());
157 }
158}
159
160/*
161* Decode a BER encoded ASN1_String
162*/
164 const BER_Object obj = source.get_next_object();
165
166 if(obj.get_class() != ASN1_Class::Universal || !is_asn1_string_type(obj.type())) {
167 auto typ = static_cast<uint32_t>(obj.type());
168 auto cls = static_cast<uint32_t>(obj.get_class());
169 throw Decoding_Error(fmt("ASN1_String: Unknown string type {}/{}", typ, cls));
170 }
171
172 m_tag = obj.type();
173 m_data.assign(obj.bits(), obj.bits() + obj.length());
174
175 if(m_tag == ASN1_Type::BmpString) {
176 m_utf8_str = ucs2_to_utf8(m_data.data(), m_data.size());
177 } else if(m_tag == ASN1_Type::UniversalString) {
178 m_utf8_str = ucs4_to_utf8(m_data.data(), m_data.size());
179 } else if(m_tag == ASN1_Type::TeletexString) {
180 /*
181 TeletexString is nominally ITU T.61 not ISO-8859-1 but it seems
182 the majority of implementations actually used that charset here.
183 */
184 m_utf8_str = latin1_to_utf8(m_data.data(), m_data.size());
185 } else {
186 // All other supported string types are UTF-8 or some subset thereof
187 m_utf8_str = ASN1::to_string(obj);
188
189 if(!is_valid_asn1_string_content(m_utf8_str, m_tag)) {
190 throw Decoding_Error(fmt("ASN1_String: Invalid {} encoding", asn1_tag_to_string(m_tag)));
191 }
192 }
193}
194
195} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
ASN1_String(std::string_view utf8="")
Definition asn1_str.cpp:145
static bool is_string_type(ASN1_Type tag)
Definition asn1_str.cpp:131
void encode_into(DER_Encoder &to) const override
Definition asn1_str.cpp:150
ASN1_Type tagging() const
Definition asn1_obj.h:363
void decode_from(BER_Decoder &from) override
Definition asn1_str.cpp:163
BER_Object get_next_object()
Definition ber_dec.cpp:426
size_t length() const
Definition asn1_obj.h:152
const uint8_t * bits() const
Definition asn1_obj.h:150
ASN1_Type type() const
Definition asn1_obj.h:146
ASN1_Class get_class() const
Definition asn1_obj.h:148
DER_Encoder & add_object(ASN1_Type type_tag, ASN1_Class class_tag, const uint8_t rep[], size_t length)
Definition der_enc.cpp:217
std::string to_string(const BER_Object &obj)
Definition asn1_obj.cpp:190
std::string asn1_tag_to_string(ASN1_Type type)
Definition asn1_obj.cpp:98
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
ASN1_Type
Definition asn1_obj.h:43
bool is_valid_utf8(const std::string &utf8)
Definition charset.cpp:106
std::string ucs2_to_utf8(const uint8_t ucs2[], size_t len)
Definition charset.cpp:119
std::string latin1_to_utf8(const uint8_t chars[], size_t len)
Definition charset.cpp:188
std::string ucs4_to_utf8(const uint8_t ucs4[], size_t len)
Definition charset.cpp:153