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