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