diff options
Diffstat (limited to 'src/lib/asn1/asn1_oid.cpp')
-rw-r--r-- | src/lib/asn1/asn1_oid.cpp | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/src/lib/asn1/asn1_oid.cpp b/src/lib/asn1/asn1_oid.cpp new file mode 100644 index 000000000..964315080 --- /dev/null +++ b/src/lib/asn1/asn1_oid.cpp @@ -0,0 +1,189 @@ +/* +* ASN.1 OID +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/asn1_oid.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/internal/bit_ops.h> +#include <botan/parsing.h> + +namespace Botan { + +/* +* ASN.1 OID Constructor +*/ +OID::OID(const std::string& oid_str) + { + if(oid_str != "") + { + try + { + id = parse_asn1_oid(oid_str); + } + catch(...) + { + throw Invalid_OID(oid_str); + } + + if(id.size() < 2 || id[0] > 2) + throw Invalid_OID(oid_str); + if((id[0] == 0 || id[0] == 1) && id[1] > 39) + throw Invalid_OID(oid_str); + } + } + +/* +* Clear the current OID +*/ +void OID::clear() + { + id.clear(); + } + +/* +* Return this OID as a string +*/ +std::string OID::as_string() const + { + std::string oid_str; + for(size_t i = 0; i != id.size(); ++i) + { + oid_str += std::to_string(id[i]); + if(i != id.size() - 1) + oid_str += '.'; + } + return oid_str; + } + +/* +* OID equality comparison +*/ +bool OID::operator==(const OID& oid) const + { + if(id.size() != oid.id.size()) + return false; + for(size_t i = 0; i != id.size(); ++i) + if(id[i] != oid.id[i]) + return false; + return true; + } + +/* +* Append another component to the OID +*/ +OID& OID::operator+=(u32bit component) + { + id.push_back(component); + return (*this); + } + +/* +* Append another component to the OID +*/ +OID operator+(const OID& oid, u32bit component) + { + OID new_oid(oid); + new_oid += component; + return new_oid; + } + +/* +* OID inequality comparison +*/ +bool operator!=(const OID& a, const OID& b) + { + return !(a == b); + } + +/* +* Compare two OIDs +*/ +bool operator<(const OID& a, const OID& b) + { + const std::vector<u32bit>& oid1 = a.get_id(); + const std::vector<u32bit>& oid2 = b.get_id(); + + if(oid1.size() < oid2.size()) + return true; + if(oid1.size() > oid2.size()) + return false; + for(size_t i = 0; i != oid1.size(); ++i) + { + if(oid1[i] < oid2[i]) + return true; + if(oid1[i] > oid2[i]) + return false; + } + return false; + } + +/* +* DER encode an OBJECT IDENTIFIER +*/ +void OID::encode_into(DER_Encoder& der) const + { + if(id.size() < 2) + throw Invalid_Argument("OID::encode_into: OID is invalid"); + + std::vector<byte> encoding; + encoding.push_back(40 * id[0] + id[1]); + + for(size_t i = 2; i != id.size(); ++i) + { + if(id[i] == 0) + encoding.push_back(0); + else + { + size_t blocks = high_bit(id[i]) + 6; + blocks = (blocks - (blocks % 7)) / 7; + + for(size_t j = 0; j != blocks - 1; ++j) + encoding.push_back(0x80 | ((id[i] >> 7*(blocks-j-1)) & 0x7F)); + encoding.push_back(id[i] & 0x7F); + } + } + der.add_object(OBJECT_ID, UNIVERSAL, encoding); + } + +/* +* Decode a BER encoded OBJECT IDENTIFIER +*/ +void OID::decode_from(BER_Decoder& decoder) + { + BER_Object obj = decoder.get_next_object(); + if(obj.type_tag != OBJECT_ID || obj.class_tag != UNIVERSAL) + throw BER_Bad_Tag("Error decoding OID, unknown tag", + obj.type_tag, obj.class_tag); + if(obj.value.size() < 2) + throw BER_Decoding_Error("OID encoding is too short"); + + + clear(); + id.push_back(obj.value[0] / 40); + id.push_back(obj.value[0] % 40); + + size_t i = 0; + while(i != obj.value.size() - 1) + { + u32bit component = 0; + while(i != obj.value.size() - 1) + { + ++i; + + if(component >> (32-7)) + throw Decoding_Error("OID component overflow"); + + component = (component << 7) + (obj.value[i] & 0x7F); + + if(!(obj.value[i] & 0x80)) + break; + } + id.push_back(component); + } + } + +} |