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