Botan  2.18.1
Crypto and TLS for C++11
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 
17 namespace Botan {
18 
19 namespace {
20 
21 // returns empty on invalid
22 std::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
62 OID 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 */
82 OID::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 */
98 std::string OID::to_string() const
99  {
100  std::ostringstream oss;
101  oss.imbue(std::locale("C"));
102  for(size_t i = 0; i != m_id.size(); ++i)
103  {
104  oss << m_id[i];
105  if(i != m_id.size() - 1)
106  oss << ".";
107  }
108  return oss.str();
109  }
110 
111 std::string OID::to_formatted_string() const
112  {
113  const std::string s = OIDS::oid2str_or_empty(*this);
114  if(!s.empty())
115  return s;
116  return this->to_string();
117  }
118 
119 /*
120 * Append another component to the OID
121 */
122 OID operator+(const OID& oid, uint32_t new_component)
123  {
124  std::vector<uint32_t> val = oid.get_components();
125  val.push_back(new_component);
126  return OID(std::move(val));
127  }
128 
129 /*
130 * Compare two OIDs
131 */
132 bool operator<(const OID& a, const OID& b)
133  {
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(),
138  oid2.begin(), oid2.end());
139  }
140 
141 /*
142 * DER encode an OBJECT IDENTIFIER
143 */
145  {
146  if(m_id.size() < 2)
147  throw Invalid_Argument("OID::encode_into: OID is invalid");
148 
149  std::vector<uint8_t> encoding;
150 
151  if(m_id[0] > 2 || m_id[1] >= 40)
152  throw Encoding_Error("Invalid OID prefix, cannot encode");
153 
154  encoding.push_back(static_cast<uint8_t>(40 * m_id[0] + m_id[1]));
155 
156  for(size_t i = 2; i != m_id.size(); ++i)
157  {
158  if(m_id[i] == 0)
159  encoding.push_back(0);
160  else
161  {
162  size_t blocks = high_bit(m_id[i]) + 6;
163  blocks = (blocks - (blocks % 7)) / 7;
164 
165  BOTAN_ASSERT(blocks > 0, "Math works");
166 
167  for(size_t j = 0; j != blocks - 1; ++j)
168  encoding.push_back(0x80 | ((m_id[i] >> 7*(blocks-j-1)) & 0x7F));
169  encoding.push_back(m_id[i] & 0x7F);
170  }
171  }
172  der.add_object(OBJECT_ID, UNIVERSAL, encoding);
173  }
174 
175 /*
176 * Decode a BER encoded OBJECT IDENTIFIER
177 */
179  {
180  BER_Object obj = decoder.get_next_object();
181  if(obj.tagging() != OBJECT_ID)
182  throw BER_Bad_Tag("Error decoding OID, unknown tag", obj.tagging());
183 
184  const size_t length = obj.length();
185  const uint8_t* bits = obj.bits();
186 
187  if(length < 2 && !(length == 1 && bits[0] == 0))
188  {
189  throw BER_Decoding_Error("OID encoding is too short");
190  }
191 
192  m_id.clear();
193  m_id.push_back(bits[0] / 40);
194  m_id.push_back(bits[0] % 40);
195 
196  size_t i = 0;
197  while(i != length - 1)
198  {
199  uint32_t component = 0;
200  while(i != length - 1)
201  {
202  ++i;
203 
204  if(component >> (32-7))
205  throw Decoding_Error("OID component overflow");
206 
207  component = (component << 7) + (bits[i] & 0x7F);
208 
209  if(!(bits[i] & 0x80))
210  break;
211  }
212  m_id.push_back(component);
213  }
214  }
215 
216 }
ASN1_Tag tagging() const
Definition: asn1_obj.h:114
DER_Encoder & add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, const uint8_t rep[], size_t length)
Definition: der_enc.cpp:249
void encode_into(class DER_Encoder &) const override
Definition: asn1_oid.cpp:144
const std::vector< uint32_t > & get_components() const
Definition: asn1_obj.h:244
BOTAN_UNSTABLE_API std::string oid2str_or_empty(const OID &oid)
Definition: oids.cpp:111
OID operator+(const OID &oid, uint32_t new_comp)
Definition: asn1_oid.cpp:122
uint32_t to_u32bit(const std::string &str)
Definition: parsing.cpp:35
BOTAN_UNSTABLE_API OID str2oid_or_empty(const std::string &name)
Definition: oids.cpp:116
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:55
std::string to_string() const
Definition: asn1_oid.cpp:98
bool operator<(const OID &a, const OID &b)
Definition: asn1_oid.cpp:132
void decode_from(class BER_Decoder &) override
Definition: asn1_oid.cpp:178
size_t high_bit(T n)
Definition: bit_ops.h:55
size_t length() const
Definition: asn1_obj.h:121
Definition: alg_id.cpp:13
BER_Object get_next_object()
Definition: ber_dec.cpp:237
const uint8_t * bits() const
Definition: asn1_obj.h:119
std::string to_formatted_string() const
Definition: asn1_oid.cpp:111
bool has_value() const
Definition: asn1_obj.h:238
static OID from_string(const std::string &str)
Definition: asn1_oid.cpp:62