Botan 3.0.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#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#include <botan/internal/fmt.h>
14
15namespace Botan {
16
17namespace {
18
19/*
20* Choose an encoding for the string
21*/
22ASN1_Type choose_encoding(std::string_view str)
23 {
24 auto all_printable = CT::Mask<uint8_t>::set();
25
26 for(size_t i = 0; i != str.size(); ++i)
27 {
28 const uint8_t c = static_cast<uint8_t>(str[i]);
29
30 auto is_alpha_lower = CT::Mask<uint8_t>::is_within_range(c, 'a', 'z');
31 auto is_alpha_upper = CT::Mask<uint8_t>::is_within_range(c, 'A', 'Z');
32 auto is_decimal = CT::Mask<uint8_t>::is_within_range(c, '0', '9');
33
34 auto is_print_punc = CT::Mask<uint8_t>::is_any_of(c, {
35 ' ', '(', ')', '+', ',', '-', '.', '/',
36 ':', '=', '?'});
37
38 auto is_printable = is_alpha_lower | is_alpha_upper | is_decimal | is_print_punc;
39
40 all_printable &= is_printable;
41 }
42
43 if(all_printable.is_set())
45 else
47 }
48
49bool is_utf8_subset_string_type(ASN1_Type tag)
50 {
51 return (tag == ASN1_Type::NumericString ||
54 tag == ASN1_Type::Ia5String ||
56 }
57
58bool is_asn1_string_type(ASN1_Type tag)
59 {
60 return (is_utf8_subset_string_type(tag) ||
62 tag == ASN1_Type::BmpString ||
64 }
65
66}
67
68//static
70 {
71 return is_asn1_string_type(tag);
72 }
73
74ASN1_String::ASN1_String(std::string_view str, ASN1_Type t) : m_utf8_str(str), m_tag(t)
75 {
76 if(!is_utf8_subset_string_type(m_tag))
77 {
78 throw Invalid_Argument("ASN1_String only supports encoding to UTF-8 or a UTF-8 subset");
79 }
80 }
81
82ASN1_String::ASN1_String(std::string_view str) :
83 ASN1_String(str, choose_encoding(str))
84 {}
85
86/*
87* DER encode an ASN1_String
88*/
90 {
91 if(m_data.empty())
92 {
93 BOTAN_ASSERT_NOMSG(is_utf8_subset_string_type(tagging()));
94 encoder.add_object(tagging(), ASN1_Class::Universal, m_utf8_str);
95 }
96 else
97 {
98 // If this string was decoded, reserialize using original encoding
99 encoder.add_object(tagging(), ASN1_Class::Universal, m_data.data(), m_data.size());
100 }
101 }
102
103/*
104* Decode a BER encoded ASN1_String
105*/
107 {
108 BER_Object obj = source.get_next_object();
109
110 if(!is_asn1_string_type(obj.type()))
111 {
112 auto typ = static_cast<uint32_t>(obj.type());
113 throw Decoding_Error(fmt("ASN1_String: Unknown string type {}", typ));
114 }
115
116 m_tag = obj.type();
117 m_data.assign(obj.bits(), obj.bits() + obj.length());
118
119 if(m_tag == ASN1_Type::BmpString)
120 {
121 m_utf8_str = ucs2_to_utf8(m_data.data(), m_data.size());
122 }
123 else if(m_tag == ASN1_Type::UniversalString)
124 {
125 m_utf8_str = ucs4_to_utf8(m_data.data(), m_data.size());
126 }
127 else if(m_tag == ASN1_Type::TeletexString)
128 {
129 /*
130 TeletexString is nominally ITU T.61 not ISO-8859-1 but it seems
131 the majority of implementations actually used that charset here.
132 */
133 m_utf8_str = latin1_to_utf8(m_data.data(), m_data.size());
134 }
135 else
136 {
137 // All other supported string types are UTF-8 or some subset thereof
138 m_utf8_str = ASN1::to_string(obj);
139 }
140 }
141
142}
#define BOTAN_ASSERT_NOMSG(expr)
Definition: assert.h:67
void encode_into(DER_Encoder &) const override
Definition: asn1_str.cpp:89
ASN1_String(std::string_view utf8="")
Definition: asn1_str.cpp:82
static bool is_string_type(ASN1_Type tag)
Definition: asn1_str.cpp:69
ASN1_Type tagging() const
Definition: asn1_obj.h:434
void decode_from(BER_Decoder &) override
Definition: asn1_str.cpp:106
BER_Object get_next_object()
Definition: ber_dec.cpp:240
size_t length() const
Definition: asn1_obj.h:157
const uint8_t * bits() const
Definition: asn1_obj.h:155
ASN1_Type type() const
Definition: asn1_obj.h:152
static Mask< T > set()
Definition: ct_utils.h:105
static Mask< T > is_any_of(T v, std::initializer_list< T > accepted)
Definition: ct_utils.h:194
static Mask< T > is_within_range(T v, T l, T u)
Definition: ct_utils.h:184
DER_Encoder & add_object(ASN1_Type type_tag, ASN1_Class class_tag, const uint8_t rep[], size_t length)
Definition: der_enc.cpp:254
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:210
Definition: alg_id.cpp:12
std::string fmt(std::string_view format, const T &... args)
Definition: fmt.h:60
ASN1_Type
Definition: asn1_obj.h:43
std::string ucs2_to_utf8(const uint8_t ucs2[], size_t len)
Definition: charset.cpp:61
std::string latin1_to_utf8(const uint8_t chars[], size_t len)
Definition: charset.cpp:98
std::string ucs4_to_utf8(const uint8_t ucs4[], size_t len)
Definition: charset.cpp:78