Coverage Report

Created: 2023-02-22 06:39

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