diff options
Diffstat (limited to 'src/ber_code.cpp')
-rw-r--r-- | src/ber_code.cpp | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/src/ber_code.cpp b/src/ber_code.cpp new file mode 100644 index 000000000..43ec17207 --- /dev/null +++ b/src/ber_code.cpp @@ -0,0 +1,237 @@ +/************************************************* +* BER Decoding Source File * +* (C) 1999-2006 The Botan Project * +*************************************************/ + +#include <botan/ber_dec.h> +#include <botan/asn1_int.h> +#include <botan/parsing.h> +#include <botan/bigint.h> + +#include <assert.h> + +namespace Botan { + +namespace { + +/************************************************* +* Check an object's type and size * +*************************************************/ +void check_object(const BER_Object& obj, + ASN1_Tag type_tag, ASN1_Tag class_tag, + u32bit length = 0, bool check_length = false) + { + if(obj.type_tag != type_tag || obj.class_tag != class_tag) + throw BER_Decoding_Error("Tag mismatch when decoding"); + if(check_length && obj.value.size() != length) + throw BER_Decoding_Error("Incorrect size for type"); + } + +} + +/************************************************* +* Decode a BER encoded NULL * +*************************************************/ +BER_Decoder& BER_Decoder::decode_null() + { + check_object(get_next_object(), NULL_TAG, UNIVERSAL, 0, true); + return (*this); + } + +/************************************************* +* Decode a BER encoded BOOLEAN * +*************************************************/ +BER_Decoder& BER_Decoder::decode(bool& out) + { + return decode(out, BOOLEAN, UNIVERSAL); + } + +/************************************************* +* Decode a small BER encoded INTEGER * +*************************************************/ +BER_Decoder& BER_Decoder::decode(u32bit& out) + { + return decode(out, INTEGER, UNIVERSAL); + } + +/************************************************* +* Decode a BER encoded INTEGER * +*************************************************/ +BER_Decoder& BER_Decoder::decode(BigInt& out) + { + return decode(out, INTEGER, UNIVERSAL); + } + +/************************************************* +* Decode a BER encoded BOOLEAN * +*************************************************/ +BER_Decoder& BER_Decoder::decode(bool& out, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + BER_Object obj = get_next_object(); + check_object(obj, type_tag, class_tag, 1, true); + out = (obj.value[0]) ? true : false; + return (*this); + } + +/************************************************* +* Decode a small BER encoded INTEGER * +*************************************************/ +BER_Decoder& BER_Decoder::decode(u32bit& out, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + BigInt integer; + decode(integer, type_tag, class_tag); + out = integer.to_u32bit(); + return (*this); + } + +/************************************************* +* Decode a BER encoded INTEGER * +*************************************************/ +BER_Decoder& BER_Decoder::decode(BigInt& out, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + BER_Object obj = get_next_object(); + check_object(obj, type_tag, class_tag); + + if(obj.value.is_empty()) + out = 0; + else + { + const bool negative = (obj.value[0] & 0x80) ? true : false; + + if(negative) + { + for(u32bit j = obj.value.size(); j > 0; --j) + if(obj.value[j-1]--) + break; + for(u32bit j = 0; j != obj.value.size(); ++j) + obj.value[j] = ~obj.value[j]; + } + + out = BigInt(obj.value, obj.value.size()); + + if(negative) + out.flip_sign(); + } + + return (*this); + } + +/************************************************* +* BER decode a BIT STRING or OCTET STRING * +*************************************************/ +BER_Decoder& BER_Decoder::decode(MemoryRegion<byte>& out, ASN1_Tag real_type) + { + return decode(out, real_type, real_type, UNIVERSAL); + } + +/************************************************* +* BER decode a BIT STRING or OCTET STRING * +*************************************************/ +BER_Decoder& BER_Decoder::decode(MemoryRegion<byte>& buffer, + ASN1_Tag real_type, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if(real_type != OCTET_STRING && real_type != BIT_STRING) + throw BER_Bad_Tag("Bad tag for {BIT,OCTET} STRING", real_type); + + BER_Object obj = get_next_object(); + check_object(obj, type_tag, class_tag); + + if(real_type == OCTET_STRING) + buffer = obj.value; + else + { + if(obj.value[0] >= 8) + throw BER_Decoding_Error("Bad number of unused bits in BIT STRING"); + buffer.set(obj.value + 1, obj.value.size() - 1); + } + return (*this); + } + +namespace BER { + +/************************************************* +* Decode and return a BER encoded SEQUENCE * +*************************************************/ +BER_Decoder get_subsequence(BER_Decoder& decoder) + { + return get_subsequence(decoder, SEQUENCE, CONSTRUCTED); + } + +/************************************************* +* Decode and return a BER encoded SET * +*************************************************/ +BER_Decoder get_subset(BER_Decoder& decoder) + { + return get_subset(decoder, SET, CONSTRUCTED); + } + +/************************************************* +* Decode and return a BER encoded SEQUENCE * +*************************************************/ +BER_Decoder get_subsequence(BER_Decoder& decoder, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + BER_Object obj = decoder.get_next_object(); + check_object(obj, type_tag, ASN1_Tag(class_tag | CONSTRUCTED)); + return BER_Decoder(obj.value, obj.value.size()); + } + +/************************************************* +* Decode and return a BER encoded SET * +*************************************************/ +BER_Decoder get_subset(BER_Decoder& decoder, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + BER_Object obj = decoder.get_next_object(); + check_object(obj, type_tag, ASN1_Tag(class_tag | CONSTRUCTED)); + return BER_Decoder(obj.value, obj.value.size()); + } + +/************************************************* +* Convert a BER object into a string object * +*************************************************/ +std::string to_string(const BER_Object& obj) + { + std::string str((const char*)obj.value.begin(), obj.value.size()); + return str; + } + +/************************************************* +* Decode an OPTIONAL string type * +*************************************************/ +bool decode_optional_string(BER_Decoder& in, MemoryRegion<byte>& out, + ASN1_Tag real_type, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + BER_Object obj = in.get_next_object(); + + if(obj.type_tag == type_tag && obj.class_tag == class_tag) + { + if(class_tag & CONSTRUCTED) + { + BER_Decoder stored_value(obj.value); + stored_value.decode(out, real_type); + stored_value.verify_end(); + } + else + { + in.push_back(obj); + in.decode(out, real_type, type_tag, class_tag); + } + return true; + } + else + { + out.clear(); + in.push_back(obj); + return false; + } + } + +} + +} |