Botan 3.4.0
Crypto and TLS for C&
asn1_oid.cpp
Go to the documentation of this file.
1/*
2* ASN.1 OID
3* (C) 1999-2007 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/bit_ops.h>
13#include <botan/internal/fmt.h>
14#include <botan/internal/oid_map.h>
15#include <botan/internal/parsing.h>
16#include <algorithm>
17#include <sstream>
18
19namespace Botan {
20
21namespace {
22
23// returns empty on invalid
24std::vector<uint32_t> parse_oid_str(std::string_view oid) {
25 try {
26 std::string elem;
27 std::vector<uint32_t> oid_elems;
28
29 for(char c : oid) {
30 if(c == '.') {
31 if(elem.empty()) {
32 return std::vector<uint32_t>();
33 }
34 oid_elems.push_back(to_u32bit(elem));
35 elem.clear();
36 } else {
37 elem += c;
38 }
39 }
40
41 if(!elem.empty()) {
42 oid_elems.push_back(to_u32bit(elem));
43 }
44
45 return oid_elems;
46 } catch(Invalid_Argument&) // thrown by to_u32bit
47 {
48 return std::vector<uint32_t>();
49 }
50}
51
52} // namespace
53
54//static
55void OID::register_oid(const OID& oid, std::string_view name) {
57}
58
59//static
60std::optional<OID> OID::from_name(std::string_view name) {
61 if(name.empty()) {
62 throw Invalid_Argument("OID::from_name argument must be non-empty");
63 }
64
66 if(o.has_value()) {
67 return std::optional(o);
68 }
69
70 return std::nullopt;
71}
72
73//static
74OID OID::from_string(std::string_view str) {
75 if(str.empty()) {
76 throw Invalid_Argument("OID::from_string argument must be non-empty");
77 }
78
80 if(o.has_value()) {
81 return o;
82 }
83
84 std::vector<uint32_t> raw = parse_oid_str(str);
85
86 if(!raw.empty()) {
87 return OID(std::move(raw));
88 }
89
90 throw Lookup_Error(fmt("No OID associated with name '{}'", str));
91}
92
93/*
94* ASN.1 OID Constructor
95*/
96OID::OID(std::string_view oid_str) {
97 if(!oid_str.empty()) {
98 m_id = parse_oid_str(oid_str);
99 if(m_id.size() < 2 || m_id[0] > 2 || (m_id[0] < 2 && m_id[1] > 39)) {
100 throw Decoding_Error(fmt("Invalid OID '{}'", oid_str));
101 }
102 }
103}
104
105/*
106* Return this OID as a string
107*/
108std::string OID::to_string() const {
109 std::ostringstream out;
110 out << (*this);
111 return out.str();
112}
113
114std::string OID::to_formatted_string() const {
115 std::string s = this->human_name_or_empty();
116 if(!s.empty()) {
117 return s;
118 }
119 return this->to_string();
120}
121
122std::string OID::human_name_or_empty() const {
123 return OID_Map::global_registry().oid2str(*this);
124}
125
127 return !human_name_or_empty().empty();
128}
129
130/*
131* Compare two OIDs
132*/
133bool operator<(const OID& a, const OID& b) {
134 const std::vector<uint32_t>& oid1 = a.get_components();
135 const std::vector<uint32_t>& oid2 = b.get_components();
136
137 return std::lexicographical_compare(oid1.begin(), oid1.end(), oid2.begin(), oid2.end());
138}
139
140std::ostream& operator<<(std::ostream& out, const OID& oid) {
141 const auto& val = oid.get_components();
142
143 for(size_t i = 0; i != val.size(); ++i) {
144 // avoid locale issues with integer formatting
145 out << std::to_string(val[i]);
146 if(i != val.size() - 1) {
147 out << ".";
148 }
149 }
150
151 return out;
152}
153
154/*
155* DER encode an OBJECT IDENTIFIER
156*/
158 if(m_id.size() < 2) {
159 throw Invalid_Argument("OID::encode_into: OID is invalid");
160 }
161
162 std::vector<uint8_t> encoding;
163
164 if(m_id[0] > 2 || m_id[1] >= 40) {
165 throw Encoding_Error("Invalid OID prefix, cannot encode");
166 }
167
168 encoding.push_back(static_cast<uint8_t>(40 * m_id[0] + m_id[1]));
169
170 for(size_t i = 2; i != m_id.size(); ++i) {
171 if(m_id[i] == 0) {
172 encoding.push_back(0);
173 } else {
174 size_t blocks = high_bit(m_id[i]) + 6;
175 blocks = (blocks - (blocks % 7)) / 7;
176
177 BOTAN_ASSERT(blocks > 0, "Math works");
178
179 for(size_t j = 0; j != blocks - 1; ++j) {
180 encoding.push_back(0x80 | ((m_id[i] >> 7 * (blocks - j - 1)) & 0x7F));
181 }
182 encoding.push_back(m_id[i] & 0x7F);
183 }
184 }
186}
187
188/*
189* Decode a BER encoded OBJECT IDENTIFIER
190*/
192 BER_Object obj = decoder.get_next_object();
194 throw BER_Bad_Tag("Error decoding OID, unknown tag", obj.tagging());
195 }
196
197 const size_t length = obj.length();
198 const uint8_t* bits = obj.bits();
199
200 if(length < 2 && !(length == 1 && bits[0] == 0)) {
201 throw BER_Decoding_Error("OID encoding is too short");
202 }
203
204 m_id.clear();
205 m_id.push_back(bits[0] / 40);
206 m_id.push_back(bits[0] % 40);
207
208 size_t i = 0;
209 while(i != length - 1) {
210 uint32_t component = 0;
211 while(i != length - 1) {
212 ++i;
213
214 if(component >> (32 - 7)) {
215 throw Decoding_Error("OID component overflow");
216 }
217
218 component = (component << 7) + (bits[i] & 0x7F);
219
220 if(!(bits[i] & 0x80)) {
221 break;
222 }
223 }
224 m_id.push_back(component);
225 }
226}
227
228} // namespace Botan
#define BOTAN_ASSERT(expr, assertion_made)
Definition assert.h:50
BER_Object get_next_object()
Definition ber_dec.cpp:231
size_t length() const
Definition asn1_obj.h:152
const uint8_t * bits() const
Definition asn1_obj.h:150
uint32_t tagging() const
Definition asn1_obj.h:140
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 oid2str(const OID &oid)
Definition oid_map.cpp:56
void add_oid(const OID &oid, std::string_view str)
Definition oid_map.cpp:21
static OID_Map & global_registry()
Definition oid_map.cpp:16
OID str2oid(std::string_view str)
Definition oid_map.cpp:69
void encode_into(DER_Encoder &) const override
Definition asn1_oid.cpp:157
std::string to_formatted_string() const
Definition asn1_oid.cpp:114
bool registered_oid() const
Definition asn1_oid.cpp:126
const std::vector< uint32_t > & get_components() const
Definition asn1_obj.h:277
static std::optional< OID > from_name(std::string_view name)
Definition asn1_oid.cpp:60
static void register_oid(const OID &oid, std::string_view name)
Definition asn1_oid.cpp:55
std::string human_name_or_empty() const
Definition asn1_oid.cpp:122
OID()=default
bool has_value() const
Definition asn1_obj.h:271
void decode_from(BER_Decoder &) override
Definition asn1_oid.cpp:191
std::string to_string() const
Definition asn1_oid.cpp:108
static OID from_string(std::string_view str)
Definition asn1_oid.cpp:74
std::string name
uint32_t to_u32bit(std::string_view str_view)
Definition parsing.cpp:32
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
bool operator<(const OID &a, const OID &b)
Definition asn1_oid.cpp:133
constexpr size_t high_bit(T n)
Definition bit_ops.h:58
std::ostream & operator<<(std::ostream &out, const OID &oid)
Definition asn1_oid.cpp:140