8#include <botan/asn1_obj.h>
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>
21class ASN1_String_Codepoint_Validator final {
23 constexpr ASN1_String_Codepoint_Validator() : m_table(make_table()) {}
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;
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;
45 static constexpr uint8_t mask_for(
ASN1_Type tag) {
48 return Numeric_String;
50 return Printable_String;
54 return Visible_String;
60 static constexpr std::array<uint8_t, 256> make_table() {
61 std::array<uint8_t, 256> table = {};
63 for(
size_t i = 0; i != table.size(); ++i) {
64 const auto c =
static_cast<uint8_t
>(i);
67 if(c >= 1 && c <= 0x7F) {
68 table[i] |= IA5_String;
71 if(c >= 0x20 && c <= 0x7E) {
72 table[i] |= Visible_String;
75 if(c ==
' ' || (c >=
'0' && c <=
'9')) {
76 table[i] |= Numeric_String;
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;
89 std::array<uint8_t, 256> m_table;
92constexpr ASN1_String_Codepoint_Validator g_char_validator;
94bool is_utf8_subset_string_type(
ASN1_Type tag) {
104bool is_valid_asn1_string_content(
const std::string& str,
ASN1_Type tag) {
114 return g_char_validator.valid_encoding(str, tag);
120ASN1_Type choose_encoding(std::string_view str) {
132 return is_asn1_string_type(tag);
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");
140 if(!is_valid_asn1_string_content(m_utf8_str, m_tag)) {
167 auto typ =
static_cast<uint32_t
>(obj.
type());
168 auto cls =
static_cast<uint32_t
>(obj.
get_class());
176 m_utf8_str =
ucs2_to_utf8(m_data.data(), m_data.size());
178 m_utf8_str =
ucs4_to_utf8(m_data.data(), m_data.size());
189 if(!is_valid_asn1_string_content(m_utf8_str, m_tag)) {
#define BOTAN_ASSERT_NOMSG(expr)
ASN1_String(std::string_view utf8="")
static bool is_string_type(ASN1_Type tag)
void encode_into(DER_Encoder &to) const override
ASN1_Type tagging() const
void decode_from(BER_Decoder &from) override
BER_Object get_next_object()
const uint8_t * bits() const
ASN1_Class get_class() const
DER_Encoder & add_object(ASN1_Type type_tag, ASN1_Class class_tag, const uint8_t rep[], size_t length)
std::string to_string(const BER_Object &obj)
std::string asn1_tag_to_string(ASN1_Type type)
std::string fmt(std::string_view format, const T &... args)
bool is_valid_utf8(const std::string &utf8)
std::string ucs2_to_utf8(const uint8_t ucs2[], size_t len)
std::string latin1_to_utf8(const uint8_t chars[], size_t len)
std::string ucs4_to_utf8(const uint8_t ucs4[], size_t len)