aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/manual/deprecated.rst2
-rw-r--r--src/lib/asn1/asn1_obj.cpp42
-rw-r--r--src/lib/asn1/asn1_obj.h42
-rw-r--r--src/lib/asn1/asn1_oid.cpp24
-rw-r--r--src/lib/asn1/asn1_print.cpp12
-rw-r--r--src/lib/asn1/asn1_str.cpp6
-rw-r--r--src/lib/asn1/asn1_time.cpp2
-rw-r--r--src/lib/asn1/ber_dec.cpp95
-rw-r--r--src/lib/asn1/ber_dec.h23
-rw-r--r--src/lib/pubkey/ec_group/ec_group.cpp6
-rw-r--r--src/lib/x509/asn1_alt_name.cpp48
-rw-r--r--src/lib/x509/name_constraint.cpp51
-rw-r--r--src/lib/x509/ocsp.cpp6
-rw-r--r--src/lib/x509/ocsp_types.cpp2
-rw-r--r--src/lib/x509/pkcs10.cpp17
-rw-r--r--src/lib/x509/x509_crl.cpp11
-rw-r--r--src/lib/x509/x509_ext.cpp31
-rw-r--r--src/lib/x509/x509cert.cpp24
-rw-r--r--src/lib/x509/x509cert.h7
-rw-r--r--src/tests/data/x509/bsi/expected.txt4
20 files changed, 258 insertions, 197 deletions
diff --git a/doc/manual/deprecated.rst b/doc/manual/deprecated.rst
index cb2a76d01..29a7b35fe 100644
--- a/doc/manual/deprecated.rst
+++ b/doc/manual/deprecated.rst
@@ -10,7 +10,7 @@ This is in addition to specific API calls marked with BOTAN_DEPRECATED
in the source.
- Directly accessing the member variables of types calendar_point, ASN1_Attribute,
- and AlgorithmIdentifier
+ AlgorithmIdentifier, and BER_Object
- The headers ``botan.h``, ``init.h``, ``lookup.h``
diff --git a/src/lib/asn1/asn1_obj.cpp b/src/lib/asn1/asn1_obj.cpp
index c83875ae5..bbe469f5c 100644
--- a/src/lib/asn1/asn1_obj.cpp
+++ b/src/lib/asn1/asn1_obj.cpp
@@ -12,6 +12,38 @@
namespace Botan {
+/*
+* Check a type invariant on BER data
+*/
+void BER_Object::assert_is_a(ASN1_Tag type_tag_, ASN1_Tag class_tag_,
+ const std::string& descr) const
+ {
+ if(this->is_a(type_tag_, class_tag_) == false)
+ {
+ throw BER_Decoding_Error("Tag mismatch when decoding " + descr + " got " +
+ std::to_string(type_tag) + "/" +
+ std::to_string(class_tag) + " expected " +
+ std::to_string(type_tag_) + "/" +
+ std::to_string(class_tag_));
+ }
+ }
+
+bool BER_Object::is_a(ASN1_Tag type_tag_, ASN1_Tag class_tag_) const
+ {
+ return (type_tag == type_tag_ && class_tag == class_tag_);
+ }
+
+bool BER_Object::is_a(int type_tag_, ASN1_Tag class_tag_) const
+ {
+ return is_a(ASN1_Tag(type_tag_), class_tag_);
+ }
+
+void BER_Object::set_tagging(ASN1_Tag t, ASN1_Tag c)
+ {
+ type_tag = t;
+ class_tag = c;
+ }
+
std::string asn1_tag_to_string(ASN1_Tag type)
{
switch(type)
@@ -95,9 +127,14 @@ namespace ASN1 {
*/
std::vector<uint8_t> put_in_sequence(const std::vector<uint8_t>& contents)
{
+ return ASN1::put_in_sequence(contents.data(), contents.size());
+ }
+
+std::vector<uint8_t> put_in_sequence(const uint8_t bits[], size_t len)
+ {
return DER_Encoder()
.start_cons(SEQUENCE)
- .raw_bytes(contents)
+ .raw_bytes(bits, len)
.end_cons()
.get_contents_unlocked();
}
@@ -107,7 +144,8 @@ std::vector<uint8_t> put_in_sequence(const std::vector<uint8_t>& contents)
*/
std::string to_string(const BER_Object& obj)
{
- return to_string(obj.value);
+ return std::string(cast_uint8_ptr_to_char(obj.bits()),
+ obj.length());
}
/*
diff --git a/src/lib/asn1/asn1_obj.h b/src/lib/asn1/asn1_obj.h
index 0b9a1493e..814b8f4f2 100644
--- a/src/lib/asn1/asn1_obj.h
+++ b/src/lib/asn1/asn1_obj.h
@@ -88,13 +88,46 @@ class BOTAN_PUBLIC_API(2,0) ASN1_Object
class BOTAN_PUBLIC_API(2,0) BER_Object final
{
public:
- void assert_is_a(ASN1_Tag type_tag, ASN1_Tag class_tag) const;
+ BER_Object() : type_tag(NO_OBJECT), class_tag(UNIVERSAL) {}
- // public member variable:
- ASN1_Tag type_tag, class_tag;
+ bool is_set() const { return type_tag != NO_OBJECT; }
+
+ ASN1_Tag tagging() const { return ASN1_Tag(type() | get_class()); }
+
+ ASN1_Tag type() const { return type_tag; }
+ ASN1_Tag get_class() const { return class_tag; }
+
+ const uint8_t* bits() const { return value.data(); }
+
+ size_t length() const { return value.size(); }
+
+ void assert_is_a(ASN1_Tag type_tag, ASN1_Tag class_tag,
+ const std::string& descr = "object") const;
+
+ bool is_a(ASN1_Tag type_tag, ASN1_Tag class_tag) const;
+
+ bool is_a(int type_tag, ASN1_Tag class_tag) const;
- // public member variable:
+ public:
+ /*
+ * The following member variables are public for historical reasons, but
+ * will be made private in a future major release. Use the accessor
+ * functions above.
+ */
+ ASN1_Tag type_tag, class_tag;
secure_vector<uint8_t> value;
+
+ private:
+
+ friend class BER_Decoder;
+
+ void set_tagging(ASN1_Tag type_tag, ASN1_Tag class_tag);
+
+ uint8_t* mutable_bits(size_t length)
+ {
+ value.resize(length);
+ return value.data();
+ }
};
/*
@@ -105,6 +138,7 @@ class DataSource;
namespace ASN1 {
std::vector<uint8_t> put_in_sequence(const std::vector<uint8_t>& val);
+std::vector<uint8_t> put_in_sequence(const uint8_t bits[], size_t len);
std::string to_string(const BER_Object& obj);
/**
diff --git a/src/lib/asn1/asn1_oid.cpp b/src/lib/asn1/asn1_oid.cpp
index 7c7161f47..2aa453c2b 100644
--- a/src/lib/asn1/asn1_oid.cpp
+++ b/src/lib/asn1/asn1_oid.cpp
@@ -161,31 +161,33 @@ void OID::encode_into(DER_Encoder& der) const
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");
+ if(obj.tagging() != OBJECT_ID)
+ throw BER_Bad_Tag("Error decoding OID, unknown tag", obj.tagging());
+
+ const size_t length = obj.length();
+ const uint8_t* bits = obj.bits();
+ if(length < 2)
+ throw BER_Decoding_Error("OID encoding is too short");
clear();
- m_id.push_back(obj.value[0] / 40);
- m_id.push_back(obj.value[0] % 40);
+ m_id.push_back(bits[0] / 40);
+ m_id.push_back(bits[0] % 40);
size_t i = 0;
- while(i != obj.value.size() - 1)
+ while(i != length - 1)
{
uint32_t component = 0;
- while(i != obj.value.size() - 1)
+ while(i != length - 1)
{
++i;
if(component >> (32-7))
throw Decoding_Error("OID component overflow");
- component = (component << 7) + (obj.value[i] & 0x7F);
+ component = (component << 7) + (bits[i] & 0x7F);
- if(!(obj.value[i] & 0x80))
+ if(!(bits[i] & 0x80))
break;
}
m_id.push_back(component);
diff --git a/src/lib/asn1/asn1_print.cpp b/src/lib/asn1/asn1_print.cpp
index f0d994dbd..13ae6d387 100644
--- a/src/lib/asn1/asn1_print.cpp
+++ b/src/lib/asn1/asn1_print.cpp
@@ -79,23 +79,23 @@ void ASN1_Formatter::decode(std::ostream& output,
const bool recurse_deeper = (m_max_depth == 0 || level < m_max_depth);
- while(obj.type_tag != NO_OBJECT)
+ while(obj.is_set())
{
- const ASN1_Tag type_tag = obj.type_tag;
- const ASN1_Tag class_tag = obj.class_tag;
- const size_t length = obj.value.size();
+ const ASN1_Tag type_tag = obj.type();
+ const ASN1_Tag class_tag = obj.get_class();
+ const size_t length = obj.length();
/* hack to insert the tag+length back in front of the stuff now
that we've gotten the type info */
DER_Encoder encoder;
- encoder.add_object(type_tag, class_tag, obj.value);
+ encoder.add_object(type_tag, class_tag, obj.bits(), obj.length());
const std::vector<uint8_t> bits = encoder.get_contents_unlocked();
BER_Decoder data(bits);
if(class_tag & CONSTRUCTED)
{
- BER_Decoder cons_info(obj.value);
+ BER_Decoder cons_info(obj.bits(), obj.length());
if(recurse_deeper)
{
diff --git a/src/lib/asn1/asn1_str.cpp b/src/lib/asn1/asn1_str.cpp
index 8b9524de2..416e4f0ac 100644
--- a/src/lib/asn1/asn1_str.cpp
+++ b/src/lib/asn1/asn1_str.cpp
@@ -130,10 +130,10 @@ void ASN1_String::decode_from(BER_Decoder& source)
{
BER_Object obj = source.get_next_object();
- assert_is_string_type(obj.type_tag);
+ assert_is_string_type(obj.type());
- m_tag = obj.type_tag;
- m_data.assign(obj.value.begin(), obj.value.end());
+ m_tag = obj.type();
+ m_data.assign(obj.bits(), obj.bits() + obj.length());
if(m_tag == BMP_STRING)
{
diff --git a/src/lib/asn1/asn1_time.cpp b/src/lib/asn1/asn1_time.cpp
index aca7fdca0..e64fd57c7 100644
--- a/src/lib/asn1/asn1_time.cpp
+++ b/src/lib/asn1/asn1_time.cpp
@@ -47,7 +47,7 @@ void X509_Time::decode_from(BER_Decoder& source)
{
BER_Object ber_time = source.get_next_object();
- set_to(ASN1::to_string(ber_time), ber_time.type_tag);
+ set_to(ASN1::to_string(ber_time), ber_time.type());
}
std::string X509_Time::to_string() const
diff --git a/src/lib/asn1/ber_dec.cpp b/src/lib/asn1/ber_dec.cpp
index 225197224..ca0056937 100644
--- a/src/lib/asn1/ber_dec.cpp
+++ b/src/lib/asn1/ber_dec.cpp
@@ -148,24 +148,11 @@ size_t find_eoc(DataSource* ber, size_t allow_indef)
}
/*
-* Check a type invariant on BER data
-*/
-void BER_Object::assert_is_a(ASN1_Tag type_tag_, ASN1_Tag class_tag_) const
- {
- if(type_tag != type_tag_ || class_tag != class_tag_)
- throw BER_Decoding_Error("Tag mismatch when decoding got " +
- std::to_string(type_tag) + "/" +
- std::to_string(class_tag) + " expected " +
- std::to_string(type_tag_) + "/" +
- std::to_string(class_tag_));
- }
-
-/*
* Check if more objects are there
*/
bool BER_Decoder::more_items() const
{
- if(m_source->end_of_data() && (m_pushed.type_tag == NO_OBJECT))
+ if(m_source->end_of_data() && !m_pushed.is_set())
return false;
return true;
}
@@ -175,7 +162,7 @@ bool BER_Decoder::more_items() const
*/
BER_Decoder& BER_Decoder::verify_end()
{
- if(!m_source->end_of_data() || (m_pushed.type_tag != NO_OBJECT))
+ if(!m_source->end_of_data() || m_pushed.is_set())
throw Invalid_State("BER_Decoder::verify_end called, but data remains");
return (*this);
}
@@ -198,17 +185,18 @@ BER_Object BER_Decoder::get_next_object()
{
BER_Object next;
- if(m_pushed.type_tag != NO_OBJECT)
+ if(m_pushed.is_set())
{
- next = m_pushed;
- m_pushed.class_tag = m_pushed.type_tag = NO_OBJECT;
+ std::swap(next, m_pushed);
return next;
}
for(;;)
{
- decode_tag(m_source, next.type_tag, next.class_tag);
- if(next.type_tag == NO_OBJECT)
+ ASN1_Tag type_tag, class_tag;
+ decode_tag(m_source, type_tag, class_tag);
+ next.set_tagging(type_tag, class_tag);
+ if(next.is_set() == false) // no more objects
return next;
size_t field_size;
@@ -216,11 +204,11 @@ BER_Object BER_Decoder::get_next_object()
if(!m_source->check_available(length))
throw BER_Decoding_Error("Value truncated");
- next.value.resize(length);
- if(m_source->read(next.value.data(), length) != length)
+ uint8_t* out = next.mutable_bits(length);
+ if(m_source->read(out, length) != length)
throw BER_Decoding_Error("Value truncated");
- if(next.type_tag == EOC && next.class_tag == UNIVERSAL)
+ if(next.tagging() == EOC)
continue;
else
break;
@@ -240,7 +228,7 @@ BER_Decoder& BER_Decoder::get_next(BER_Object& ber)
*/
void BER_Decoder::push_back(const BER_Object& obj)
{
- if(m_pushed.type_tag != NO_OBJECT)
+ if(m_pushed.is_set())
throw Invalid_State("BER_Decoder: Only one push back is allowed");
m_pushed = obj;
}
@@ -254,7 +242,7 @@ BER_Decoder BER_Decoder::start_cons(ASN1_Tag type_tag,
BER_Object obj = get_next_object();
obj.assert_is_a(type_tag, ASN1_Tag(class_tag | CONSTRUCTED));
- BER_Decoder result(obj.value.data(), obj.value.size());
+ BER_Decoder result(obj.bits(), obj.length());
result.m_parent = this;
return result;
}
@@ -271,14 +259,16 @@ BER_Decoder& BER_Decoder::end_cons()
return (*m_parent);
}
+BER_Decoder::BER_Decoder(const BER_Object& obj) : BER_Decoder(obj.bits(), obj.length())
+ {
+ }
+
/*
* BER_Decoder Constructor
*/
BER_Decoder::BER_Decoder(DataSource& src)
{
m_source = &src;
- m_pushed.type_tag = m_pushed.class_tag = NO_OBJECT;
- m_parent = nullptr;
}
/*
@@ -288,8 +278,6 @@ BER_Decoder::BER_Decoder(const uint8_t data[], size_t length)
{
m_data_src.reset(new DataSource_Memory(data, length));
m_source = m_data_src.get();
- m_pushed.type_tag = m_pushed.class_tag = NO_OBJECT;
- m_parent = nullptr;
}
/*
@@ -299,8 +287,6 @@ BER_Decoder::BER_Decoder(const secure_vector<uint8_t>& data)
{
m_data_src.reset(new DataSource_Memory(data));
m_source = m_data_src.get();
- m_pushed.type_tag = m_pushed.class_tag = NO_OBJECT;
- m_parent = nullptr;
}
/*
@@ -310,8 +296,6 @@ BER_Decoder::BER_Decoder(const std::vector<uint8_t>& data)
{
m_data_src.reset(new DataSource_Memory(data.data(), data.size()));
m_source = m_data_src.get();
- m_pushed.type_tag = m_pushed.class_tag = NO_OBJECT;
- m_parent = nullptr;
}
/*
@@ -323,7 +307,6 @@ BER_Decoder::BER_Decoder(const BER_Decoder& other)
// take ownership
std::swap(m_data_src, other.m_data_src);
- m_pushed.type_tag = m_pushed.class_tag = NO_OBJECT;
m_parent = other.m_parent;
}
@@ -344,7 +327,7 @@ BER_Decoder& BER_Decoder::decode_null()
{
BER_Object obj = get_next_object();
obj.assert_is_a(NULL_TAG, UNIVERSAL);
- if(obj.value.size())
+ if(obj.length() > 0)
throw BER_Decoding_Error("NULL object had nonzero size");
return (*this);
}
@@ -397,10 +380,10 @@ BER_Decoder& BER_Decoder::decode(bool& out,
BER_Object obj = get_next_object();
obj.assert_is_a(type_tag, class_tag);
- if(obj.value.size() != 1)
+ if(obj.length() != 1)
throw BER_Decoding_Error("BER boolean value had invalid size");
- out = (obj.value[0]) ? true : false;
+ out = (obj.bits()[0]) ? true : false;
return (*this);
}
@@ -457,25 +440,29 @@ BER_Decoder& BER_Decoder::decode(BigInt& out,
BER_Object obj = get_next_object();
obj.assert_is_a(type_tag, class_tag);
- if(obj.value.empty())
+ if(obj.length() == 0)
+ {
out = 0;
+ }
else
{
- const bool negative = (obj.value[0] & 0x80) ? true : false;
+ const bool negative = (obj.bits()[0] & 0x80) ? true : false;
if(negative)
{
- for(size_t i = obj.value.size(); i > 0; --i)
- if(obj.value[i-1]--)
+ secure_vector<uint8_t> vec(obj.bits(), obj.bits() + obj.length());
+ for(size_t i = obj.length(); i > 0; --i)
+ if(vec[i-1]--)
break;
- for(size_t i = 0; i != obj.value.size(); ++i)
- obj.value[i] = ~obj.value[i];
- }
-
- out = BigInt(&obj.value[0], obj.value.size());
-
- if(negative)
+ for(size_t i = 0; i != obj.length(); ++i)
+ vec[i] = ~vec[i];
+ out = BigInt(vec.data(), vec.size());
out.flip_sign();
+ }
+ else
+ {
+ out = BigInt(obj.bits(), obj.length());
+ }
}
return (*this);
@@ -494,19 +481,19 @@ void asn1_decode_binary_string(std::vector<uint8_t, Alloc>& buffer,
if(real_type == OCTET_STRING)
{
- buffer.assign(obj.value.begin(), obj.value.end());
+ buffer.assign(obj.bits(), obj.bits() + obj.length());
}
else
{
- if(obj.value.empty())
+ if(obj.length() == 0)
throw BER_Decoding_Error("Invalid BIT STRING");
- if(obj.value[0] >= 8)
+ if(obj.bits()[0] >= 8)
throw BER_Decoding_Error("Bad number of unused bits in BIT STRING");
- buffer.resize(obj.value.size() - 1);
+ buffer.resize(obj.length() - 1);
- if(obj.value.size() > 1)
- copy_mem(buffer.data(), &obj.value[1], obj.value.size() - 1);
+ if(obj.length() > 1)
+ copy_mem(buffer.data(), obj.bits() + 1, obj.length() - 1);
}
}
diff --git a/src/lib/asn1/ber_dec.h b/src/lib/asn1/ber_dec.h
index 637cdc527..ab2516175 100644
--- a/src/lib/asn1/ber_dec.h
+++ b/src/lib/asn1/ber_dec.h
@@ -54,14 +54,14 @@ class BOTAN_PUBLIC_API(2,0) BER_Decoder final
BER_Object obj = get_next_object();
obj.assert_is_a(type_tag, class_tag);
- if (obj.value.size() != sizeof(T))
+ if (obj.length() != sizeof(T))
throw BER_Decoding_Error(
"Size mismatch. Object value size is " +
- std::to_string(obj.value.size()) +
+ std::to_string(obj.length()) +
"; Output type size is " +
std::to_string(sizeof(T)));
- copy_mem(reinterpret_cast<uint8_t*>(&out), obj.value.data(), obj.value.size());
+ copy_mem(reinterpret_cast<uint8_t*>(&out), obj.bits(), obj.length());
return (*this);
}
@@ -185,10 +185,10 @@ class BOTAN_PUBLIC_API(2,0) BER_Decoder final
ASN1_Tag type_tag = static_cast<ASN1_Tag>(type_no);
- if(obj.type_tag == type_tag && obj.class_tag == class_tag)
+ if(obj.is_a(type_tag, class_tag))
{
if((class_tag & CONSTRUCTED) && (class_tag & CONTEXT_SPECIFIC))
- BER_Decoder(obj.value).decode(out, real_type).verify_end();
+ BER_Decoder(obj).decode(out, real_type).verify_end();
else
{
push_back(obj);
@@ -210,13 +210,15 @@ class BOTAN_PUBLIC_API(2,0) BER_Decoder final
BER_Decoder(const uint8_t[], size_t);
+ explicit BER_Decoder(const BER_Object& obj);
+
explicit BER_Decoder(const secure_vector<uint8_t>&);
explicit BER_Decoder(const std::vector<uint8_t>& vec);
BER_Decoder(const BER_Decoder&);
private:
- BER_Decoder* m_parent;
+ BER_Decoder* m_parent = nullptr;
BER_Object m_pushed;
// either m_data_src.get() or an unowned pointer
DataSource* m_source;
@@ -234,10 +236,10 @@ BER_Decoder& BER_Decoder::decode_optional(T& out,
{
BER_Object obj = get_next_object();
- if(obj.type_tag == type_tag && obj.class_tag == class_tag)
+ if(obj.is_a(type_tag, class_tag))
{
if((class_tag & CONSTRUCTED) && (class_tag & CONTEXT_SPECIFIC))
- BER_Decoder(obj.value).decode(out).verify_end();
+ BER_Decoder(obj).decode(out).verify_end();
else
{
push_back(obj);
@@ -267,10 +269,9 @@ BER_Decoder& BER_Decoder::decode_optional_implicit(
{
BER_Object obj = get_next_object();
- if(obj.type_tag == type_tag && obj.class_tag == class_tag)
+ if(obj.is_a(type_tag, class_tag))
{
- obj.type_tag = real_type;
- obj.class_tag = real_class;
+ obj.set_tagging(real_type, real_class);
push_back(obj);
decode(out, real_type, real_class);
}
diff --git a/src/lib/pubkey/ec_group/ec_group.cpp b/src/lib/pubkey/ec_group/ec_group.cpp
index 831c41e37..6ae8c16d8 100644
--- a/src/lib/pubkey/ec_group/ec_group.cpp
+++ b/src/lib/pubkey/ec_group/ec_group.cpp
@@ -52,15 +52,15 @@ EC_Group::EC_Group(const std::vector<uint8_t>& ber_data)
BER_Decoder ber(ber_data);
BER_Object obj = ber.get_next_object();
- if(obj.type_tag == NULL_TAG)
+ if(obj.type() == NULL_TAG)
throw Decoding_Error("Cannot handle ImplicitCA ECDSA parameters");
- else if(obj.type_tag == OBJECT_ID)
+ else if(obj.type() == OBJECT_ID)
{
OID dom_par_oid;
BER_Decoder(ber_data).decode(dom_par_oid);
*this = EC_Group(dom_par_oid);
}
- else if(obj.type_tag == SEQUENCE)
+ else if(obj.type() == SEQUENCE)
{
BigInt p, a, b;
std::vector<uint8_t> sv_base_point;
diff --git a/src/lib/x509/asn1_alt_name.cpp b/src/lib/x509/asn1_alt_name.cpp
index c9f7c780b..4e052ca58 100644
--- a/src/lib/x509/asn1_alt_name.cpp
+++ b/src/lib/x509/asn1_alt_name.cpp
@@ -179,18 +179,15 @@ void AlternativeName::decode_from(BER_Decoder& source)
{
BER_Decoder names = source.start_cons(SEQUENCE);
+ // FIXME this is largely a duplication of GeneralName::decode_from
+
while(names.more_items())
{
BER_Object obj = names.get_next_object();
- if((obj.class_tag != CONTEXT_SPECIFIC) &&
- (obj.class_tag != (CONTEXT_SPECIFIC | CONSTRUCTED)))
- continue;
-
- const ASN1_Tag tag = obj.type_tag;
- if(tag == 0)
+ if(obj.is_a(0, CONTEXT_SPECIFIC))
{
- BER_Decoder othername(obj.value);
+ BER_Decoder othername(obj);
OID oid;
othername.decode(oid);
@@ -199,34 +196,35 @@ void AlternativeName::decode_from(BER_Decoder& source)
BER_Object othername_value_outer = othername.get_next_object();
othername.verify_end();
- if(othername_value_outer.type_tag != ASN1_Tag(0) ||
- othername_value_outer.class_tag !=
- (CONTEXT_SPECIFIC | CONSTRUCTED)
- )
+ if(othername_value_outer.is_a(0, ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED)) == false)
throw Decoding_Error("Invalid tags on otherName value");
- BER_Decoder othername_value_inner(othername_value_outer.value);
+ BER_Decoder othername_value_inner(othername_value_outer);
BER_Object value = othername_value_inner.get_next_object();
othername_value_inner.verify_end();
- const ASN1_Tag value_type = value.type_tag;
-
- if(ASN1_String::is_string_type(value_type) && value.class_tag == UNIVERSAL)
+ if(ASN1_String::is_string_type(value.type()) && value.get_class() == UNIVERSAL)
{
- add_othername(oid, ASN1::to_string(value), value_type);
+ add_othername(oid, ASN1::to_string(value), value.type());
}
}
}
- else if(tag == 1 || tag == 2 || tag == 6)
+ if(obj.is_a(1, CONTEXT_SPECIFIC))
+ {
+ add_attribute("RFC822", ASN1::to_string(obj));
+ }
+ else if(obj.is_a(2, CONTEXT_SPECIFIC))
+ {
+ add_attribute("DNS", ASN1::to_string(obj));
+ }
+ else if(obj.is_a(6, CONTEXT_SPECIFIC))
{
- if(tag == 1) add_attribute("RFC822", ASN1::to_string(obj));
- if(tag == 2) add_attribute("DNS", ASN1::to_string(obj));
- if(tag == 6) add_attribute("URI", ASN1::to_string(obj));
+ add_attribute("URI", ASN1::to_string(obj));
}
- else if(tag == 4)
+ else if(obj.is_a(4, ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED)))
{
- BER_Decoder dec(obj.value);
+ BER_Decoder dec(obj);
X509_DN dn;
std::stringstream ss;
@@ -235,11 +233,11 @@ void AlternativeName::decode_from(BER_Decoder& source)
add_attribute("DN", ss.str());
}
- else if(tag == 7)
+ else if(obj.is_a(7, CONTEXT_SPECIFIC))
{
- if(obj.value.size() == 4)
+ if(obj.length() == 4)
{
- const uint32_t ip = load_be<uint32_t>(&obj.value[0], 0);
+ const uint32_t ip = load_be<uint32_t>(obj.bits(), 0);
add_attribute("IP", ipv4_to_string(ip));
}
}
diff --git a/src/lib/x509/name_constraint.cpp b/src/lib/x509/name_constraint.cpp
index 21145824b..888291557 100644
--- a/src/lib/x509/name_constraint.cpp
+++ b/src/lib/x509/name_constraint.cpp
@@ -41,58 +41,49 @@ void GeneralName::encode_into(DER_Encoder&) const
void GeneralName::decode_from(class BER_Decoder& ber)
{
BER_Object obj = ber.get_next_object();
- if((obj.class_tag != CONTEXT_SPECIFIC) &&
- (obj.class_tag != (CONTEXT_SPECIFIC | CONSTRUCTED)))
- throw Decoding_Error("Invalid class tag while decoding GeneralName");
- const ASN1_Tag tag = obj.type_tag;
-
- if(tag == 1 || tag == 2 || tag == 6)
+ if(obj.is_a(1, CONTEXT_SPECIFIC))
{
+ m_type = "RFC822";
m_name = ASN1::to_string(obj);
-
- if(tag == 1)
- {
- m_type = "RFC822";
- }
- else if(tag == 2)
- {
- m_type = "DNS";
- }
- else if(tag == 6)
- {
- m_type = "URI";
- }
}
- else if(tag == 4)
+ else if(obj.is_a(2, CONTEXT_SPECIFIC))
{
+ m_type = "DNS";
+ m_name = ASN1::to_string(obj);
+ }
+ else if(obj.is_a(6, CONTEXT_SPECIFIC))
+ {
+ m_type = "URI";
+ m_name = ASN1::to_string(obj);
+ }
+ else if(obj.is_a(4, ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED)))
+ {
+ m_type = "DN";
X509_DN dn;
- BER_Decoder dec(obj.value);
+ BER_Decoder dec(obj);
std::stringstream ss;
dn.decode_from(dec);
ss << dn;
m_name = ss.str();
- m_type = "DN";
}
- else if(tag == 7)
+ else if(obj.is_a(7, CONTEXT_SPECIFIC))
{
- if(obj.value.size() == 8)
+ if(obj.length() == 8)
{
- const std::vector<uint8_t> ip(obj.value.begin(), obj.value.begin() + 4);
- const std::vector<uint8_t> net(obj.value.begin() + 4, obj.value.end());
m_type = "IP";
- m_name = ipv4_to_string(load_be<uint32_t>(ip.data(), 0)) + "/" + ipv4_to_string(load_be<uint32_t>(net.data(), 0));
+ m_name = ipv4_to_string(load_be<uint32_t>(obj.bits(), 0)) + "/" +
+ ipv4_to_string(load_be<uint32_t>(obj.bits(), 1));
}
- else if(obj.value.size() == 32)
+ else if(obj.length() == 32)
{
throw Decoding_Error("Unsupported IPv6 name constraint");
}
else
{
- throw Decoding_Error("Invalid IP name constraint size " +
- std::to_string(obj.value.size()));
+ throw Decoding_Error("Invalid IP name constraint size " + std::to_string(obj.length()));
}
}
else
diff --git a/src/lib/x509/ocsp.cpp b/src/lib/x509/ocsp.cpp
index 5a98b7495..10449b019 100644
--- a/src/lib/x509/ocsp.cpp
+++ b/src/lib/x509/ocsp.cpp
@@ -32,18 +32,18 @@ void decode_optional_list(BER_Decoder& ber,
{
BER_Object obj = ber.get_next_object();
- if(obj.type_tag != tag || obj.class_tag != (CONTEXT_SPECIFIC | CONSTRUCTED))
+ if(obj.is_a(tag, ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED)) == false)
{
ber.push_back(obj);
return;
}
- BER_Decoder list(obj.value);
+ BER_Decoder list(obj);
while(list.more_items())
{
BER_Object certbits = list.get_next_object();
- X509_Certificate cert(unlock(certbits.value));
+ X509_Certificate cert(certbits.bits(), certbits.length());
output.push_back(std::move(cert));
}
}
diff --git a/src/lib/x509/ocsp_types.cpp b/src/lib/x509/ocsp_types.cpp
index 353cb100a..3eda5c05b 100644
--- a/src/lib/x509/ocsp_types.cpp
+++ b/src/lib/x509/ocsp_types.cpp
@@ -97,7 +97,7 @@ void SingleResponse::decode_from(class BER_Decoder& from)
ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED))
.end_cons();
- m_cert_status = cert_status.type_tag;
+ m_cert_status = cert_status.type();
}
}
diff --git a/src/lib/x509/pkcs10.cpp b/src/lib/x509/pkcs10.cpp
index b1543e398..78fea8dc6 100644
--- a/src/lib/x509/pkcs10.cpp
+++ b/src/lib/x509/pkcs10.cpp
@@ -72,20 +72,18 @@ std::unique_ptr<PKCS10_Data> decode_pkcs10(const std::vector<uint8_t>& body)
cert_req_info.decode(data->m_subject_dn);
BER_Object public_key = cert_req_info.get_next_object();
- if(public_key.type_tag != SEQUENCE || public_key.class_tag != CONSTRUCTED)
- throw BER_Bad_Tag("PKCS10_Request: Unexpected tag for public key",
- public_key.type_tag, public_key.class_tag);
+ if(public_key.is_a(SEQUENCE, CONSTRUCTED) == false)
+ throw BER_Bad_Tag("PKCS10_Request: Unexpected tag for public key", public_key.tagging());
- data->m_public_key_bits = ASN1::put_in_sequence(unlock(public_key.value));
+ data->m_public_key_bits = ASN1::put_in_sequence(public_key.bits(), public_key.length());
BER_Object attr_bits = cert_req_info.get_next_object();
std::set<std::string> pkcs9_email;
- if(attr_bits.type_tag == 0 &&
- attr_bits.class_tag == ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))
+ if(attr_bits.is_a(0, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)))
{
- BER_Decoder attributes(attr_bits.value);
+ BER_Decoder attributes(attr_bits);
while(attributes.more_items())
{
Attribute attr;
@@ -113,9 +111,8 @@ std::unique_ptr<PKCS10_Data> decode_pkcs10(const std::vector<uint8_t>& body)
}
attributes.verify_end();
}
- else if(attr_bits.type_tag != NO_OBJECT)
- throw BER_Bad_Tag("PKCS10_Request: Unexpected tag for attributes",
- attr_bits.type_tag, attr_bits.class_tag);
+ else if(attr_bits.is_set())
+ throw BER_Bad_Tag("PKCS10_Request: Unexpected tag for attributes", attr_bits.tagging());
cert_req_info.verify_end();
diff --git a/src/lib/x509/x509_crl.cpp b/src/lib/x509/x509_crl.cpp
index c6449baf8..da075e009 100644
--- a/src/lib/x509/x509_crl.cpp
+++ b/src/lib/x509/x509_crl.cpp
@@ -141,9 +141,9 @@ std::unique_ptr<CRL_Data> decode_crl_body(const std::vector<uint8_t>& body,
BER_Object next = tbs_crl.get_next_object();
- if(next.type_tag == SEQUENCE && next.class_tag == CONSTRUCTED)
+ if(next.is_a(SEQUENCE, CONSTRUCTED))
{
- BER_Decoder cert_list(next.value);
+ BER_Decoder cert_list(next);
while(cert_list.more_items())
{
@@ -154,15 +154,14 @@ std::unique_ptr<CRL_Data> decode_crl_body(const std::vector<uint8_t>& body,
next = tbs_crl.get_next_object();
}
- if(next.type_tag == 0 &&
- next.class_tag == ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))
+ if(next.is_a(0, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)))
{
- BER_Decoder crl_options(next.value);
+ BER_Decoder crl_options(next);
crl_options.decode(data->m_extensions).verify_end();
next = tbs_crl.get_next_object();
}
- if(next.type_tag != NO_OBJECT)
+ if(next.is_set())
throw X509_CRL::X509_CRL_Error("Unknown tag in CRL");
tbs_crl.verify_end();
diff --git a/src/lib/x509/x509_ext.cpp b/src/lib/x509/x509_ext.cpp
index c3b58236a..44c469c48 100644
--- a/src/lib/x509/x509_ext.cpp
+++ b/src/lib/x509/x509_ext.cpp
@@ -350,22 +350,27 @@ void Key_Usage::decode_inner(const std::vector<uint8_t>& in)
BER_Object obj = ber.get_next_object();
- if(obj.type_tag != BIT_STRING || obj.class_tag != UNIVERSAL)
- throw BER_Bad_Tag("Bad tag for usage constraint",
- obj.type_tag, obj.class_tag);
+ obj.assert_is_a(BIT_STRING, UNIVERSAL, "usage constraint");
- if(obj.value.size() != 2 && obj.value.size() != 3)
+ if(obj.length() != 2 && obj.length() != 3)
throw BER_Decoding_Error("Bad size for BITSTRING in usage constraint");
- if(obj.value[0] >= 8)
+ uint16_t usage = 0;
+
+ const uint8_t* bits = obj.bits();
+
+ if(bits[0] >= 8)
throw BER_Decoding_Error("Invalid unused bits in usage constraint");
- obj.value[obj.value.size()-1] &= (0xFF << obj.value[0]);
+ const uint8_t mask = static_cast<uint8_t>(0xFF << bits[0]);
- uint16_t usage = 0;
- for(size_t i = 1; i != obj.value.size(); ++i)
+ if(obj.length() == 2)
+ {
+ usage = make_uint16(bits[1] & mask, 0);
+ }
+ else if(obj.length() == 3)
{
- usage = (obj.value[i] << 8*(sizeof(usage)-i)) | usage;
+ usage = make_uint16(bits[1], bits[2] & mask);
}
m_constraints = Key_Constraints(usage);
@@ -545,7 +550,7 @@ void Name_Constraints::decode_inner(const std::vector<uint8_t>& in)
BER_Object per = ext.get_next_object();
ext.push_back(per);
- if(per.type_tag == 0 && per.class_tag == ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))
+ if(per.is_a(0, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)))
{
ext.decode_list(permit,ASN1_Tag(0),ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC));
if(permit.empty())
@@ -554,7 +559,7 @@ void Name_Constraints::decode_inner(const std::vector<uint8_t>& in)
BER_Object exc = ext.get_next_object();
ext.push_back(exc);
- if(per.type_tag == 1 && per.class_tag == ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))
+ if(per.is_a(1, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)))
{
ext.decode_list(exclude,ASN1_Tag(1),ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC));
if(exclude.empty())
@@ -771,7 +776,7 @@ void Authority_Information_Access::decode_inner(const std::vector<uint8_t>& in)
{
BER_Object name = info.get_next_object();
- if(name.type_tag == 6 && name.class_tag == CONTEXT_SPECIFIC)
+ if(name.is_a(6, CONTEXT_SPECIFIC))
{
m_ocsp_responder = ASN1::to_string(name);
}
@@ -781,7 +786,7 @@ void Authority_Information_Access::decode_inner(const std::vector<uint8_t>& in)
{
BER_Object name = info.get_next_object();
- if(name.type_tag == 6 && name.class_tag == CONTEXT_SPECIFIC)
+ if(name.is_a(6, CONTEXT_SPECIFIC))
{
m_ca_issuers.push_back(ASN1::to_string(name));
}
diff --git a/src/lib/x509/x509cert.cpp b/src/lib/x509/x509cert.cpp
index f298006c0..66921ed66 100644
--- a/src/lib/x509/x509cert.cpp
+++ b/src/lib/x509/x509cert.cpp
@@ -85,6 +85,12 @@ X509_Certificate::X509_Certificate(const std::vector<uint8_t>& vec)
load_data(src);
}
+X509_Certificate::X509_Certificate(const uint8_t data[], size_t len)
+ {
+ DataSource_Memory src(data, len);
+ load_data(src);
+ }
+
#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
X509_Certificate::X509_Certificate(const std::string& fsname)
{
@@ -128,13 +134,11 @@ std::unique_ptr<X509_Certificate_Data> parse_x509_cert_body(const X509_Object& o
data->m_issuer_dn_bits = ASN1::put_in_sequence(data->m_issuer_dn.get_bits());
BER_Object public_key = tbs_cert.get_next_object();
- if(public_key.type_tag != SEQUENCE || public_key.class_tag != CONSTRUCTED)
- throw BER_Bad_Tag("X509_Certificate: Unexpected tag for public key",
- public_key.type_tag, public_key.class_tag);
+ public_key.assert_is_a(SEQUENCE, CONSTRUCTED, "X.509 certificate public key");
// validate_public_key_params(public_key.value);
AlgorithmIdentifier public_key_alg_id;
- BER_Decoder(public_key.value).decode(public_key_alg_id).discard_remaining();
+ BER_Decoder(public_key).decode(public_key_alg_id).discard_remaining();
std::vector<std::string> public_key_info =
split_on(OIDS::oid2str(public_key_alg_id.get_oid()), '/');
@@ -180,7 +184,7 @@ std::unique_ptr<X509_Certificate_Data> parse_x509_cert_body(const X509_Object& o
}
}
- data->m_subject_public_key_bits = unlock(public_key.value);
+ data->m_subject_public_key_bits.assign(public_key.bits(), public_key.bits() + public_key.length());
BER_Decoder(data->m_subject_public_key_bits)
.decode(data->m_subject_public_key_algid)
@@ -190,14 +194,12 @@ std::unique_ptr<X509_Certificate_Data> parse_x509_cert_body(const X509_Object& o
tbs_cert.decode_optional_string(data->m_v2_subject_key_id, BIT_STRING, 2);
BER_Object v3_exts_data = tbs_cert.get_next_object();
- if(v3_exts_data.type_tag == 3 &&
- v3_exts_data.class_tag == ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))
+ if(v3_exts_data.is_a(3, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)))
{
- BER_Decoder(v3_exts_data.value).decode(data->m_v3_extensions).verify_end();
+ BER_Decoder(v3_exts_data).decode(data->m_v3_extensions).verify_end();
}
- else if(v3_exts_data.type_tag != NO_OBJECT)
- throw BER_Bad_Tag("Unknown tag in X.509 cert",
- v3_exts_data.type_tag, v3_exts_data.class_tag);
+ else if(v3_exts_data.is_set())
+ throw BER_Bad_Tag("Unknown tag in X.509 cert", v3_exts_data.tagging());
if(tbs_cert.more_items())
throw Decoding_Error("TBSCertificate has extra data after extensions block");
diff --git a/src/lib/x509/x509cert.h b/src/lib/x509/x509cert.h
index a1448637d..79d16d37f 100644
--- a/src/lib/x509/x509cert.h
+++ b/src/lib/x509/x509cert.h
@@ -408,6 +408,13 @@ class BOTAN_PUBLIC_API(2,0) X509_Certificate : public X509_Object
explicit X509_Certificate(const std::vector<uint8_t>& in);
/**
+ * Create a certificate from a buffer
+ * @param data the buffer containing the DER-encoded certificate
+ * @param length length of data in bytes
+ */
+ X509_Certificate(const uint8_t data[], size_t length);
+
+ /**
* Create an uninitialized certificate object. Any attempts to
* access this object will throw an exception.
*/
diff --git a/src/tests/data/x509/bsi/expected.txt b/src/tests/data/x509/bsi/expected.txt
index 6b609a201..fefb42bc5 100644
--- a/src/tests/data/x509/bsi/expected.txt
+++ b/src/tests/data/x509/bsi/expected.txt
@@ -28,7 +28,7 @@ cert_path_CRL_10$Certificate is revoked
cert_path_CRL_11$Certificate is revoked
cert_path_CRL_12$No revocation data
cert_path_CRL_13$No CRL with matching distribution point for certificate
-cert_path_CRL_14$Invalid argument Decoding error: X509 CRL decoding failed: Invalid argument Decoding error: BER: Tag mismatch when decoding got 65280/65280 expected 3/0
+cert_path_CRL_14$Invalid argument Decoding error: X509 CRL decoding failed: Invalid argument Decoding error: BER: Tag mismatch when decoding object got 65280/65280 expected 3/0
cert_path_CRL_15$No CRL with matching distribution point for certificate
cert_path_CRL_16$Certificate is revoked
cert_path_crypt_01$Signature error
@@ -42,7 +42,7 @@ cert_path_ext_06$CA certificate not allowed to issue certs
cert_path_ext_07$CA certificate not allowed to issue certs
cert_path_ext_08$Certificate chain too long
cert_path_ext_09$Verified
-cert_path_ext_10$Invalid argument Decoding error: CERTIFICATE decoding failed: Invalid argument Decoding error: Decoding X.509 extension 2.5.29.15 failed failed with exception Invalid argument Decoding error: BER: Bad tag for usage constraint: 16/32
+cert_path_ext_10$Invalid argument Decoding error: CERTIFICATE decoding failed: Invalid argument Decoding error: Decoding X.509 extension 2.5.29.15 failed failed with exception Invalid argument Decoding error: BER: Tag mismatch when decoding usage constraint got 16/32 expected 3/0
cert_path_ext_11$CA certificate not allowed to issue certs
cert_path_ext_12$Certificate contains duplicate policy
cert_path_ext_13$Unknown critical extension encountered