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