Repository: randombit/botan
Pull request #2584 (2021-01-11 01:29:48)

Split ASN1 tags enum class into 2 enum classes
This should improve type safety even more.


I did this fairly quickly without delving much into the code logic.

I changed the old `ASN1_Tag::PRIVATE` to `ASN1_Class::EXPLICIT_CONTEXT_SPECIFIC` as per #2581. Of course this is a placeholder name if you want to change it.
I replace all instaces of `PRIVATE` to the new name, HOWEVER I am not able to verify that those places used it with the correct meaning. I haven't read the relevant RFCs.

Disclaimer: My feelings won't be hurt if you don't want this PR.


Patch:
diff --git a/src/cli/pk_crypt.cpp b/src/cli/pk_crypt.cpp
index c30b17b48..bbcc93e49 100644
--- a/src/cli/pk_crypt.cpp
+++ b/src/cli/pk_crypt.cpp
@@ -91,10 +91,10 @@ class PK_Encrypt final : public Command
 
          der.start_sequence()
             .encode(pk_alg_id)
-            .encode(encrypted_key, Botan::ASN1_Tag::OCTET_STRING)
+            .encode(encrypted_key, Botan::ASN1_Type::OCTET_STRING)
             .encode(aead_oid)
-            .encode(nonce, Botan::ASN1_Tag::OCTET_STRING)
-            .encode(data, Botan::ASN1_Tag::OCTET_STRING)
+            .encode(nonce, Botan::ASN1_Type::OCTET_STRING)
+            .encode(data, Botan::ASN1_Type::OCTET_STRING)
             .end_cons();
 
          output() << Botan::PEM_Code::encode(buf, "PUBKEY ENCRYPTED MESSAGE", 72);
@@ -147,10 +147,10 @@ class PK_Decrypt final : public Command
             Botan::BER_Decoder(Botan::PEM_Code::decode_check_label(input, "PUBKEY ENCRYPTED MESSAGE"))
                .start_sequence()
                   .decode(pk_alg_id)
-                  .decode(encrypted_key, Botan::ASN1_Tag::OCTET_STRING)
+                  .decode(encrypted_key, Botan::ASN1_Type::OCTET_STRING)
                   .decode(aead_oid)
-                  .decode(nonce, Botan::ASN1_Tag::OCTET_STRING)
-                  .decode(data, Botan::ASN1_Tag::OCTET_STRING)
+                  .decode(nonce, Botan::ASN1_Type::OCTET_STRING)
+                  .decode(data, Botan::ASN1_Type::OCTET_STRING)
                .end_cons();
             }
          catch(Botan::Decoding_Error&)
diff --git a/src/fuzzer/asn1.cpp b/src/fuzzer/asn1.cpp
index 89073991d..c3fffb15c 100644
--- a/src/fuzzer/asn1.cpp
+++ b/src/fuzzer/asn1.cpp
@@ -14,13 +14,13 @@ class ASN1_Parser final : public Botan::ASN1_Formatter
       ASN1_Parser() : Botan::ASN1_Formatter(true, 64) {}
 
    protected:
-      std::string format(Botan::ASN1_Tag, Botan::ASN1_Tag, size_t, size_t,
+      std::string format(Botan::ASN1_Type, Botan::ASN1_Class, size_t, size_t,
                          const std::string&) const override
          {
          return "";
          }
 
-      std::string format_bin(Botan::ASN1_Tag, Botan::ASN1_Tag,
+      std::string format_bin(Botan::ASN1_Type, Botan::ASN1_Class,
                              const std::vector<uint8_t>&) const override
          {
          return "";
diff --git a/src/lib/asn1/asn1_obj.cpp b/src/lib/asn1/asn1_obj.cpp
index 4a471ba50..9b4c9760e 100644
--- a/src/lib/asn1/asn1_obj.cpp
+++ b/src/lib/asn1/asn1_obj.cpp
@@ -24,7 +24,7 @@ std::vector<uint8_t> ASN1_Object::BER_encode() const
 /*
 * Check a type invariant on BER data
 */
-void BER_Object::assert_is_a(ASN1_Tag expected_type_tag, ASN1_Tag expected_class_tag,
+void BER_Object::assert_is_a(ASN1_Type expected_type_tag, ASN1_Class expected_class_tag,
                              const std::string& descr) const
    {
    if(this->is_a(expected_type_tag, expected_class_tag) == false)
@@ -33,13 +33,13 @@ void BER_Object::assert_is_a(ASN1_Tag expected_type_tag, ASN1_Tag expected_class
 
       msg << "Tag mismatch when decoding " << descr << " got ";
 
-      if(m_class_tag == ASN1_Tag::NO_OBJECT && m_type_tag == ASN1_Tag::NO_OBJECT)
+      if(m_class_tag == ASN1_Class::NO_OBJECT && m_type_tag == ASN1_Type::NO_OBJECT)
          {
          msg << "EOF";
          }
       else
          {
-         if(m_class_tag == ASN1_Tag::UNIVERSAL || m_class_tag == ASN1_Tag::CONSTRUCTED)
+         if(m_class_tag == ASN1_Class::UNIVERSAL || m_class_tag == ASN1_Class::CONSTRUCTED)
             {
             msg << asn1_tag_to_string(m_type_tag);
             }
@@ -53,7 +53,7 @@ void BER_Object::assert_is_a(ASN1_Tag expected_type_tag, ASN1_Tag expected_class
 
       msg << " expected ";
 
-      if(expected_class_tag == ASN1_Tag::UNIVERSAL || expected_class_tag == ASN1_Tag::CONSTRUCTED)
+      if(expected_class_tag == ASN1_Class::UNIVERSAL || expected_class_tag == ASN1_Class::CONSTRUCTED)
          {
          msg << asn1_tag_to_string(expected_type_tag);
          }
@@ -68,105 +68,105 @@ void BER_Object::assert_is_a(ASN1_Tag expected_type_tag, ASN1_Tag expected_class
       }
    }
 
-bool BER_Object::is_a(ASN1_Tag expected_type_tag, ASN1_Tag expected_class_tag) const
+bool BER_Object::is_a(ASN1_Type expected_type_tag, ASN1_Class expected_class_tag) const
    {
    return (m_type_tag == expected_type_tag && m_class_tag == expected_class_tag);
    }
 
-bool BER_Object::is_a(int expected_type_tag, ASN1_Tag expected_class_tag) const
+bool BER_Object::is_a(int expected_type_tag, ASN1_Class expected_class_tag) const
    {
-   return is_a(ASN1_Tag(expected_type_tag), expected_class_tag);
+   return is_a(ASN1_Type(expected_type_tag), expected_class_tag);
    }
 
-void BER_Object::set_tagging(ASN1_Tag type_tag, ASN1_Tag class_tag)
+void BER_Object::set_tagging(ASN1_Type type_tag, ASN1_Class class_tag)
    {
    m_type_tag = type_tag;
    m_class_tag = class_tag;
    }
 
-std::string asn1_class_to_string(ASN1_Tag type)
+std::string asn1_class_to_string(ASN1_Class type)
    {
    switch(type)
       {
-      case ASN1_Tag::UNIVERSAL:
+      case ASN1_Class::UNIVERSAL:
          return "UNIVERSAL";
-      case ASN1_Tag::CONSTRUCTED:
+      case ASN1_Class::CONSTRUCTED:
          return "CONSTRUCTED";
-      case ASN1_Tag::CONTEXT_SPECIFIC:
+      case ASN1_Class::CONTEXT_SPECIFIC:
          return "CONTEXT_SPECIFIC";
-      case ASN1_Tag::APPLICATION:
+      case ASN1_Class::APPLICATION:
          return "APPLICATION";
-      case ASN1_Tag::PRIVATE:
+      case ASN1_Class::PRIVATE:
          return "PRIVATE";
-      case ASN1_Tag::NO_OBJECT:
+      case ASN1_Class::NO_OBJECT:
          return "NO_OBJECT";
       default:
          return "CLASS(" + std::to_string(static_cast<size_t>(type)) + ")";
       }
    }
 
-std::string asn1_tag_to_string(ASN1_Tag type)
+std::string asn1_tag_to_string(ASN1_Type type)
    {
    switch(type)
       {
-      case ASN1_Tag::SEQUENCE:
+      case ASN1_Type::SEQUENCE:
          return "SEQUENCE";
 
-      case ASN1_Tag::SET:
+      case ASN1_Type::SET:
          return "SET";
 
-      case ASN1_Tag::PRINTABLE_STRING:
+      case ASN1_Type::PRINTABLE_STRING:
          return "PRINTABLE STRING";
 
-      case ASN1_Tag::NUMERIC_STRING:
+      case ASN1_Type::NUMERIC_STRING:
          return "NUMERIC STRING";
 
-      case ASN1_Tag::IA5_STRING:
+      case ASN1_Type::IA5_STRING:
          return "IA5 STRING";
 
-      case ASN1_Tag::T61_STRING:
+      case ASN1_Type::T61_STRING:
          return "T61 STRING";
 
-      case ASN1_Tag::UTF8_STRING:
+      case ASN1_Type::UTF8_STRING:
          return "UTF8 STRING";
 
-      case ASN1_Tag::VISIBLE_STRING:
+      case ASN1_Type::VISIBLE_STRING:
          return "VISIBLE STRING";
 
-      case ASN1_Tag::BMP_STRING:
+      case ASN1_Type::BMP_STRING:
          return "BMP STRING";
 
-      case ASN1_Tag::UNIVERSAL_STRING:
+      case ASN1_Type::UNIVERSAL_STRING:
          return "UNIVERSAL STRING";
 
-      case ASN1_Tag::UTC_TIME:
+      case ASN1_Type::UTC_TIME:
          return "UTC TIME";
 
-      case ASN1_Tag::GENERALIZED_TIME:
+      case ASN1_Type::GENERALIZED_TIME:
          return "GENERALIZED TIME";
 
-      case ASN1_Tag::OCTET_STRING:
+      case ASN1_Type::OCTET_STRING:
          return "OCTET STRING";
 
-      case ASN1_Tag::BIT_STRING:
+      case ASN1_Type::BIT_STRING:
          return "BIT STRING";
 
-      case ASN1_Tag::ENUMERATED:
+      case ASN1_Type::ENUMERATED:
          return "ENUMERATED";
 
-      case ASN1_Tag::INTEGER:
+      case ASN1_Type::INTEGER:
          return "INTEGER";
 
-      case ASN1_Tag::NULL_TAG:
+      case ASN1_Type::NULL_TAG:
          return "NULL";
 
-      case ASN1_Tag::OBJECT_ID:
+      case ASN1_Type::OBJECT_ID:
          return "OBJECT";
 
-      case ASN1_Tag::BOOLEAN:
+      case ASN1_Type::BOOLEAN:
          return "BOOLEAN";
 
-      case ASN1_Tag::NO_OBJECT:
+      case ASN1_Type::NO_OBJECT:
          return "NO_OBJECT";
 
       default:
@@ -180,14 +180,8 @@ std::string asn1_tag_to_string(ASN1_Tag type)
 BER_Decoding_Error::BER_Decoding_Error(const std::string& str) :
    Decoding_Error("BER: " + str) {}
 
-BER_Bad_Tag::BER_Bad_Tag(const std::string& str, ASN1_Tag tag) :
-   BER_Decoding_Error(str + ": " + std::to_string(static_cast<uint32_t>(tag))) {}
-
-BER_Bad_Tag::BER_Bad_Tag(const std::string& str,
-                         ASN1_Tag tag1, ASN1_Tag tag2) :
-   BER_Decoding_Error(str + ": " +
-                      std::to_string(static_cast<uint32_t>(tag1)) + "/" +
-                      std::to_string(static_cast<uint32_t>(tag2))) {}
+BER_Bad_Tag::BER_Bad_Tag(const std::string& str, uint32_t tagging) :
+   BER_Decoding_Error(str + ": " + std::to_string(tagging)) {}
 
 namespace ASN1 {
 
@@ -230,8 +224,8 @@ bool maybe_BER(DataSource& source)
       throw Stream_IO_Error("ASN1::maybe_BER: Source was empty");
       }
 
-   const auto cons_seq = ASN1_Tag::CONSTRUCTED | ASN1_Tag::SEQUENCE;
-   if(first_u8 == static_cast<uint8_t>(cons_seq))
+   const auto cons_seq = static_cast<uint8_t>(ASN1_Class::CONSTRUCTED) | static_cast<uint8_t>(ASN1_Type::SEQUENCE);
+   if(first_u8 == cons_seq)
       return true;
    return false;
    }
diff --git a/src/lib/asn1/asn1_obj.h b/src/lib/asn1/asn1_obj.h
index 1538bd196..e64363d34 100644
--- a/src/lib/asn1/asn1_obj.h
+++ b/src/lib/asn1/asn1_obj.h
@@ -19,17 +19,24 @@ class BER_Decoder;
 class DER_Encoder;
 
 /**
-* ASN.1 Type and Class Tags
+* ASN.1 Class Tags
 */
-enum class ASN1_Tag : uint32_t {
-   UNIVERSAL        = 0x00,
-   APPLICATION      = 0x40,
-   CONTEXT_SPECIFIC = 0x80,
+enum class ASN1_Class : uint32_t {
+    UNIVERSAL        = 0b0000'0000,
+    APPLICATION      = 0b0100'0000,
+    CONTEXT_SPECIFIC = 0b1000'0000,
+    PRIVATE          = 0b1100'0000,
 
-   CONSTRUCTED      = 0x20,
+    CONSTRUCTED      = 0b0010'0000,
+    EXPLICIT_CONTEXT_SPECIFIC = CONSTRUCTED | CONTEXT_SPECIFIC,
 
-   PRIVATE          = CONSTRUCTED | CONTEXT_SPECIFIC,
+    NO_OBJECT        = 0xFF00
+};
 
+/**
+* ASN.1 Type Tags
+*/
+enum class ASN1_Type : uint32_t {
    EOC              = 0x00,
    BOOLEAN          = 0x01,
    INTEGER          = 0x02,
@@ -58,18 +65,33 @@ enum class ASN1_Tag : uint32_t {
    DIRECTORY_STRING = 0xFF01
 };
 
-inline bool intersects(ASN1_Tag x, ASN1_Tag y)
+inline bool intersects(ASN1_Class x, ASN1_Class y)
    {
    return static_cast<uint32_t>(x) & static_cast<uint32_t>(y);
    }
 
-inline ASN1_Tag operator|(ASN1_Tag x, ASN1_Tag y)
+inline ASN1_Type operator|(ASN1_Type x, ASN1_Type y)
+   {
+   return static_cast<ASN1_Type>(static_cast<uint32_t>(x) | static_cast<uint32_t>(y));
+   }
+
+inline ASN1_Class operator|(ASN1_Class x, ASN1_Class y)
+   {
+   return static_cast<ASN1_Class>(static_cast<uint32_t>(x) | static_cast<uint32_t>(y));
+   }
+
+inline uint32_t operator|(ASN1_Type x, ASN1_Class y)
+   {
+   return static_cast<uint32_t>(x) | static_cast<uint32_t>(y);
+   }
+
+inline uint32_t operator|(ASN1_Class x, ASN1_Type y)
    {
-   return static_cast<ASN1_Tag>(static_cast<uint32_t>(x) | static_cast<uint32_t>(y));
+    return static_cast<uint32_t>(x) | static_cast<uint32_t>(y);
    }
 
-std::string BOTAN_UNSTABLE_API asn1_tag_to_string(ASN1_Tag type);
-std::string BOTAN_UNSTABLE_API asn1_class_to_string(ASN1_Tag type);
+std::string BOTAN_UNSTABLE_API asn1_tag_to_string(ASN1_Type type);
+std::string BOTAN_UNSTABLE_API asn1_class_to_string(ASN1_Class type);
 
 /**
 * Basic ASN.1 Object Interface
@@ -108,7 +130,7 @@ class BOTAN_PUBLIC_API(2,0) ASN1_Object
 class BOTAN_PUBLIC_API(2,0) BER_Object final
    {
    public:
-      BER_Object() : m_type_tag(ASN1_Tag::NO_OBJECT), m_class_tag(ASN1_Tag::UNIVERSAL) {}
+      BER_Object() : m_type_tag(ASN1_Type::NO_OBJECT), m_class_tag(ASN1_Class::UNIVERSAL) {}
 
       BER_Object(const BER_Object& other) = default;
 
@@ -118,34 +140,35 @@ class BOTAN_PUBLIC_API(2,0) BER_Object final
 
       BER_Object& operator=(BER_Object&& other) = default;
 
-      bool is_set() const { return m_type_tag != ASN1_Tag::NO_OBJECT; }
+      bool is_set() const { return m_type_tag != ASN1_Type::NO_OBJECT; }
 
-      ASN1_Tag tagging() const { return type_tag() | class_tag(); }
+      uint32_t tagging() const { return type_tag() | class_tag(); }
 
-      ASN1_Tag type_tag() const { return m_type_tag; }
-      ASN1_Tag class_tag() const { return m_class_tag; }
+      ASN1_Type type_tag() const { return m_type_tag; }
+      ASN1_Class class_tag() const { return m_class_tag; }
 
-      ASN1_Tag type() const { return m_type_tag; }
-      ASN1_Tag get_class() const { return m_class_tag; }
+      ASN1_Type type() const { return m_type_tag; }
+      ASN1_Class get_class() const { return m_class_tag; }
 
       const uint8_t* bits() const { return m_value.data(); }
 
       size_t length() const { return m_value.size(); }
 
-      void assert_is_a(ASN1_Tag type_tag, ASN1_Tag class_tag,
+      void assert_is_a(ASN1_Type type_tag, ASN1_Class class_tag,
                        const std::string& descr = "object") const;
 
-      bool is_a(ASN1_Tag type_tag, ASN1_Tag class_tag) const;
+      bool is_a(ASN1_Type type_tag, ASN1_Class class_tag) const;
 
-      bool is_a(int type_tag, ASN1_Tag class_tag) const;
+      bool is_a(int type_tag, ASN1_Class class_tag) const;
 
    private:
-      ASN1_Tag m_type_tag, m_class_tag;
+       ASN1_Type m_type_tag;
+       ASN1_Class m_class_tag;
       secure_vector<uint8_t> m_value;
 
       friend class BER_Decoder;
 
-      void set_tagging(ASN1_Tag type_tag, ASN1_Tag class_tag);
+      void set_tagging(ASN1_Type type_tag, ASN1_Class class_tag);
 
       uint8_t* mutable_bits(size_t length)
          {
@@ -188,8 +211,7 @@ class BOTAN_PUBLIC_API(2,0) BER_Decoding_Error : public Decoding_Error
 class BOTAN_PUBLIC_API(2,0) BER_Bad_Tag final : public BER_Decoding_Error
    {
    public:
-      BER_Bad_Tag(const std::string& msg, ASN1_Tag tag);
-      BER_Bad_Tag(const std::string& msg, ASN1_Tag tag1, ASN1_Tag tag2);
+      BER_Bad_Tag(const std::string& msg, uint32_t tagging);
    };
 
 /**
@@ -332,7 +354,7 @@ class BOTAN_PUBLIC_API(2,0) ASN1_Time final : public ASN1_Object
       explicit ASN1_Time(const std::chrono::system_clock::time_point& time);
 
       /// Create an ASN1_Time from string
-      ASN1_Time(const std::string& t_spec, ASN1_Tag tag);
+      ASN1_Time(const std::string& t_spec, ASN1_Type tag);
 
       /// Returns a STL timepoint object
       std::chrono::system_clock::time_point to_std_timepoint() const;
@@ -341,7 +363,7 @@ class BOTAN_PUBLIC_API(2,0) ASN1_Time final : public ASN1_Object
       uint64_t time_since_epoch() const;
 
    private:
-      void set_to(const std::string& t_spec, ASN1_Tag);
+      void set_to(const std::string& t_spec, ASN1_Type);
       bool passes_sanity_check() const;
 
       uint32_t m_year = 0;
@@ -350,7 +372,7 @@ class BOTAN_PUBLIC_API(2,0) ASN1_Time final : public ASN1_Object
       uint32_t m_hour = 0;
       uint32_t m_minute = 0;
       uint32_t m_second = 0;
-      ASN1_Tag m_tag = ASN1_Tag::NO_OBJECT;
+      ASN1_Type m_tag = ASN1_Type::NO_OBJECT;
    };
 
 /*
@@ -375,7 +397,7 @@ class BOTAN_PUBLIC_API(2,0) ASN1_String final : public ASN1_Object
       void encode_into(class DER_Encoder&) const override;
       void decode_from(class BER_Decoder&) override;
 
-      ASN1_Tag tagging() const { return m_tag; }
+      ASN1_Type tagging() const { return m_tag; }
 
       const std::string& value() const { return m_utf8_str; }
 
@@ -387,17 +409,17 @@ class BOTAN_PUBLIC_API(2,0) ASN1_String final : public ASN1_Object
       * Return true iff this is a tag for a known string type we can handle.
       * This ignores string types that are not supported, eg teletexString
       */
-      static bool is_string_type(ASN1_Tag tag);
+      static bool is_string_type(ASN1_Type tag);
 
       bool operator==(const ASN1_String& other) const
          { return value() == other.value(); }
 
       explicit ASN1_String(const std::string& utf8 = "");
-      ASN1_String(const std::string& utf8, ASN1_Tag tag);
+      ASN1_String(const std::string& utf8, ASN1_Type tag);
    private:
       std::vector<uint8_t> m_data;
       std::string m_utf8_str;
-      ASN1_Tag m_tag;
+      ASN1_Type m_tag;
    };
 
 /**
diff --git a/src/lib/asn1/asn1_oid.cpp b/src/lib/asn1/asn1_oid.cpp
index 2839166da..5d18f53f4 100644
--- a/src/lib/asn1/asn1_oid.cpp
+++ b/src/lib/asn1/asn1_oid.cpp
@@ -168,7 +168,7 @@ void OID::encode_into(DER_Encoder& der) const
          encoding.push_back(m_id[i] & 0x7F);
          }
       }
-   der.add_object(ASN1_Tag::OBJECT_ID, ASN1_Tag::UNIVERSAL, encoding);
+   der.add_object(ASN1_Type::OBJECT_ID, ASN1_Class::UNIVERSAL, encoding);
    }
 
 /*
@@ -177,8 +177,8 @@ void OID::encode_into(DER_Encoder& der) const
 void OID::decode_from(BER_Decoder& decoder)
    {
    BER_Object obj = decoder.get_next_object();
-   if(obj.tagging() != ASN1_Tag::OBJECT_ID)
-      throw BER_Bad_Tag("Error decoding OID, unknown tag", obj.tagging());
+   if(obj.tagging() != (ASN1_Class::UNIVERSAL | ASN1_Type::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();
diff --git a/src/lib/asn1/asn1_print.cpp b/src/lib/asn1/asn1_print.cpp
index 5468f8bdd..0c1401ec6 100644
--- a/src/lib/asn1/asn1_print.cpp
+++ b/src/lib/asn1/asn1_print.cpp
@@ -79,8 +79,8 @@ void ASN1_Formatter::decode(std::ostream& output,
 
    while(obj.is_set())
       {
-      const ASN1_Tag type_tag = obj.type();
-      const ASN1_Tag class_tag = obj.get_class();
+      const ASN1_Type type_tag = obj.type();
+      const ASN1_Class class_tag = obj.get_class();
       const size_t length = obj.length();
 
       /* hack to insert the tag+length back in front of the stuff now
@@ -90,7 +90,7 @@ void ASN1_Formatter::decode(std::ostream& output,
 
       BER_Decoder data(bits);
 
-      if(intersects(class_tag, ASN1_Tag::CONSTRUCTED))
+      if(intersects(class_tag, ASN1_Class::CONSTRUCTED))
          {
          BER_Decoder cons_info(obj.bits(), obj.length());
 
@@ -105,7 +105,7 @@ void ASN1_Formatter::decode(std::ostream& output,
                              format_bin(type_tag, class_tag, bits));
             }
          }
-      else if(intersects(class_tag, ASN1_Tag::APPLICATION) || intersects(class_tag, ASN1_Tag::CONTEXT_SPECIFIC))
+      else if(intersects(class_tag, ASN1_Class::APPLICATION) || intersects(class_tag, ASN1_Class::CONTEXT_SPECIFIC))
          {
          bool success_parsing_cs = false;
 
@@ -142,7 +142,7 @@ void ASN1_Formatter::decode(std::ostream& output,
                              format_bin(type_tag, class_tag, bits));
             }
          }
-      else if(type_tag == ASN1_Tag::OBJECT_ID)
+      else if(type_tag == ASN1_Type::OBJECT_ID)
          {
          OID oid;
          data.decode(oid);
@@ -159,17 +159,17 @@ void ASN1_Formatter::decode(std::ostream& output,
 
          output << format(type_tag, class_tag, level, length, out);
          }
-      else if(type_tag == ASN1_Tag::INTEGER || type_tag == ASN1_Tag::ENUMERATED)
+      else if(type_tag == ASN1_Type::INTEGER || type_tag == ASN1_Type::ENUMERATED)
          {
          BigInt number;
 
-         if(type_tag == ASN1_Tag::INTEGER)
+         if(type_tag == ASN1_Type::INTEGER)
             {
             data.decode(number);
             }
-         else if(type_tag == ASN1_Tag::ENUMERATED)
+         else if(type_tag == ASN1_Type::ENUMERATED)
             {
-            data.decode(number, ASN1_Tag::ENUMERATED, class_tag);
+            data.decode(number, ASN1_Type::ENUMERATED, class_tag);
             }
 
          std::vector<uint8_t> rep = BigInt::encode(number);
@@ -178,17 +178,17 @@ void ASN1_Formatter::decode(std::ostream& output,
 
          output << format(type_tag, class_tag, level, length, hex_encode(rep));
          }
-      else if(type_tag == ASN1_Tag::BOOLEAN)
+      else if(type_tag == ASN1_Type::BOOLEAN)
          {
          bool boolean;
          data.decode(boolean);
          output << format(type_tag, class_tag, level, length, (boolean ? "true" : "false"));
          }
-      else if(type_tag == ASN1_Tag::NULL_TAG)
+      else if(type_tag == ASN1_Type::NULL_TAG)
          {
          output << format(type_tag, class_tag, level, length, "");
          }
-      else if(type_tag == ASN1_Tag::OCTET_STRING || type_tag == ASN1_Tag::BIT_STRING)
+      else if(type_tag == ASN1_Type::OCTET_STRING || type_tag == ASN1_Type::BIT_STRING)
          {
          std::vector<uint8_t> decoded_bits;
          data.decode(decoded_bits, type_tag);
@@ -224,7 +224,7 @@ void ASN1_Formatter::decode(std::ostream& output,
          data.decode(str);
          output << format(type_tag, class_tag, level, length, str.value());
          }
-      else if(type_tag == ASN1_Tag::UTC_TIME || type_tag == ASN1_Tag::GENERALIZED_TIME)
+      else if(type_tag == ASN1_Type::UTC_TIME || type_tag == ASN1_Type::GENERALIZED_TIME)
          {
          ASN1_Time time;
          data.decode(time);
@@ -242,26 +242,26 @@ void ASN1_Formatter::decode(std::ostream& output,
 
 namespace {
 
-std::string format_type(ASN1_Tag type_tag, ASN1_Tag class_tag)
+std::string format_type(ASN1_Type type_tag, ASN1_Class class_tag)
    {
-   if(class_tag == ASN1_Tag::UNIVERSAL)
+   if(class_tag == ASN1_Class::UNIVERSAL)
       return asn1_tag_to_string(type_tag);
 
-   if(class_tag == ASN1_Tag::CONSTRUCTED && (type_tag == ASN1_Tag::SEQUENCE || type_tag == ASN1_Tag::SET))
+   if(class_tag == ASN1_Class::CONSTRUCTED && (type_tag == ASN1_Type::SEQUENCE || type_tag == ASN1_Type::SET))
       return asn1_tag_to_string(type_tag);
 
    std::string name;
 
-   if(intersects(class_tag, ASN1_Tag::CONSTRUCTED))
+   if(intersects(class_tag, ASN1_Class::CONSTRUCTED))
       name += "cons ";
 
    name += "[" + std::to_string(static_cast<uint32_t>(type_tag)) + "]";
 
-   if(intersects(class_tag, ASN1_Tag::APPLICATION))
+   if(intersects(class_tag, ASN1_Class::APPLICATION))
       {
       name += " appl";
       }
-   if(intersects(class_tag, ASN1_Tag::CONTEXT_SPECIFIC))
+   if(intersects(class_tag, ASN1_Class::CONTEXT_SPECIFIC))
       {
       name += " context";
       }
@@ -271,8 +271,8 @@ std::string format_type(ASN1_Tag type_tag, ASN1_Tag class_tag)
 
 }
 
-std::string ASN1_Pretty_Printer::format(ASN1_Tag type_tag,
-                                        ASN1_Tag class_tag,
+std::string ASN1_Pretty_Printer::format(ASN1_Type type_tag,
+                                        ASN1_Class class_tag,
                                         size_t level,
                                         size_t length,
                                         const std::string& value) const
@@ -284,7 +284,7 @@ std::string ASN1_Pretty_Printer::format(ASN1_Tag type_tag,
       should_skip = true;
       }
 
-   if((type_tag == ASN1_Tag::OCTET_STRING || type_tag == ASN1_Tag::BIT_STRING) &&
+   if((type_tag == ASN1_Type::OCTET_STRING || type_tag == ASN1_Type::BIT_STRING) &&
       value.length() > m_print_binary_limit)
       {
       should_skip = true;
@@ -312,8 +312,8 @@ std::string ASN1_Pretty_Printer::format(ASN1_Tag type_tag,
    return oss.str();
    }
 
-std::string ASN1_Pretty_Printer::format_bin(ASN1_Tag /*type_tag*/,
-                                            ASN1_Tag /*class_tag*/,
+std::string ASN1_Pretty_Printer::format_bin(ASN1_Type /*type_tag*/,
+                                            ASN1_Class /*class_tag*/,
                                             const std::vector<uint8_t>& vec) const
    {
    if(all_printable_chars(vec.data(), vec.size()))
diff --git a/src/lib/asn1/asn1_print.h b/src/lib/asn1/asn1_print.h
index a6bc6b15f..53ed42de6 100644
--- a/src/lib/asn1/asn1_print.h
+++ b/src/lib/asn1/asn1_print.h
@@ -50,8 +50,8 @@ class BOTAN_PUBLIC_API(2,4) ASN1_Formatter
       /**
       * This is called for each element
       */
-      virtual std::string format(ASN1_Tag type_tag,
-                                 ASN1_Tag class_tag,
+      virtual std::string format(ASN1_Type type_tag,
+                                 ASN1_Class class_tag,
                                  size_t level,
                                  size_t length,
                                  const std::string& value) const = 0;
@@ -61,8 +61,8 @@ class BOTAN_PUBLIC_API(2,4) ASN1_Formatter
       * convert to a string The result will be passed as value to format; the
       * tags are included as a hint to aid decoding.
       */
-      virtual std::string format_bin(ASN1_Tag type_tag,
-                                     ASN1_Tag class_tag,
+      virtual std::string format_bin(ASN1_Type type_tag,
+                                     ASN1_Class class_tag,
                                      const std::vector<uint8_t>& vec) const = 0;
 
    private:
@@ -104,14 +104,14 @@ class BOTAN_PUBLIC_API(2,4) ASN1_Pretty_Printer final : public ASN1_Formatter
          {}
 
    private:
-      std::string format(ASN1_Tag type_tag,
-                         ASN1_Tag class_tag,
+      std::string format(ASN1_Type type_tag,
+                         ASN1_Class class_tag,
                          size_t level,
                          size_t length,
                          const std::string& value) const override;
 
-      std::string format_bin(ASN1_Tag type_tag,
-                             ASN1_Tag class_tag,
+      std::string format_bin(ASN1_Type type_tag,
+                             ASN1_Class class_tag,
                              const std::vector<uint8_t>& vec) const override;
 
       const size_t m_print_limit;
diff --git a/src/lib/asn1/asn1_str.cpp b/src/lib/asn1/asn1_str.cpp
index ac0bbfc68..516dd86b8 100644
--- a/src/lib/asn1/asn1_str.cpp
+++ b/src/lib/asn1/asn1_str.cpp
@@ -18,7 +18,7 @@ namespace {
 /*
 * Choose an encoding for the string
 */
-ASN1_Tag choose_encoding(const std::string& str)
+ASN1_Type choose_encoding(const std::string& str)
    {
    auto all_printable = CT::Mask<uint8_t>::set();
 
@@ -40,12 +40,12 @@ ASN1_Tag choose_encoding(const std::string& str)
       }
 
    if(all_printable.is_set())
-      return ASN1_Tag::PRINTABLE_STRING;
+      return ASN1_Type::PRINTABLE_STRING;
    else
-      return ASN1_Tag::UTF8_STRING;
+      return ASN1_Type::UTF8_STRING;
    }
 
-void assert_is_string_type(ASN1_Tag tag)
+void assert_is_string_type(ASN1_Type tag)
    {
    if(!ASN1_String::is_string_type(tag))
       {
@@ -57,25 +57,25 @@ void assert_is_string_type(ASN1_Tag tag)
 }
 
 //static
-bool ASN1_String::is_string_type(ASN1_Tag tag)
+bool ASN1_String::is_string_type(ASN1_Type tag)
    {
-   return (tag == ASN1_Tag::NUMERIC_STRING ||
-           tag == ASN1_Tag::PRINTABLE_STRING ||
-           tag == ASN1_Tag::VISIBLE_STRING ||
-           tag == ASN1_Tag::T61_STRING ||
-           tag == ASN1_Tag::IA5_STRING ||
-           tag == ASN1_Tag::UTF8_STRING ||
-           tag == ASN1_Tag::BMP_STRING ||
-           tag == ASN1_Tag::UNIVERSAL_STRING);
+   return (tag == ASN1_Type::NUMERIC_STRING ||
+           tag == ASN1_Type::PRINTABLE_STRING ||
+           tag == ASN1_Type::VISIBLE_STRING ||
+           tag == ASN1_Type::T61_STRING ||
+           tag == ASN1_Type::IA5_STRING ||
+           tag == ASN1_Type::UTF8_STRING ||
+           tag == ASN1_Type::BMP_STRING ||
+           tag == ASN1_Type::UNIVERSAL_STRING);
    }
 
 
 /*
 * Create an ASN1_String
 */
-ASN1_String::ASN1_String(const std::string& str, ASN1_Tag t) : m_utf8_str(str), m_tag(t)
+ASN1_String::ASN1_String(const std::string& str, ASN1_Type t) : m_utf8_str(str), m_tag(t)
    {
-   if(m_tag == ASN1_Tag::DIRECTORY_STRING)
+   if(m_tag == ASN1_Type::DIRECTORY_STRING)
       {
       m_tag = choose_encoding(m_utf8_str);
       }
@@ -98,12 +98,12 @@ void ASN1_String::encode_into(DER_Encoder& encoder) const
    {
    if(m_data.empty())
       {
-      encoder.add_object(tagging(), ASN1_Tag::UNIVERSAL, m_utf8_str);
+      encoder.add_object(tagging(), ASN1_Class::UNIVERSAL, m_utf8_str);
       }
    else
       {
       // If this string was decoded, reserialize using original encoding
-      encoder.add_object(tagging(), ASN1_Tag::UNIVERSAL, m_data.data(), m_data.size());
+      encoder.add_object(tagging(), ASN1_Class::UNIVERSAL, m_data.data(), m_data.size());
       }
    }
 
@@ -119,11 +119,11 @@ void ASN1_String::decode_from(BER_Decoder& source)
    m_tag = obj.type();
    m_data.assign(obj.bits(), obj.bits() + obj.length());
 
-   if(m_tag == ASN1_Tag::BMP_STRING)
+   if(m_tag == ASN1_Type::BMP_STRING)
       {
       m_utf8_str = ucs2_to_utf8(m_data.data(), m_data.size());
       }
-   else if(m_tag == ASN1_Tag::UNIVERSAL_STRING)
+   else if(m_tag == ASN1_Type::UNIVERSAL_STRING)
       {
       m_utf8_str = ucs4_to_utf8(m_data.data(), m_data.size());
       }
diff --git a/src/lib/asn1/asn1_time.cpp b/src/lib/asn1/asn1_time.cpp
index 927402f74..b7c40b464 100644
--- a/src/lib/asn1/asn1_time.cpp
+++ b/src/lib/asn1/asn1_time.cpp
@@ -27,20 +27,20 @@ ASN1_Time::ASN1_Time(const std::chrono::system_clock::time_point& time)
    m_minute = cal.minutes();
    m_second = cal.seconds();
 
-   m_tag = (m_year >= 2050) ? ASN1_Tag::GENERALIZED_TIME : ASN1_Tag::UTC_TIME;
+   m_tag = (m_year >= 2050) ? ASN1_Type::GENERALIZED_TIME : ASN1_Type::UTC_TIME;
    }
 
-ASN1_Time::ASN1_Time(const std::string& t_spec, ASN1_Tag tag)
+ASN1_Time::ASN1_Time(const std::string& t_spec, ASN1_Type tag)
    {
    set_to(t_spec, tag);
    }
 
 void ASN1_Time::encode_into(DER_Encoder& der) const
    {
-   BOTAN_ARG_CHECK(m_tag == ASN1_Tag::UTC_TIME || m_tag == ASN1_Tag::GENERALIZED_TIME,
+   BOTAN_ARG_CHECK(m_tag == ASN1_Type::UTC_TIME || m_tag == ASN1_Type::GENERALIZED_TIME,
                    "ASN1_Time: Bad encoding tag");
 
-   der.add_object(m_tag, ASN1_Tag::UNIVERSAL, to_string());
+   der.add_object(m_tag, ASN1_Class::UNIVERSAL, to_string());
    }
 
 void ASN1_Time::decode_from(BER_Decoder& source)
@@ -57,7 +57,7 @@ std::string ASN1_Time::to_string() const
 
    uint32_t full_year = m_year;
 
-   if(m_tag == ASN1_Tag::UTC_TIME)
+   if(m_tag == ASN1_Type::UTC_TIME)
       {
       if(m_year < 1950 || m_year >= 2050)
          throw Encoding_Error("ASN1_Time: The time " + readable_string() +
@@ -82,7 +82,7 @@ std::string ASN1_Time::to_string() const
 
    std::string repr = std::to_string(int_repr) + "Z";
 
-   uint32_t desired_size = (m_tag == ASN1_Tag::UTC_TIME) ? 13 : 15;
+   uint32_t desired_size = (m_tag == ASN1_Type::UTC_TIME) ? 13 : 15;
 
    while(repr.size() < desired_size)
       repr = "0" + repr;
@@ -138,20 +138,20 @@ int32_t ASN1_Time::cmp(const ASN1_Time& other) const
    return SAME_TIME;
    }
 
-void ASN1_Time::set_to(const std::string& t_spec, ASN1_Tag spec_tag)
+void ASN1_Time::set_to(const std::string& t_spec, ASN1_Type spec_tag)
    {
-   if(spec_tag == ASN1_Tag::UTC_OR_GENERALIZED_TIME)
+   if(spec_tag == ASN1_Type::UTC_OR_GENERALIZED_TIME)
       {
       try
          {
-         set_to(t_spec, ASN1_Tag::GENERALIZED_TIME);
+         set_to(t_spec, ASN1_Type::GENERALIZED_TIME);
          return;
          }
       catch(Invalid_Argument&) {} // Not a generalized time. Continue
 
       try
          {
-         set_to(t_spec, ASN1_Tag::UTC_TIME);
+         set_to(t_spec, ASN1_Type::UTC_TIME);
          return;
          }
       catch(Invalid_Argument&) {} // Not a UTC time. Continue
@@ -159,22 +159,22 @@ void ASN1_Time::set_to(const std::string& t_spec, ASN1_Tag spec_tag)
       throw Invalid_Argument("Time string could not be parsed as GeneralizedTime or UTCTime.");
       }
 
-   BOTAN_ASSERT(spec_tag == ASN1_Tag::UTC_TIME || spec_tag == ASN1_Tag::GENERALIZED_TIME, "Invalid tag.");
+   BOTAN_ASSERT(spec_tag == ASN1_Type::UTC_TIME || spec_tag == ASN1_Type::GENERALIZED_TIME, "Invalid tag.");
 
    BOTAN_ARG_CHECK(t_spec.size() > 0, "Time string must not be empty.");
 
    BOTAN_ARG_CHECK(t_spec.back() == 'Z', "Botan does not support times with timezones other than Z");
 
-   if(spec_tag == ASN1_Tag::GENERALIZED_TIME)
+   if(spec_tag == ASN1_Type::GENERALIZED_TIME)
       {
       BOTAN_ARG_CHECK(t_spec.size() == 15, "Invalid GeneralizedTime string");
       }
-   else if(spec_tag == ASN1_Tag::UTC_TIME)
+   else if(spec_tag == ASN1_Type::UTC_TIME)
       {
       BOTAN_ARG_CHECK(t_spec.size() == 13, "Invalid UTCTime string");
       }
 
-   const size_t YEAR_SIZE = (spec_tag == ASN1_Tag::UTC_TIME) ? 2 : 4;
+   const size_t YEAR_SIZE = (spec_tag == ASN1_Type::UTC_TIME) ? 2 : 4;
 
    std::vector<std::string> params;
    std::string current;
@@ -202,7 +202,7 @@ void ASN1_Time::set_to(const std::string& t_spec, ASN1_Tag spec_tag)
    m_second = (params.size() == 6) ? to_u32bit(params[5]) : 0;
    m_tag    = spec_tag;
 
-   if(spec_tag == ASN1_Tag::UTC_TIME)
+   if(spec_tag == ASN1_Type::UTC_TIME)
       {
       if(m_year >= 50) m_year += 1900;
       else             m_year += 2000;
@@ -240,7 +240,7 @@ bool ASN1_Time::passes_sanity_check() const
    if(m_hour >= 24 || m_minute >= 60 || m_second > 60)
       return false;
 
-   if (m_tag == ASN1_Tag::UTC_TIME)
+   if (m_tag == ASN1_Type::UTC_TIME)
       {
       /*
       UTCTime limits the value of components such that leap seconds
diff --git a/src/lib/asn1/ber_dec.cpp b/src/lib/asn1/ber_dec.cpp
index 968a8ad4d..d2ae46589 100644
--- a/src/lib/asn1/ber_dec.cpp
+++ b/src/lib/asn1/ber_dec.cpp
@@ -24,24 +24,25 @@ const size_t ALLOWED_EOC_NESTINGS = 16;
 /*
 * BER decode an ASN.1 type tag
 */
-size_t decode_tag(DataSource* ber, ASN1_Tag& type_tag, ASN1_Tag& class_tag)
+size_t decode_tag(DataSource* ber, ASN1_Type& type_tag, ASN1_Class& class_tag)
    {
    uint8_t b;
    if(!ber->read_byte(b))
       {
-      class_tag = type_tag = ASN1_Tag::NO_OBJECT;
+      type_tag = ASN1_Type::NO_OBJECT;
+      class_tag = ASN1_Class::NO_OBJECT;
       return 0;
       }
 
    if((b & 0x1F) != 0x1F)
       {
-      type_tag = ASN1_Tag(b & 0x1F);
-      class_tag = ASN1_Tag(b & 0xE0);
+      type_tag = ASN1_Type(b & 0x1F);
+      class_tag = ASN1_Class(b & 0xE0);
       return 1;
       }
 
    size_t tag_bytes = 1;
-   class_tag = ASN1_Tag(b & 0xE0);
+   class_tag = ASN1_Class(b & 0xE0);
 
    size_t tag_buf = 0;
    while(true)
@@ -54,7 +55,7 @@ size_t decode_tag(DataSource* ber, ASN1_Tag& type_tag, ASN1_Tag& class_tag)
       tag_buf = (tag_buf << 7) | (b & 0x7F);
       if((b & 0x80) == 0) break;
       }
-   type_tag = ASN1_Tag(tag_buf);
+   type_tag = ASN1_Type(tag_buf);
    return tag_bytes;
    }
 
@@ -126,9 +127,10 @@ size_t find_eoc(DataSource* ber, size_t allow_indef)
    size_t length = 0;
    while(true)
       {
-      ASN1_Tag type_tag, class_tag;
+      ASN1_Type type_tag;
+      ASN1_Class class_tag;
       size_t tag_size = decode_tag(&source, type_tag, class_tag);
-      if(type_tag == ASN1_Tag::NO_OBJECT)
+      if(type_tag == ASN1_Type::NO_OBJECT)
          break;
 
       size_t length_size = 0;
@@ -139,7 +141,7 @@ size_t find_eoc(DataSource* ber, size_t allow_indef)
       length = BOTAN_CHECKED_ADD(length, tag_size);
       length = BOTAN_CHECKED_ADD(length, length_size);
 
-      if(type_tag == ASN1_Tag::EOC && class_tag == ASN1_Tag::UNIVERSAL)
+      if(type_tag == ASN1_Type::EOC && class_tag == ASN1_Class::UNIVERSAL)
          break;
       }
    return length;
@@ -246,7 +248,8 @@ BER_Object BER_Decoder::get_next_object()
 
    for(;;)
       {
-      ASN1_Tag type_tag, class_tag;
+      ASN1_Type type_tag;
+      ASN1_Class 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
@@ -261,7 +264,7 @@ BER_Object BER_Decoder::get_next_object()
       if(m_source->read(out, length) != length)
          throw BER_Decoding_Error("Value truncated");
 
-      if(next.tagging() == ASN1_Tag::EOC)
+      if(next.tagging() == static_cast<uint32_t>(ASN1_Type::EOC))
          continue;
       else
          break;
@@ -287,10 +290,10 @@ void BER_Decoder::push_back(BER_Object&& obj)
    m_pushed = std::move(obj);
    }
 
-BER_Decoder BER_Decoder::start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag)
+BER_Decoder BER_Decoder::start_cons(ASN1_Type type_tag, ASN1_Class class_tag)
    {
    BER_Object obj = get_next_object();
-   obj.assert_is_a(type_tag, class_tag | ASN1_Tag::CONSTRUCTED);
+   obj.assert_is_a(type_tag, class_tag | ASN1_Class::CONSTRUCTED);
    return BER_Decoder(std::move(obj), this);
    }
 
@@ -364,7 +367,7 @@ BER_Decoder::BER_Decoder(const BER_Decoder& other)
 * Request for an object to decode itself
 */
 BER_Decoder& BER_Decoder::decode(ASN1_Object& obj,
-                                 ASN1_Tag, ASN1_Tag)
+                                 ASN1_Type, ASN1_Class)
    {
    obj.decode_from(*this);
    return (*this);
@@ -376,7 +379,7 @@ BER_Decoder& BER_Decoder::decode(ASN1_Object& obj,
 BER_Decoder& BER_Decoder::decode_null()
    {
    BER_Object obj = get_next_object();
-   obj.assert_is_a(ASN1_Tag::NULL_TAG, ASN1_Tag::UNIVERSAL);
+   obj.assert_is_a(ASN1_Type::NULL_TAG, ASN1_Class::UNIVERSAL);
    if(obj.length() > 0)
       throw BER_Decoding_Error("NULL object had nonzero size");
    return (*this);
@@ -385,7 +388,7 @@ BER_Decoder& BER_Decoder::decode_null()
 BER_Decoder& BER_Decoder::decode_octet_string_bigint(BigInt& out)
    {
    secure_vector<uint8_t> out_vec;
-   decode(out_vec, ASN1_Tag::OCTET_STRING);
+   decode(out_vec, ASN1_Type::OCTET_STRING);
    out = BigInt::decode(out_vec.data(), out_vec.size());
    return (*this);
    }
@@ -394,7 +397,7 @@ BER_Decoder& BER_Decoder::decode_octet_string_bigint(BigInt& out)
 * Decode a BER encoded BOOLEAN
 */
 BER_Decoder& BER_Decoder::decode(bool& out,
-                                 ASN1_Tag type_tag, ASN1_Tag class_tag)
+                                 ASN1_Type type_tag, ASN1_Class class_tag)
    {
    BER_Object obj = get_next_object();
    obj.assert_is_a(type_tag, class_tag);
@@ -410,8 +413,8 @@ BER_Decoder& BER_Decoder::decode(bool& out,
 * Decode a small BER encoded INTEGER
 */
 BER_Decoder& BER_Decoder::decode(size_t& out,
-                                 ASN1_Tag type_tag,
-                                 ASN1_Tag class_tag)
+                                 ASN1_Type type_tag,
+                                 ASN1_Class class_tag)
    {
    BigInt integer;
    decode(integer, type_tag, class_tag);
@@ -432,8 +435,8 @@ BER_Decoder& BER_Decoder::decode(size_t& out,
 /*
 * Decode a small BER encoded INTEGER
 */
-uint64_t BER_Decoder::decode_constrained_integer(ASN1_Tag type_tag,
-                                                 ASN1_Tag class_tag,
+uint64_t BER_Decoder::decode_constrained_integer(ASN1_Type type_tag,
+                                                 ASN1_Class class_tag,
                                                  size_t T_bytes)
    {
    if(T_bytes > 8)
@@ -456,8 +459,8 @@ uint64_t BER_Decoder::decode_constrained_integer(ASN1_Tag type_tag,
 * Decode a BER encoded INTEGER
 */
 BER_Decoder& BER_Decoder::decode(BigInt& out,
-                                 ASN1_Tag type_tag,
-                                 ASN1_Tag class_tag)
+                                 ASN1_Type type_tag,
+                                 ASN1_Class class_tag)
    {
    BER_Object obj = get_next_object();
    obj.assert_is_a(type_tag, class_tag);
@@ -495,13 +498,13 @@ namespace {
 template<typename Alloc>
 void asn1_decode_binary_string(std::vector<uint8_t, Alloc>& buffer,
                                const BER_Object& obj,
-                               ASN1_Tag real_type,
-                               ASN1_Tag type_tag,
-                               ASN1_Tag class_tag)
+                               ASN1_Type real_type,
+                               ASN1_Type type_tag,
+                               ASN1_Class class_tag)
    {
    obj.assert_is_a(type_tag, class_tag);
 
-   if(real_type == ASN1_Tag::OCTET_STRING)
+   if(real_type == ASN1_Type::OCTET_STRING)
       {
       buffer.assign(obj.bits(), obj.bits() + obj.length());
       }
@@ -525,22 +528,22 @@ void asn1_decode_binary_string(std::vector<uint8_t, Alloc>& buffer,
 * BER decode a BIT STRING or OCTET STRING
 */
 BER_Decoder& BER_Decoder::decode(secure_vector<uint8_t>& buffer,
-                                 ASN1_Tag real_type,
-                                 ASN1_Tag type_tag, ASN1_Tag class_tag)
+                                 ASN1_Type real_type,
+                                 ASN1_Type type_tag, ASN1_Class class_tag)
    {
-   if(real_type != ASN1_Tag::OCTET_STRING && real_type != ASN1_Tag::BIT_STRING)
-      throw BER_Bad_Tag("Bad tag for {BIT,OCTET} STRING", real_type);
+   if(real_type != ASN1_Type::OCTET_STRING && real_type != ASN1_Type::BIT_STRING)
+       throw BER_Bad_Tag("Bad tag for {BIT,OCTET} STRING", static_cast<uint32_t>(real_type));
 
    asn1_decode_binary_string(buffer, get_next_object(), real_type, type_tag, class_tag);
    return (*this);
    }
 
 BER_Decoder& BER_Decoder::decode(std::vector<uint8_t>& buffer,
-                                 ASN1_Tag real_type,
-                                 ASN1_Tag type_tag, ASN1_Tag class_tag)
+                                 ASN1_Type real_type,
+                                 ASN1_Type type_tag, ASN1_Class class_tag)
    {
-   if(real_type != ASN1_Tag::OCTET_STRING && real_type != ASN1_Tag::BIT_STRING)
-      throw BER_Bad_Tag("Bad tag for {BIT,OCTET} STRING", real_type);
+   if(real_type != ASN1_Type::OCTET_STRING && real_type != ASN1_Type::BIT_STRING)
+      throw BER_Bad_Tag("Bad tag for {BIT,OCTET} STRING", static_cast<uint32_t>(real_type));
 
    asn1_decode_binary_string(buffer, get_next_object(), real_type, type_tag, class_tag);
    return (*this);
diff --git a/src/lib/asn1/ber_dec.h b/src/lib/asn1/ber_dec.h
index 4d96a8d3a..3784c929d 100644
--- a/src/lib/asn1/ber_dec.h
+++ b/src/lib/asn1/ber_dec.h
@@ -109,11 +109,11 @@ class BOTAN_PUBLIC_API(2,0) BER_Decoder final
       /**
       * Start decoding a constructed data (sequence or set)
       */
-      BER_Decoder start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag = ASN1_Tag::UNIVERSAL);
+      BER_Decoder start_cons(ASN1_Type type_tag, ASN1_Class class_tag = ASN1_Class::UNIVERSAL);
 
       BER_Decoder start_sequence()
          {
-         return start_cons(ASN1_Tag::SEQUENCE);
+         return start_cons(ASN1_Type::SEQUENCE);
          }
 
       /**
@@ -128,14 +128,14 @@ class BOTAN_PUBLIC_API(2,0) BER_Decoder final
       * Asserts Type tag and optional Class tag according to parameters.
       * Copy value to POD type (struct, union, C-style array, std::array, etc.).
       * @param out POD type reference where to copy object value
-      * @param type_tag ASN1_Tag enum to assert type on object read
-      * @param class_tag ASN1_Tag enum to assert class on object read (default: CONTEXT_SPECIFIC)
+      * @param type_tag ASN1_Type enum to assert type on object read
+      * @param class_tag ASN1_Type enum to assert class on object read (default: CONTEXT_SPECIFIC)
       * @return this reference
       */
       template <typename T>
          BER_Decoder& get_next_value(T &out,
-                                     ASN1_Tag type_tag,
-                                     ASN1_Tag class_tag = ASN1_Tag::CONTEXT_SPECIFIC)
+                                     ASN1_Type type_tag,
+                                     ASN1_Class class_tag = ASN1_Class::CONTEXT_SPECIFIC)
          {
          static_assert(std::is_standard_layout<T>::value && std::is_trivial<T>::value, "Type must be POD");
 
@@ -174,7 +174,7 @@ class BOTAN_PUBLIC_API(2,0) BER_Decoder final
       */
       BER_Decoder& decode(bool& out)
          {
-         return decode(out, ASN1_Tag::BOOLEAN, ASN1_Tag::UNIVERSAL);
+         return decode(out, ASN1_Type::BOOLEAN, ASN1_Class::UNIVERSAL);
          }
 
       /*
@@ -182,7 +182,7 @@ class BOTAN_PUBLIC_API(2,0) BER_Decoder final
       */
       BER_Decoder& decode(size_t& out)
          {
-         return decode(out, ASN1_Tag::INTEGER, ASN1_Tag::UNIVERSAL);
+         return decode(out, ASN1_Type::INTEGER, ASN1_Class::UNIVERSAL);
          }
 
       /*
@@ -190,13 +190,13 @@ class BOTAN_PUBLIC_API(2,0) BER_Decoder final
       */
       BER_Decoder& decode(BigInt& out)
          {
-         return decode(out, ASN1_Tag::INTEGER, ASN1_Tag::UNIVERSAL);
+         return decode(out, ASN1_Type::INTEGER, ASN1_Class::UNIVERSAL);
          }
 
       std::vector<uint8_t> get_next_octet_string()
          {
          std::vector<uint8_t> out_vec;
-         decode(out_vec, ASN1_Tag::OCTET_STRING);
+         decode(out_vec, ASN1_Type::OCTET_STRING);
          return out_vec;
          }
 
@@ -204,55 +204,55 @@ class BOTAN_PUBLIC_API(2,0) BER_Decoder final
       * BER decode a BIT STRING or OCTET STRING
       */
       template<typename Alloc>
-      BER_Decoder& decode(std::vector<uint8_t, Alloc>& out, ASN1_Tag real_type)
+      BER_Decoder& decode(std::vector<uint8_t, Alloc>& out, ASN1_Type real_type)
          {
-         return decode(out, real_type, real_type, ASN1_Tag::UNIVERSAL);
+         return decode(out, real_type, real_type, ASN1_Class::UNIVERSAL);
          }
 
       BER_Decoder& decode(bool& v,
-                          ASN1_Tag type_tag,
-                          ASN1_Tag class_tag = ASN1_Tag::CONTEXT_SPECIFIC);
+                          ASN1_Type type_tag,
+                          ASN1_Class class_tag = ASN1_Class::CONTEXT_SPECIFIC);
 
       BER_Decoder& decode(size_t& v,
-                          ASN1_Tag type_tag,
-                          ASN1_Tag class_tag = ASN1_Tag::CONTEXT_SPECIFIC);
+                          ASN1_Type type_tag,
+                          ASN1_Class class_tag = ASN1_Class::CONTEXT_SPECIFIC);
 
       BER_Decoder& decode(BigInt& v,
-                          ASN1_Tag type_tag,
-                          ASN1_Tag class_tag = ASN1_Tag::CONTEXT_SPECIFIC);
+                          ASN1_Type type_tag,
+                          ASN1_Class class_tag = ASN1_Class::CONTEXT_SPECIFIC);
 
       BER_Decoder& decode(std::vector<uint8_t>& v,
-                          ASN1_Tag real_type,
-                          ASN1_Tag type_tag,
-                          ASN1_Tag class_tag = ASN1_Tag::CONTEXT_SPECIFIC);
+                          ASN1_Type real_type,
+                          ASN1_Type type_tag,
+                          ASN1_Class class_tag = ASN1_Class::CONTEXT_SPECIFIC);
 
       BER_Decoder& decode(secure_vector<uint8_t>& v,
-                          ASN1_Tag real_type,
-                          ASN1_Tag type_tag,
-                          ASN1_Tag class_tag = ASN1_Tag::CONTEXT_SPECIFIC);
+                          ASN1_Type real_type,
+                          ASN1_Type type_tag,
+                          ASN1_Class class_tag = ASN1_Class::CONTEXT_SPECIFIC);
 
       BER_Decoder& decode(class ASN1_Object& obj,
-                          ASN1_Tag type_tag = ASN1_Tag::NO_OBJECT,
-                          ASN1_Tag class_tag = ASN1_Tag::NO_OBJECT);
+                          ASN1_Type type_tag = ASN1_Type::NO_OBJECT,
+                          ASN1_Class class_tag = ASN1_Class::NO_OBJECT);
 
       /**
       * Decode an integer value which is typed as an octet string
       */
       BER_Decoder& decode_octet_string_bigint(BigInt& b);
 
-      uint64_t decode_constrained_integer(ASN1_Tag type_tag,
-                                          ASN1_Tag class_tag,
+      uint64_t decode_constrained_integer(ASN1_Type type_tag,
+                                          ASN1_Class class_tag,
                                           size_t T_bytes);
 
       template<typename T> BER_Decoder& decode_integer_type(T& out)
          {
-         return decode_integer_type<T>(out, ASN1_Tag::INTEGER, ASN1_Tag::UNIVERSAL);
+         return decode_integer_type<T>(out, ASN1_Type::INTEGER, ASN1_Class::UNIVERSAL);
          }
 
       template<typename T>
          BER_Decoder& decode_integer_type(T& out,
-                                          ASN1_Tag type_tag,
-                                          ASN1_Tag class_tag = ASN1_Tag::CONTEXT_SPECIFIC)
+                                          ASN1_Type type_tag,
+                                          ASN1_Class class_tag = ASN1_Class::CONTEXT_SPECIFIC)
          {
          out = static_cast<T>(decode_constrained_integer(type_tag, class_tag, sizeof(out)));
          return (*this);
@@ -260,23 +260,23 @@ class BOTAN_PUBLIC_API(2,0) BER_Decoder final
 
       template<typename T>
          BER_Decoder& decode_optional(T& out,
-                                      ASN1_Tag type_tag,
-                                      ASN1_Tag class_tag,
+                                      ASN1_Type type_tag,
+                                      ASN1_Class class_tag,
                                       const T& default_value = T());
 
       template<typename T>
          BER_Decoder& decode_optional_implicit(
             T& out,
-            ASN1_Tag type_tag,
-            ASN1_Tag class_tag,
-            ASN1_Tag real_type,
-            ASN1_Tag real_class,
+            ASN1_Type type_tag,
+            ASN1_Class class_tag,
+            ASN1_Type real_type,
+            ASN1_Class real_class,
             const T& default_value = T());
 
       template<typename T>
          BER_Decoder& decode_list(std::vector<T>& out,
-                                  ASN1_Tag type_tag = ASN1_Tag::SEQUENCE,
-                                  ASN1_Tag class_tag = ASN1_Tag::UNIVERSAL);
+                                  ASN1_Type type_tag = ASN1_Type::SEQUENCE,
+                                  ASN1_Class class_tag = ASN1_Class::UNIVERSAL);
 
       template<typename T>
          BER_Decoder& decode_and_check(const T& expected,
@@ -296,17 +296,17 @@ class BOTAN_PUBLIC_API(2,0) BER_Decoder final
       */
       template<typename Alloc>
       BER_Decoder& decode_optional_string(std::vector<uint8_t, Alloc>& out,
-                                          ASN1_Tag real_type,
+                                          ASN1_Type real_type,
                                           uint32_t expected_tag,
-                                          ASN1_Tag class_tag = ASN1_Tag::CONTEXT_SPECIFIC)
+                                          ASN1_Class class_tag = ASN1_Class::CONTEXT_SPECIFIC)
          {
          BER_Object obj = get_next_object();
 
-         ASN1_Tag type_tag = static_cast<ASN1_Tag>(expected_tag);
+         ASN1_Type type_tag = static_cast<ASN1_Type>(expected_tag);
 
          if(obj.is_a(type_tag, class_tag))
             {
-            if(class_tag == ASN1_Tag::PRIVATE)
+            if(class_tag == ASN1_Class::EXPLICIT_CONTEXT_SPECIFIC)
                {
                BER_Decoder(std::move(obj)).decode(out, real_type).verify_end();
                }
@@ -327,9 +327,9 @@ class BOTAN_PUBLIC_API(2,0) BER_Decoder final
 
       template<typename Alloc>
       BER_Decoder& decode_optional_string(std::vector<uint8_t, Alloc>& out,
-                                          ASN1_Tag real_type,
-                                          ASN1_Tag expected_tag,
-                                          ASN1_Tag class_tag = ASN1_Tag::CONTEXT_SPECIFIC)
+                                          ASN1_Type real_type,
+                                          ASN1_Type expected_tag,
+                                          ASN1_Class class_tag = ASN1_Class::CONTEXT_SPECIFIC)
          {
          return decode_optional_string(out, real_type,
                                        static_cast<uint32_t>(expected_tag),
@@ -351,15 +351,15 @@ class BOTAN_PUBLIC_API(2,0) BER_Decoder final
 */
 template<typename T>
 BER_Decoder& BER_Decoder::decode_optional(T& out,
-                                          ASN1_Tag type_tag,
-                                          ASN1_Tag class_tag,
+                                          ASN1_Type type_tag,
+                                          ASN1_Class class_tag,
                                           const T& default_value)
    {
    BER_Object obj = get_next_object();
 
    if(obj.is_a(type_tag, class_tag))
       {
-      if(class_tag == ASN1_Tag::PRIVATE)
+      if(class_tag == ASN1_Class::EXPLICIT_CONTEXT_SPECIFIC)
          {
          BER_Decoder(std::move(obj)).decode(out).verify_end();
          }
@@ -384,10 +384,10 @@ BER_Decoder& BER_Decoder::decode_optional(T& out,
 template<typename T>
 BER_Decoder& BER_Decoder::decode_optional_implicit(
    T& out,
-   ASN1_Tag type_tag,
-   ASN1_Tag class_tag,
-   ASN1_Tag real_type,
-   ASN1_Tag real_class,
+   ASN1_Type type_tag,
+   ASN1_Class class_tag,
+   ASN1_Type real_type,
+   ASN1_Class real_class,
    const T& default_value)
    {
    BER_Object obj = get_next_object();
@@ -412,8 +412,8 @@ BER_Decoder& BER_Decoder::decode_optional_implicit(
 */
 template<typename T>
 BER_Decoder& BER_Decoder::decode_list(std::vector<T>& vec,
-                                      ASN1_Tag type_tag,
-                                      ASN1_Tag class_tag)
+                                      ASN1_Type type_tag,
+                                      ASN1_Class class_tag)
    {
    BER_Decoder list = start_cons(type_tag, class_tag);
 
diff --git a/src/lib/asn1/der_enc.cpp b/src/lib/asn1/der_enc.cpp
index bb65e38ee..b6357369f 100644
--- a/src/lib/asn1/der_enc.cpp
+++ b/src/lib/asn1/der_enc.cpp
@@ -20,7 +20,7 @@ namespace {
 * DER encode an ASN.1 type tag
 */
 void encode_tag(std::vector<uint8_t>& encoded_tag,
-                ASN1_Tag type_tag_e, ASN1_Tag class_tag_e)
+                ASN1_Type type_tag_e, ASN1_Class class_tag_e)
    {
    const uint32_t type_tag = static_cast<uint32_t>(type_tag_e);
    const uint32_t class_tag = static_cast<uint32_t>(class_tag_e);
@@ -90,9 +90,9 @@ DER_Encoder::DER_Encoder(std::vector<uint8_t>& vec)
 */
 void DER_Encoder::DER_Sequence::push_contents(DER_Encoder& der)
    {
-   const ASN1_Tag real_class_tag = ASN1_Tag(m_class_tag) | ASN1_Tag::CONSTRUCTED;
+       const auto real_class_tag = m_class_tag | ASN1_Class::CONSTRUCTED;
 
-   if(m_type_tag == ASN1_Tag::SET)
+   if(m_type_tag == ASN1_Type::SET)
       {
       std::sort(m_set_contents.begin(), m_set_contents.end());
       for(size_t i = 0; i != m_set_contents.size(); ++i)
@@ -109,7 +109,7 @@ void DER_Encoder::DER_Sequence::push_contents(DER_Encoder& der)
 */
 void DER_Encoder::DER_Sequence::add_bytes(const uint8_t data[], size_t length)
    {
-   if(m_type_tag == ASN1_Tag::SET)
+   if(m_type_tag == ASN1_Type::SET)
       m_set_contents.push_back(secure_vector<uint8_t>(data, data + length));
    else
       m_contents += std::make_pair(data, length);
@@ -118,7 +118,7 @@ void DER_Encoder::DER_Sequence::add_bytes(const uint8_t data[], size_t length)
 void DER_Encoder::DER_Sequence::add_bytes(const uint8_t hdr[], size_t hdr_len,
                                           const uint8_t val[], size_t val_len)
    {
-   if(m_type_tag == ASN1_Tag::SET)
+   if(m_type_tag == ASN1_Type::SET)
       {
       secure_vector<uint8_t> m;
       m.reserve(hdr_len + val_len);
@@ -136,15 +136,15 @@ void DER_Encoder::DER_Sequence::add_bytes(const uint8_t hdr[], size_t hdr_len,
 /*
 * Return the type and class taggings
 */
-ASN1_Tag DER_Encoder::DER_Sequence::tag_of() const
+uint32_t DER_Encoder::DER_Sequence::tag_of() const
    {
-   return ASN1_Tag(m_type_tag | m_class_tag);
+   return m_type_tag | m_class_tag;
    }
 
 /*
 * DER_Sequence Constructor
 */
-DER_Encoder::DER_Sequence::DER_Sequence(ASN1_Tag t1, ASN1_Tag t2) :
+DER_Encoder::DER_Sequence::DER_Sequence(ASN1_Type t1, ASN1_Class t2) :
    m_type_tag(t1), m_class_tag(t2)
    {
    }
@@ -181,8 +181,8 @@ std::vector<uint8_t> DER_Encoder::get_contents_unlocked()
 /*
 * Start a new ASN.1 SEQUENCE/SET/EXPLICIT
 */
-DER_Encoder& DER_Encoder::start_cons(ASN1_Tag type_tag,
-                                     ASN1_Tag class_tag)
+DER_Encoder& DER_Encoder::start_cons(ASN1_Type type_tag,
+                                     ASN1_Class class_tag)
    {
    m_subsequences.push_back(DER_Sequence(type_tag, class_tag));
    return (*this);
@@ -208,13 +208,13 @@ DER_Encoder& DER_Encoder::end_cons()
 */
 DER_Encoder& DER_Encoder::start_explicit(uint16_t type_no)
    {
-   ASN1_Tag type_tag = static_cast<ASN1_Tag>(type_no);
+   ASN1_Type type_tag = static_cast<ASN1_Type>(type_no);
 
    // This would confuse DER_Sequence
-   if(type_tag == ASN1_Tag::SET)
+   if(type_tag == ASN1_Type::SET)
       throw Internal_Error("DER_Encoder.start_explicit(SET) not supported");
 
-   return start_cons(type_tag, ASN1_Tag::CONTEXT_SPECIFIC);
+   return start_cons(type_tag, ASN1_Class::CONTEXT_SPECIFIC);
    }
 
 /*
@@ -249,7 +249,7 @@ DER_Encoder& DER_Encoder::raw_bytes(const uint8_t bytes[], size_t length)
 /*
 * Write the encoding of the byte(s)
 */
-DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag,
+DER_Encoder& DER_Encoder::add_object(ASN1_Type type_tag, ASN1_Class class_tag,
                                      const uint8_t rep[], size_t length)
    {
    std::vector<uint8_t> hdr;
@@ -279,7 +279,7 @@ DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag,
 */
 DER_Encoder& DER_Encoder::encode_null()
    {
-   return add_object(ASN1_Tag::NULL_TAG, ASN1_Tag::UNIVERSAL, nullptr, 0);
+   return add_object(ASN1_Type::NULL_TAG, ASN1_Class::UNIVERSAL, nullptr, 0);
    }
 
 /*
@@ -287,7 +287,7 @@ DER_Encoder& DER_Encoder::encode_null()
 */
 DER_Encoder& DER_Encoder::encode(bool is_true)
    {
-   return encode(is_true, ASN1_Tag::BOOLEAN, ASN1_Tag::UNIVERSAL);
+   return encode(is_true, ASN1_Type::BOOLEAN, ASN1_Class::UNIVERSAL);
    }
 
 /*
@@ -295,7 +295,7 @@ DER_Encoder& DER_Encoder::encode(bool is_true)
 */
 DER_Encoder& DER_Encoder::encode(size_t n)
    {
-   return encode(BigInt(n), ASN1_Tag::INTEGER, ASN1_Tag::UNIVERSAL);
+   return encode(BigInt(n), ASN1_Type::INTEGER, ASN1_Class::UNIVERSAL);
    }
 
 /*
@@ -303,23 +303,23 @@ DER_Encoder& DER_Encoder::encode(size_t n)
 */
 DER_Encoder& DER_Encoder::encode(const BigInt& n)
    {
-   return encode(n, ASN1_Tag::INTEGER, ASN1_Tag::UNIVERSAL);
+   return encode(n, ASN1_Type::INTEGER, ASN1_Class::UNIVERSAL);
    }
 
 /*
 * Encode this object
 */
 DER_Encoder& DER_Encoder::encode(const uint8_t bytes[], size_t length,
-                                 ASN1_Tag real_type)
+                                 ASN1_Type real_type)
    {
-   return encode(bytes, length, real_type, real_type, ASN1_Tag::UNIVERSAL);
+   return encode(bytes, length, real_type, real_type, ASN1_Class::UNIVERSAL);
    }
 
 /*
 * DER encode a BOOLEAN
 */
 DER_Encoder& DER_Encoder::encode(bool is_true,
-                                 ASN1_Tag type_tag, ASN1_Tag class_tag)
+                                 ASN1_Type type_tag, ASN1_Class class_tag)
    {
    uint8_t val = is_true ? 0xFF : 0x00;
    return add_object(type_tag, class_tag, &val, 1);
@@ -329,7 +329,7 @@ DER_Encoder& DER_Encoder::encode(bool is_true,
 * DER encode a small INTEGER
 */
 DER_Encoder& DER_Encoder::encode(size_t n,
-                                 ASN1_Tag type_tag, ASN1_Tag class_tag)
+                                 ASN1_Type type_tag, ASN1_Class class_tag)
    {
    return encode(BigInt(n), type_tag, class_tag);
    }
@@ -338,7 +338,7 @@ DER_Encoder& DER_Encoder::encode(size_t n,
 * DER encode an INTEGER
 */
 DER_Encoder& DER_Encoder::encode(const BigInt& n,
-                                 ASN1_Tag type_tag, ASN1_Tag class_tag)
+                                 ASN1_Type type_tag, ASN1_Class class_tag)
    {
    if(n == 0)
       return add_object(type_tag, class_tag, 0);
@@ -362,13 +362,13 @@ DER_Encoder& DER_Encoder::encode(const BigInt& n,
 * DER encode an OCTET STRING or BIT STRING
 */
 DER_Encoder& DER_Encoder::encode(const uint8_t bytes[], size_t length,
-                                 ASN1_Tag real_type,
-                                 ASN1_Tag type_tag, ASN1_Tag class_tag)
+                                 ASN1_Type real_type,
+                                 ASN1_Type type_tag, ASN1_Class class_tag)
    {
-   if(real_type != ASN1_Tag::OCTET_STRING && real_type != ASN1_Tag::BIT_STRING)
+   if(real_type != ASN1_Type::OCTET_STRING && real_type != ASN1_Type::BIT_STRING)
       throw Invalid_Argument("DER_Encoder: Invalid tag for byte/bit string");
 
-   if(real_type == ASN1_Tag::BIT_STRING)
+   if(real_type == ASN1_Type::BIT_STRING)
       {
       secure_vector<uint8_t> encoded;
       encoded.push_back(0);
@@ -388,7 +388,7 @@ DER_Encoder& DER_Encoder::encode(const ASN1_Object& obj)
 /*
 * Write the encoding of the byte(s)
 */
-DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag,
+DER_Encoder& DER_Encoder::add_object(ASN1_Type type_tag, ASN1_Class class_tag,
                                      const std::string& rep_str)
    {
    const uint8_t* rep = cast_char_ptr_to_uint8(rep_str.data());
@@ -399,8 +399,8 @@ DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag,
 /*
 * Write the encoding of the byte
 */
-DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag,
-                                     ASN1_Tag class_tag, uint8_t rep)
+DER_Encoder& DER_Encoder::add_object(ASN1_Type type_tag,
+                                     ASN1_Class class_tag, uint8_t rep)
    {
    return add_object(type_tag, class_tag, &rep, 1);
    }
diff --git a/src/lib/asn1/der_enc.h b/src/lib/asn1/der_enc.h
index ff23a5096..e8ac2bf4f 100644
--- a/src/lib/asn1/der_enc.h
+++ b/src/lib/asn1/der_enc.h
@@ -61,12 +61,12 @@ class BOTAN_PUBLIC_API(2,0) DER_Encoder final
       BOTAN_DEPRECATED("Use DER_Encoder(vector) instead")
       std::vector<uint8_t> get_contents_unlocked();
 
-      DER_Encoder& start_cons(ASN1_Tag type_tag,
-                              ASN1_Tag class_tag = ASN1_Tag::UNIVERSAL);
+      DER_Encoder& start_cons(ASN1_Type type_tag,
+                              ASN1_Class class_tag = ASN1_Class::UNIVERSAL);
 
       DER_Encoder& start_sequence()
          {
-         return start_cons(ASN1_Tag::SEQUENCE);
+         return start_cons(ASN1_Type::SEQUENCE);
          }
 
       DER_Encoder& end_cons();
@@ -89,35 +89,35 @@ class BOTAN_PUBLIC_API(2,0) DER_Encoder final
       DER_Encoder& encode(bool b);
       DER_Encoder& encode(size_t s);
       DER_Encoder& encode(const BigInt& n);
-      DER_Encoder& encode(const uint8_t val[], size_t len, ASN1_Tag real_type);
+      DER_Encoder& encode(const uint8_t val[], size_t len, ASN1_Type real_type);
 
       template<typename Alloc>
-      DER_Encoder& encode(const std::vector<uint8_t, Alloc>& vec, ASN1_Tag real_type)
+      DER_Encoder& encode(const std::vector<uint8_t, Alloc>& vec, ASN1_Type real_type)
          {
          return encode(vec.data(), vec.size(), real_type);
          }
 
       DER_Encoder& encode(bool b,
-                          ASN1_Tag type_tag,
-                          ASN1_Tag class_tag = ASN1_Tag::CONTEXT_SPECIFIC);
+                          ASN1_Type type_tag,
+                          ASN1_Class class_tag = ASN1_Class::CONTEXT_SPECIFIC);
 
       DER_Encoder& encode(size_t s,
-                          ASN1_Tag type_tag,
-                          ASN1_Tag class_tag = ASN1_Tag::CONTEXT_SPECIFIC);
+                          ASN1_Type type_tag,
+                          ASN1_Class class_tag = ASN1_Class::CONTEXT_SPECIFIC);
 
       DER_Encoder& encode(const BigInt& n,
-                          ASN1_Tag type_tag,
-                          ASN1_Tag class_tag = ASN1_Tag::CONTEXT_SPECIFIC);
+                          ASN1_Type type_tag,
+                          ASN1_Class class_tag = ASN1_Class::CONTEXT_SPECIFIC);
 
       DER_Encoder& encode(const uint8_t v[], size_t len,
-                          ASN1_Tag real_type,
-                          ASN1_Tag type_tag,
-                          ASN1_Tag class_tag = ASN1_Tag::CONTEXT_SPECIFIC);
+                          ASN1_Type real_type,
+                          ASN1_Type type_tag,
+                          ASN1_Class class_tag = ASN1_Class::CONTEXT_SPECIFIC);
 
       template<typename Alloc>
       DER_Encoder& encode(const std::vector<uint8_t, Alloc>& bytes,
-                          ASN1_Tag real_type,
-                          ASN1_Tag type_tag, ASN1_Tag class_tag)
+                          ASN1_Type real_type,
+                          ASN1_Type type_tag, ASN1_Class class_tag)
          {
          return encode(bytes.data(), bytes.size(),
                        real_type, type_tag, class_tag);
@@ -161,32 +161,32 @@ class BOTAN_PUBLIC_API(2,0) DER_Encoder final
          return (*this);
          }
 
-      DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag,
+      DER_Encoder& add_object(ASN1_Type type_tag, ASN1_Class class_tag,
                               const uint8_t rep[], size_t length);
 
-      DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag,
+      DER_Encoder& add_object(ASN1_Type type_tag, ASN1_Class class_tag,
                               const std::vector<uint8_t>& rep)
          {
          return add_object(type_tag, class_tag, rep.data(), rep.size());
          }
 
-      DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag,
+      DER_Encoder& add_object(ASN1_Type type_tag, ASN1_Class class_tag,
                               const secure_vector<uint8_t>& rep)
          {
          return add_object(type_tag, class_tag, rep.data(), rep.size());
          }
 
-      DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag,
+      DER_Encoder& add_object(ASN1_Type type_tag, ASN1_Class class_tag,
                               const std::string& str);
 
-      DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag,
+      DER_Encoder& add_object(ASN1_Type type_tag, ASN1_Class class_tag,
                               uint8_t val);
 
    private:
       class DER_Sequence final
          {
          public:
-            ASN1_Tag tag_of() const;
+            uint32_t tag_of() const;
 
             void push_contents(DER_Encoder& der);
 
@@ -195,7 +195,7 @@ class BOTAN_PUBLIC_API(2,0) DER_Encoder final
             void add_bytes(const uint8_t hdr[], size_t hdr_len,
                            const uint8_t val[], size_t val_len);
 
-            DER_Sequence(ASN1_Tag, ASN1_Tag);
+            DER_Sequence(ASN1_Type, ASN1_Class);
 
             DER_Sequence(DER_Sequence&& seq)
                {
@@ -219,7 +219,8 @@ class BOTAN_PUBLIC_API(2,0) DER_Encoder final
             DER_Sequence& operator=(const DER_Sequence& seq) = default;
 
          private:
-            ASN1_Tag m_type_tag, m_class_tag;
+             ASN1_Type m_type_tag;
+             ASN1_Class m_class_tag;
             secure_vector<uint8_t> m_contents;
             std::vector< secure_vector<uint8_t> > m_set_contents;
          };
diff --git a/src/lib/kdf/prf_x942/prf_x942.cpp b/src/lib/kdf/prf_x942/prf_x942.cpp
index 93dc098cd..a9bcdfdf3 100644
--- a/src/lib/kdf/prf_x942/prf_x942.cpp
+++ b/src/lib/kdf/prf_x942/prf_x942.cpp
@@ -24,7 +24,7 @@ std::vector<uint8_t> encode_x942_int(uint32_t n)
    store_be(n, n_buf);
 
    std::vector<uint8_t> output;
-   DER_Encoder(output).encode(n_buf, 4, ASN1_Tag::OCTET_STRING);
+   DER_Encoder(output).encode(n_buf, 4, ASN1_Type::OCTET_STRING);
    return output;
    }
 
@@ -69,7 +69,7 @@ void X942_PRF::kdf(uint8_t key[], size_t key_len,
             .encode_if(salt_len != 0,
                DER_Encoder()
                   .start_explicit(0)
-                    .encode(in, ASN1_Tag::OCTET_STRING)
+                    .encode(in, ASN1_Type::OCTET_STRING)
                   .end_explicit()
                )
 
diff --git a/src/lib/pk_pad/emsa_pssr/pssr.cpp b/src/lib/pk_pad/emsa_pssr/pssr.cpp
index a4d28bafe..2920e81db 100644
--- a/src/lib/pk_pad/emsa_pssr/pssr.cpp
+++ b/src/lib/pk_pad/emsa_pssr/pssr.cpp
@@ -208,10 +208,10 @@ AlgorithmIdentifier PSSR::config_for_x509(const Private_Key& key,
    std::vector<uint8_t> parameters;
    DER_Encoder(parameters)
       .start_sequence()
-      .start_cons(ASN1_Tag(0), ASN1_Tag::CONTEXT_SPECIFIC).encode(hash_id).end_cons()
-      .start_cons(ASN1_Tag(1), ASN1_Tag::CONTEXT_SPECIFIC).encode(mgf_id).end_cons()
-      .start_cons(ASN1_Tag(2), ASN1_Tag::CONTEXT_SPECIFIC).encode(m_salt_size).end_cons()
-      .start_cons(ASN1_Tag(3), ASN1_Tag::CONTEXT_SPECIFIC).encode(size_t(1)).end_cons() // trailer field
+      .start_cons(ASN1_Type(0), ASN1_Class::CONTEXT_SPECIFIC).encode(hash_id).end_cons()
+      .start_cons(ASN1_Type(1), ASN1_Class::CONTEXT_SPECIFIC).encode(mgf_id).end_cons()
+      .start_cons(ASN1_Type(2), ASN1_Class::CONTEXT_SPECIFIC).encode(m_salt_size).end_cons()
+      .start_cons(ASN1_Type(3), ASN1_Class::CONTEXT_SPECIFIC).encode(size_t(1)).end_cons() // trailer field
       .end_cons();
 
    // hardcoded as RSA is the only valid algorithm for EMSA4 at the moment
diff --git a/src/lib/prov/openssl/openssl_ec.cpp b/src/lib/prov/openssl/openssl_ec.cpp
index 6030256be..5229952dc 100644
--- a/src/lib/prov/openssl/openssl_ec.cpp
+++ b/src/lib/prov/openssl/openssl_ec.cpp
@@ -50,12 +50,12 @@ secure_vector<uint8_t> PKCS8_for_openssl(const EC_PrivateKey& ec)
    return DER_Encoder()
      .start_sequence()
         .encode(static_cast<size_t>(1))
-        .encode(BigInt::encode_1363(priv_key, priv_key.bytes()), ASN1_Tag::OCTET_STRING)
-      .start_cons(ASN1_Tag(0), ASN1_Tag::PRIVATE)
+        .encode(BigInt::encode_1363(priv_key, priv_key.bytes()), ASN1_Type::OCTET_STRING)
+      .start_cons(ASN1_Type(0), ASN1_Class::EXPLICIT_CONTEXT_SPECIFIC)
       .raw_bytes(ec.domain().DER_encode(EC_Group_Encoding::NamedCurve))
       .end_cons()
-      .start_cons(ASN1_Tag(1), ASN1_Tag::PRIVATE)
-      .encode(pub_key.encode(PointGFp::UNCOMPRESSED), ASN1_Tag::BIT_STRING)
+      .start_cons(ASN1_Type(1), ASN1_Class::EXPLICIT_CONTEXT_SPECIFIC)
+      .encode(pub_key.encode(PointGFp::UNCOMPRESSED), ASN1_Type::BIT_STRING)
       .end_cons()
       .end_cons()
       .get_contents();
diff --git a/src/lib/prov/pkcs11/p11_ecc_key.cpp b/src/lib/prov/pkcs11/p11_ecc_key.cpp
index b1c8da6dc..dddf3a0c4 100644
--- a/src/lib/prov/pkcs11/p11_ecc_key.cpp
+++ b/src/lib/prov/pkcs11/p11_ecc_key.cpp
@@ -21,7 +21,7 @@ namespace {
 PointGFp decode_public_point(const secure_vector<uint8_t>& ec_point_data, const EC_Group& group)
    {
    secure_vector<uint8_t> ec_point;
-   BER_Decoder(ec_point_data).decode(ec_point, ASN1_Tag::OCTET_STRING);
+   BER_Decoder(ec_point_data).decode(ec_point, ASN1_Type::OCTET_STRING);
    return group.OS2ECP(ec_point);
    }
 }
@@ -55,7 +55,7 @@ PKCS11_EC_PublicKey::PKCS11_EC_PublicKey(Session& session, const EC_PublicKeyImp
    m_domain_params = EC_Group(props.ec_params());
 
    secure_vector<uint8_t> ec_point;
-   BER_Decoder(props.ec_point()).decode(ec_point, ASN1_Tag::OCTET_STRING);
+   BER_Decoder(props.ec_point()).decode(ec_point, ASN1_Type::OCTET_STRING);
    m_public_key = m_domain_params.OS2ECP(ec_point);
    m_domain_encoding = EC_Group_Encoding::Explicit;
    }
diff --git a/src/lib/prov/pkcs11/p11_ecdh.cpp b/src/lib/prov/pkcs11/p11_ecdh.cpp
index 5e4a15a0d..d4ca30caa 100644
--- a/src/lib/prov/pkcs11/p11_ecdh.cpp
+++ b/src/lib/prov/pkcs11/p11_ecdh.cpp
@@ -60,7 +60,7 @@ class PKCS11_ECDH_KA_Operation final : public PK_Ops::Key_Agreement
          std::vector<uint8_t> der_encoded_other_key;
          if(m_key.point_encoding() == PublicPointEncoding::Der)
             {
-            DER_Encoder(der_encoded_other_key).encode(other_key, other_key_len, ASN1_Tag::OCTET_STRING);
+            DER_Encoder(der_encoded_other_key).encode(other_key, other_key_len, ASN1_Type::OCTET_STRING);
             m_mechanism.set_ecdh_other_key(der_encoded_other_key.data(), der_encoded_other_key.size());
             }
          else
diff --git a/src/lib/pubkey/curve25519/curve25519.cpp b/src/lib/pubkey/curve25519/curve25519.cpp
index 7c562cb6a..77da9f834 100644
--- a/src/lib/pubkey/curve25519/curve25519.cpp
+++ b/src/lib/pubkey/curve25519/curve25519.cpp
@@ -80,7 +80,7 @@ Curve25519_PrivateKey::Curve25519_PrivateKey(RandomNumberGenerator& rng)
 Curve25519_PrivateKey::Curve25519_PrivateKey(const AlgorithmIdentifier&,
                                              const secure_vector<uint8_t>& key_bits)
    {
-   BER_Decoder(key_bits).decode(m_private, ASN1_Tag::OCTET_STRING).discard_remaining();
+   BER_Decoder(key_bits).decode(m_private, ASN1_Type::OCTET_STRING).discard_remaining();
 
    size_check(m_private.size(), "private key");
    m_public.resize(32);
@@ -94,7 +94,7 @@ std::unique_ptr<Public_Key> Curve25519_PrivateKey::public_key() const
 
 secure_vector<uint8_t> Curve25519_PrivateKey::private_key_bits() const
    {
-   return DER_Encoder().encode(m_private, ASN1_Tag::OCTET_STRING).get_contents();
+   return DER_Encoder().encode(m_private, ASN1_Type::OCTET_STRING).get_contents();
    }
 
 bool Curve25519_PrivateKey::check_key(RandomNumberGenerator&, bool) const
diff --git a/src/lib/pubkey/ec_group/ec_group.cpp b/src/lib/pubkey/ec_group/ec_group.cpp
index 4509bc740..245b216ea 100644
--- a/src/lib/pubkey/ec_group/ec_group.cpp
+++ b/src/lib/pubkey/ec_group/ec_group.cpp
@@ -299,17 +299,17 @@ std::shared_ptr<EC_Group_Data> EC_Group::BER_decode_EC_group(const uint8_t bits[
    BER_Decoder ber(bits, len);
    BER_Object obj = ber.get_next_object();
 
-   if(obj.type() == ASN1_Tag::NULL_TAG)
+   if(obj.type() == ASN1_Type::NULL_TAG)
       {
       throw Decoding_Error("Cannot handle ImplicitCA ECC parameters");
       }
-   else if(obj.type() == ASN1_Tag::OBJECT_ID)
+   else if(obj.type() == ASN1_Type::OBJECT_ID)
       {
       OID dom_par_oid;
       BER_Decoder(bits, len).decode(dom_par_oid);
       return ec_group_data().lookup(dom_par_oid);
       }
-   else if(obj.type() == ASN1_Tag::SEQUENCE)
+   else if(obj.type() == ASN1_Type::SEQUENCE)
       {
       BigInt p, a, b, order, cofactor;
       std::vector<uint8_t> base_pt;
@@ -326,9 +326,9 @@ std::shared_ptr<EC_Group_Data> EC_Group::BER_decode_EC_group(const uint8_t bits[
            .start_sequence()
              .decode_octet_string_bigint(a)
              .decode_octet_string_bigint(b)
-             .decode_optional_string(seed, ASN1_Tag::BIT_STRING, ASN1_Tag::BIT_STRING)
+             .decode_optional_string(seed, ASN1_Type::BIT_STRING, ASN1_Type::BIT_STRING)
            .end_cons()
-           .decode(base_pt, ASN1_Tag::OCTET_STRING)
+           .decode(base_pt, ASN1_Type::OCTET_STRING)
            .decode(order)
            .decode(cofactor)
          .end_cons()
@@ -627,11 +627,11 @@ EC_Group::DER_encode(EC_Group_Encoding form) const
             .end_cons()
             .start_sequence()
                .encode(BigInt::encode_1363(get_a(), p_bytes),
-                       ASN1_Tag::OCTET_STRING)
+                       ASN1_Type::OCTET_STRING)
                .encode(BigInt::encode_1363(get_b(), p_bytes),
-                       ASN1_Tag::OCTET_STRING)
+                       ASN1_Type::OCTET_STRING)
             .end_cons()
-              .encode(get_base_point().encode(PointGFp::UNCOMPRESSED), ASN1_Tag::OCTET_STRING)
+              .encode(get_base_point().encode(PointGFp::UNCOMPRESSED), ASN1_Type::OCTET_STRING)
             .encode(get_order())
             .encode(get_cofactor())
          .end_cons();
diff --git a/src/lib/pubkey/ecc_key/ecc_key.cpp b/src/lib/pubkey/ecc_key/ecc_key.cpp
index 310c568d3..559c42dad 100644
--- a/src/lib/pubkey/ecc_key/ecc_key.cpp
+++ b/src/lib/pubkey/ecc_key/ecc_key.cpp
@@ -145,9 +145,9 @@ secure_vector<uint8_t> EC_PrivateKey::private_key_bits() const
    return DER_Encoder()
       .start_sequence()
          .encode(static_cast<size_t>(1))
-         .encode(BigInt::encode_1363(m_private_key, m_private_key.bytes()), ASN1_Tag::OCTET_STRING)
-         .start_cons(ASN1_Tag(1), ASN1_Tag::PRIVATE)
-            .encode(m_public_key.encode(PointGFp::Compression_Type::UNCOMPRESSED), ASN1_Tag::BIT_STRING)
+         .encode(BigInt::encode_1363(m_private_key, m_private_key.bytes()), ASN1_Type::OCTET_STRING)
+         .start_cons(ASN1_Type(1), ASN1_Class::EXPLICIT_CONTEXT_SPECIFIC)
+            .encode(m_public_key.encode(PointGFp::Compression_Type::UNCOMPRESSED), ASN1_Type::BIT_STRING)
          .end_cons()
       .end_cons()
       .get_contents();
@@ -167,8 +167,8 @@ EC_PrivateKey::EC_PrivateKey(const AlgorithmIdentifier& alg_id,
       .start_sequence()
          .decode_and_check<size_t>(1, "Unknown version code for ECC key")
          .decode_octet_string_bigint(m_private_key)
-         .decode_optional(key_parameters, ASN1_Tag(0), ASN1_Tag::PRIVATE)
-         .decode_optional_string(public_key_bits, ASN1_Tag::BIT_STRING, 1, ASN1_Tag::PRIVATE)
+         .decode_optional(key_parameters, ASN1_Type(0), ASN1_Class::EXPLICIT_CONTEXT_SPECIFIC)
+         .decode_optional_string(public_key_bits, ASN1_Type::BIT_STRING, 1, ASN1_Class::EXPLICIT_CONTEXT_SPECIFIC)
       .end_cons();
 
    if(public_key_bits.empty())
diff --git a/src/lib/pubkey/ed25519/ed25519_key.cpp b/src/lib/pubkey/ed25519/ed25519_key.cpp
index 464d6fdba..be1d56057 100644
--- a/src/lib/pubkey/ed25519/ed25519_key.cpp
+++ b/src/lib/pubkey/ed25519/ed25519_key.cpp
@@ -78,7 +78,7 @@ Ed25519_PrivateKey::Ed25519_PrivateKey(const AlgorithmIdentifier&,
                                        const secure_vector<uint8_t>& key_bits)
    {
    secure_vector<uint8_t> bits;
-   BER_Decoder(key_bits).decode(bits, ASN1_Tag::OCTET_STRING).discard_remaining();
+   BER_Decoder(key_bits).decode(bits, ASN1_Type::OCTET_STRING).discard_remaining();
 
    if(bits.size() != 32)
       throw Decoding_Error("Invalid size for Ed25519 private key");
@@ -95,7 +95,7 @@ std::unique_ptr<Public_Key> Ed25519_PrivateKey::public_key() const
 secure_vector<uint8_t> Ed25519_PrivateKey::private_key_bits() const
    {
    secure_vector<uint8_t> bits(&m_private[0], &m_private[32]);
-   return DER_Encoder().encode(bits, ASN1_Tag::OCTET_STRING).get_contents();
+   return DER_Encoder().encode(bits, ASN1_Type::OCTET_STRING).get_contents();
    }
 
 bool Ed25519_PrivateKey::check_key(RandomNumberGenerator&, bool) const
diff --git a/src/lib/pubkey/gost_3410/gost_3410.cpp b/src/lib/pubkey/gost_3410/gost_3410.cpp
index 6b813963c..a5bf4f252 100644
--- a/src/lib/pubkey/gost_3410/gost_3410.cpp
+++ b/src/lib/pubkey/gost_3410/gost_3410.cpp
@@ -36,7 +36,7 @@ std::vector<uint8_t> GOST_3410_PublicKey::public_key_bits() const
       }
 
    std::vector<uint8_t> output;
-   DER_Encoder(output).encode(bits, ASN1_Tag::OCTET_STRING);
+   DER_Encoder(output).encode(bits, ASN1_Type::OCTET_STRING);
    return output;
    }
 
@@ -78,7 +78,7 @@ GOST_3410_PublicKey::GOST_3410_PublicKey(const AlgorithmIdentifier& alg_id,
                            std::to_string(p_bits));
 
    secure_vector<uint8_t> bits;
-   BER_Decoder(key_bits).decode(bits, ASN1_Tag::OCTET_STRING);
+   BER_Decoder(key_bits).decode(bits, ASN1_Type::OCTET_STRING);
 
    const size_t part_size = bits.size() / 2;
 
diff --git a/src/lib/pubkey/mce/mceliece_key.cpp b/src/lib/pubkey/mce/mceliece_key.cpp
index ed9654e0b..3e81b64e9 100644
--- a/src/lib/pubkey/mce/mceliece_key.cpp
+++ b/src/lib/pubkey/mce/mceliece_key.cpp
@@ -93,7 +93,7 @@ std::vector<uint8_t> McEliece_PublicKey::public_key_bits() const
          .encode(static_cast<size_t>(get_code_length()))
          .encode(static_cast<size_t>(get_t()))
          .end_cons()
-      .encode(m_public_matrix, ASN1_Tag::OCTET_STRING)
+      .encode(m_public_matrix, ASN1_Type::OCTET_STRING)
       .end_cons();
    return output;
    }
@@ -118,7 +118,7 @@ McEliece_PublicKey::McEliece_PublicKey(const std::vector<uint8_t>& key_bits)
       .decode(n)
       .decode(t)
       .end_cons()
-      .decode(m_public_matrix, ASN1_Tag::OCTET_STRING)
+      .decode(m_public_matrix, ASN1_Type::OCTET_STRING)
       .end_cons();
    m_t = t;
    m_code_length = n;
@@ -132,12 +132,12 @@ secure_vector<uint8_t> McEliece_PrivateKey::private_key_bits() const
       .encode(static_cast<size_t>(get_code_length()))
       .encode(static_cast<size_t>(get_t()))
       .end_cons()
-      .encode(m_public_matrix, ASN1_Tag::OCTET_STRING)
-      .encode(m_g[0].encode(), ASN1_Tag::OCTET_STRING); // g as octet string
+      .encode(m_public_matrix, ASN1_Type::OCTET_STRING)
+      .encode(m_g[0].encode(), ASN1_Type::OCTET_STRING); // g as octet string
    enc.start_sequence();
    for(size_t i = 0; i < m_sqrtmod.size(); i++)
       {
-      enc.encode(m_sqrtmod[i].encode(), ASN1_Tag::OCTET_STRING);
+      enc.encode(m_sqrtmod[i].encode(), ASN1_Type::OCTET_STRING);
       }
    enc.end_cons();
    secure_vector<uint8_t> enc_support;
@@ -147,7 +147,7 @@ secure_vector<uint8_t> McEliece_PrivateKey::private_key_bits() const
       enc_support.push_back(get_byte(0, Linv));
       enc_support.push_back(get_byte(1, Linv));
       }
-   enc.encode(enc_support, ASN1_Tag::OCTET_STRING);
+   enc.encode(enc_support, ASN1_Type::OCTET_STRING);
    secure_vector<uint8_t> enc_H;
    for(uint32_t coef : m_coeffs)
       {
@@ -156,7 +156,7 @@ secure_vector<uint8_t> McEliece_PrivateKey::private_key_bits() const
       enc_H.push_back(get_byte(2, coef));
       enc_H.push_back(get_byte(3, coef));
       }
-   enc.encode(enc_H, ASN1_Tag::OCTET_STRING);
+   enc.encode(enc_H, ASN1_Type::OCTET_STRING);
    enc.end_cons();
    return enc.get_contents();
    }
@@ -189,8 +189,8 @@ McEliece_PrivateKey::McEliece_PrivateKey(const secure_vector<uint8_t>& key_bits)
       .decode(n)
       .decode(t)
       .end_cons()
-      .decode(m_public_matrix, ASN1_Tag::OCTET_STRING)
-      .decode(enc_g, ASN1_Tag::OCTET_STRING);
+      .decode(m_public_matrix, ASN1_Type::OCTET_STRING)
+      .decode(enc_g, ASN1_Type::OCTET_STRING);
 
    if(t == 0 || n == 0)
       throw Decoding_Error("invalid McEliece parameters");
@@ -211,7 +211,7 @@ McEliece_PrivateKey::McEliece_PrivateKey(const secure_vector<uint8_t>& key_bits)
    for(uint32_t i = 0; i < t/2; i++)
       {
       secure_vector<uint8_t> sqrt_enc;
-      dec2.decode(sqrt_enc, ASN1_Tag::OCTET_STRING);
+      dec2.decode(sqrt_enc, ASN1_Type::OCTET_STRING);
       while(sqrt_enc.size() < (t*2))
          {
          // ensure that the length is always t
@@ -226,7 +226,7 @@ McEliece_PrivateKey::McEliece_PrivateKey(const secure_vector<uint8_t>& key_bits)
       }
    secure_vector<uint8_t> enc_support;
    BER_Decoder dec3 = dec2.end_cons()
-      .decode(enc_support, ASN1_Tag::OCTET_STRING);
+      .decode(enc_support, ASN1_Type::OCTET_STRING);
    if(enc_support.size() % 2)
       {
       throw Decoding_Error("encoded support has odd length");
@@ -241,7 +241,7 @@ McEliece_PrivateKey::McEliece_PrivateKey(const secure_vector<uint8_t>& key_bits)
       m_Linv.push_back(el);
       }
    secure_vector<uint8_t> enc_H;
-   dec3.decode(enc_H, ASN1_Tag::OCTET_STRING)
+   dec3.decode(enc_H, ASN1_Type::OCTET_STRING)
       .end_cons();
    if(enc_H.size() % 4)
       {
diff --git a/src/lib/pubkey/pbes2/pbes2.cpp b/src/lib/pubkey/pbes2/pbes2.cpp
index 1b2da796b..11f17605d 100644
--- a/src/lib/pubkey/pbes2/pbes2.cpp
+++ b/src/lib/pubkey/pbes2/pbes2.cpp
@@ -42,10 +42,10 @@ SymmetricKey derive_key(const std::string& passphrase,
       AlgorithmIdentifier prf_algo;
       BER_Decoder(kdf_algo.get_parameters())
          .start_sequence()
-         .decode(salt, ASN1_Tag::OCTET_STRING)
+         .decode(salt, ASN1_Type::OCTET_STRING)
          .decode(iterations)
-         .decode_optional(key_length, ASN1_Tag::INTEGER, ASN1_Tag::UNIVERSAL)
-         .decode_optional(prf_algo, ASN1_Tag::SEQUENCE, ASN1_Tag::CONSTRUCTED,
+         .decode_optional(key_length, ASN1_Type::INTEGER, ASN1_Class::UNIVERSAL)
+         .decode_optional(prf_algo, ASN1_Type::SEQUENCE, ASN1_Class::CONSTRUCTED,
                           AlgorithmIdentifier("HMAC(SHA-160)",
                                               AlgorithmIdentifier::USE_NULL_PARAM))
          .end_cons();
@@ -70,11 +70,11 @@ SymmetricKey derive_key(const std::string& passphrase,
       AlgorithmIdentifier prf_algo;
       BER_Decoder(kdf_algo.get_parameters())
          .start_sequence()
-         .decode(salt, ASN1_Tag::OCTET_STRING)
+         .decode(salt, ASN1_Type::OCTET_STRING)
          .decode(N)
          .decode(r)
          .decode(p)
-         .decode_optional(key_length, ASN1_Tag::INTEGER, ASN1_Tag::UNIVERSAL)
+         .decode_optional(key_length, ASN1_Type::INTEGER, ASN1_Class::UNIVERSAL)
          .end_cons();
 
       if(key_length == 0)
@@ -135,7 +135,7 @@ secure_vector<uint8_t> derive_key(const std::string& passphrase,
       std::vector<uint8_t> scrypt_params;
       DER_Encoder(scrypt_params)
          .start_sequence()
-            .encode(salt, ASN1_Tag::OCTET_STRING)
+            .encode(salt, ASN1_Type::OCTET_STRING)
             .encode(N)
             .encode(r)
             .encode(p)
@@ -183,7 +183,7 @@ secure_vector<uint8_t> derive_key(const std::string& passphrase,
 
       DER_Encoder(pbkdf2_params)
          .start_sequence()
-            .encode(salt, ASN1_Tag::OCTET_STRING)
+            .encode(salt, ASN1_Type::OCTET_STRING)
             .encode(iterations)
             .encode(key_length)
             .encode_if(prf != "HMAC(SHA-160)",
@@ -240,7 +240,7 @@ pbes2_encrypt_shared(const secure_vector<uint8_t>& key_bits,
    enc->finish(ctext);
 
    std::vector<uint8_t> encoded_iv;
-   DER_Encoder(encoded_iv).encode(iv, ASN1_Tag::OCTET_STRING);
+   DER_Encoder(encoded_iv).encode(iv, ASN1_Type::OCTET_STRING);
 
    std::vector<uint8_t> pbes2_params;
    DER_Encoder(pbes2_params)
@@ -320,7 +320,7 @@ pbes2_decrypt(const secure_vector<uint8_t>& key_bits,
       throw Decoding_Error("PBE-PKCS5 v2.0: Don't know param format for " + cipher);
 
    secure_vector<uint8_t> iv;
-   BER_Decoder(enc_algo.get_parameters()).decode(iv, ASN1_Tag::OCTET_STRING).verify_end();
+   BER_Decoder(enc_algo.get_parameters()).decode(iv, ASN1_Type::OCTET_STRING).verify_end();
 
    std::unique_ptr<Cipher_Mode> dec = Cipher_Mode::create(cipher, DECRYPTION);
    if(!dec)
diff --git a/src/lib/pubkey/pk_keys.cpp b/src/lib/pubkey/pk_keys.cpp
index e1094663e..777b868a5 100644
--- a/src/lib/pubkey/pk_keys.cpp
+++ b/src/lib/pubkey/pk_keys.cpp
@@ -41,7 +41,7 @@ std::vector<uint8_t> Public_Key::subject_public_key() const
 
    DER_Encoder(output).start_sequence()
          .encode(algorithm_identifier())
-         .encode(public_key_bits(), ASN1_Tag::BIT_STRING)
+         .encode(public_key_bits(), ASN1_Type::BIT_STRING)
       .end_cons();
 
    return output;
@@ -66,7 +66,7 @@ secure_vector<uint8_t> Private_Key::private_key_info() const
          .start_sequence()
             .encode(PKCS8_VERSION)
             .encode(pkcs8_algorithm_identifier())
-            .encode(private_key_bits(), ASN1_Tag::OCTET_STRING)
+            .encode(private_key_bits(), ASN1_Type::OCTET_STRING)
          .end_cons()
       .get_contents();
    }
diff --git a/src/lib/pubkey/pkcs8.cpp b/src/lib/pubkey/pkcs8.cpp
index fd210e6ce..99ffa9263 100644
--- a/src/lib/pubkey/pkcs8.cpp
+++ b/src/lib/pubkey/pkcs8.cpp
@@ -36,7 +36,7 @@ secure_vector<uint8_t> PKCS8_extract(DataSource& source,
    BER_Decoder(source)
       .start_sequence()
          .decode(pbe_alg_id)
-         .decode(key_data, ASN1_Tag::OCTET_STRING)
+         .decode(key_data, ASN1_Type::OCTET_STRING)
       .verify_end();
 
    return key_data;
@@ -120,7 +120,7 @@ secure_vector<uint8_t> PKCS8_decode(
          .start_sequence()
             .decode_and_check<size_t>(0, "Unknown PKCS #8 version number")
             .decode(pk_alg_id)
-            .decode(key, ASN1_Tag::OCTET_STRING)
+            .decode(key, ASN1_Type::OCTET_STRING)
             .discard_remaining()
          .end_cons();
       }
@@ -205,7 +205,7 @@ std::vector<uint8_t> BER_encode(const Private_Key& key,
    DER_Encoder der(output);
    der.start_sequence()
          .encode(pbe_info.first)
-         .encode(pbe_info.second, ASN1_Tag::OCTET_STRING)
+         .encode(pbe_info.second, ASN1_Type::OCTET_STRING)
       .end_cons();
 
    return output;
@@ -253,7 +253,7 @@ std::vector<uint8_t> BER_encode_encrypted_pbkdf_iter(const Private_Key& key,
    DER_Encoder der(output);
    der.start_sequence()
          .encode(pbe_info.first)
-         .encode(pbe_info.second, ASN1_Tag::OCTET_STRING)
+         .encode(pbe_info.second, ASN1_Type::OCTET_STRING)
       .end_cons();
 
    return output;
@@ -302,7 +302,7 @@ std::vector<uint8_t> BER_encode_encrypted_pbkdf_msec(const Private_Key& key,
    DER_Encoder(output)
       .start_sequence()
          .encode(pbe_info.first)
-         .encode(pbe_info.second, ASN1_Tag::OCTET_STRING)
+         .encode(pbe_info.second, ASN1_Type::OCTET_STRING)
       .end_cons();
 
    return output;
diff --git a/src/lib/pubkey/sm2/sm2_enc.cpp b/src/lib/pubkey/sm2/sm2_enc.cpp
index 6be10d416..cc349ff99 100644
--- a/src/lib/pubkey/sm2/sm2_enc.cpp
+++ b/src/lib/pubkey/sm2/sm2_enc.cpp
@@ -94,8 +94,8 @@ class SM2_Encryption_Operation final : public PK_Ops::Encryption
             .start_sequence()
             .encode(x1)
             .encode(y1)
-            .encode(C3, ASN1_Tag::OCTET_STRING)
-            .encode(masked_msg, ASN1_Tag::OCTET_STRING)
+            .encode(C3, ASN1_Type::OCTET_STRING)
+            .encode(masked_msg, ASN1_Type::OCTET_STRING)
             .end_cons()
             .get_contents();
          }
@@ -163,8 +163,8 @@ class SM2_Decryption_Operation final : public PK_Ops::Decryption
             .start_sequence()
             .decode(x1)
             .decode(y1)
-            .decode(C3, ASN1_Tag::OCTET_STRING)
-            .decode(masked_msg, ASN1_Tag::OCTET_STRING)
+            .decode(C3, ASN1_Type::OCTET_STRING)
+            .decode(masked_msg, ASN1_Type::OCTET_STRING)
             .end_cons()
             .verify_end();
 
@@ -173,8 +173,8 @@ class SM2_Decryption_Operation final : public PK_Ops::Decryption
             .start_sequence()
             .encode(x1)
             .encode(y1)
-            .encode(C3, ASN1_Tag::OCTET_STRING)
-            .encode(masked_msg, ASN1_Tag::OCTET_STRING)
+            .encode(C3, ASN1_Type::OCTET_STRING)
+            .encode(masked_msg, ASN1_Type::OCTET_STRING)
             .end_cons();
 
          if(recode_ctext.size() != ciphertext_len)
diff --git a/src/lib/pubkey/x509_key.cpp b/src/lib/pubkey/x509_key.cpp
index 5ba689fc5..c4ada1c6f 100644
--- a/src/lib/pubkey/x509_key.cpp
+++ b/src/lib/pubkey/x509_key.cpp
@@ -39,7 +39,7 @@ Public_Key* load_key(DataSource& source)
          BER_Decoder(source)
             .start_sequence()
             .decode(alg_id)
-            .decode(key_bits, ASN1_Tag::BIT_STRING)
+            .decode(key_bits, ASN1_Type::BIT_STRING)
          .end_cons();
          }
       else
@@ -51,7 +51,7 @@ Public_Key* load_key(DataSource& source)
          BER_Decoder(ber)
             .start_sequence()
             .decode(alg_id)
-            .decode(key_bits, ASN1_Tag::BIT_STRING)
+            .decode(key_bits, ASN1_Type::BIT_STRING)
          .end_cons();
          }
 
diff --git a/src/lib/pubkey/xmss/xmss_privatekey.cpp b/src/lib/pubkey/xmss/xmss_privatekey.cpp
index ee5a15bdd..7a075cd75 100644
--- a/src/lib/pubkey/xmss/xmss_privatekey.cpp
+++ b/src/lib/pubkey/xmss/xmss_privatekey.cpp
@@ -37,7 +37,7 @@ secure_vector<uint8_t> extract_raw_key(const secure_vector<uint8_t>& key_bits)
    secure_vector<uint8_t> raw_key;
    try
       {
-      BER_Decoder(key_bits).decode(raw_key, ASN1_Tag::OCTET_STRING);
+      BER_Decoder(key_bits).decode(raw_key, ASN1_Type::OCTET_STRING);
       }
    catch(Decoding_Error&)
       {
@@ -318,7 +318,7 @@ XMSS_PrivateKey::tree_hash_subtree(secure_vector<uint8_t>& result,
 
 secure_vector<uint8_t> XMSS_PrivateKey::private_key_bits() const
    {
-   return DER_Encoder().encode(raw_private_key(), ASN1_Tag::OCTET_STRING).get_contents();
+   return DER_Encoder().encode(raw_private_key(), ASN1_Type::OCTET_STRING).get_contents();
    }
 
 std::shared_ptr<Atomic<size_t>>
diff --git a/src/lib/pubkey/xmss/xmss_publickey.cpp b/src/lib/pubkey/xmss/xmss_publickey.cpp
index 0ec34cde0..845747399 100644
--- a/src/lib/pubkey/xmss/xmss_publickey.cpp
+++ b/src/lib/pubkey/xmss/xmss_publickey.cpp
@@ -30,7 +30,7 @@ std::vector<uint8_t> extract_raw_key(const std::vector<uint8_t>& key_bits)
    std::vector<uint8_t> raw_key;
    try
       {
-      BER_Decoder(key_bits).decode(raw_key, ASN1_Tag::OCTET_STRING);
+      BER_Decoder(key_bits).decode(raw_key, ASN1_Type::OCTET_STRING);
       }
    catch(Decoding_Error&)
       {
@@ -122,7 +122,7 @@ std::vector<uint8_t> XMSS_PublicKey::raw_public_key() const
 std::vector<uint8_t> XMSS_PublicKey::public_key_bits() const
    {
    std::vector<uint8_t> output;
-   DER_Encoder(output).encode(raw_public_key(), ASN1_Tag::OCTET_STRING);
+   DER_Encoder(output).encode(raw_public_key(), ASN1_Type::OCTET_STRING);
    return output;
    }
 
diff --git a/src/lib/tls/tls_session.cpp b/src/lib/tls/tls_session.cpp
index 4df079655..54f7d73d9 100644
--- a/src/lib/tls/tls_session.cpp
+++ b/src/lib/tls/tls_session.cpp
@@ -77,16 +77,16 @@ Session::Session(const uint8_t ber[], size_t ber_len)
         .decode_integer_type(start_time)
         .decode_integer_type(major_version)
         .decode_integer_type(minor_version)
-        .decode(m_identifier, ASN1_Tag::OCTET_STRING)
-        .decode(m_session_ticket, ASN1_Tag::OCTET_STRING)
+        .decode(m_identifier, ASN1_Type::OCTET_STRING)
+        .decode(m_session_ticket, ASN1_Type::OCTET_STRING)
         .decode_integer_type(m_ciphersuite)
         .decode_integer_type(compression_method)
         .decode_integer_type(side_code)
         .decode_integer_type(fragment_size)
         .decode(m_extended_master_secret)
         .decode(m_encrypt_then_mac)
-        .decode(m_master_secret, ASN1_Tag::OCTET_STRING)
-        .decode(peer_cert_bits, ASN1_Tag::OCTET_STRING)
+        .decode(m_master_secret, ASN1_Type::OCTET_STRING)
+        .decode(peer_cert_bits, ASN1_Type::OCTET_STRING)
         .decode(server_hostname)
         .decode(server_service)
         .decode(server_port)
@@ -143,20 +143,20 @@ secure_vector<uint8_t> Session::DER_encode() const
          .encode(static_cast<size_t>(std::chrono::system_clock::to_time_t(m_start_time)))
          .encode(static_cast<size_t>(m_version.major_version()))
          .encode(static_cast<size_t>(m_version.minor_version()))
-         .encode(m_identifier, ASN1_Tag::OCTET_STRING)
-         .encode(m_session_ticket, ASN1_Tag::OCTET_STRING)
+         .encode(m_identifier, ASN1_Type::OCTET_STRING)
+         .encode(m_session_ticket, ASN1_Type::OCTET_STRING)
          .encode(static_cast<size_t>(m_ciphersuite))
          .encode(static_cast<size_t>(/*old compression method*/0))
          .encode(static_cast<size_t>(m_connection_side))
          .encode(static_cast<size_t>(/*old fragment size*/0))
          .encode(m_extended_master_secret)
          .encode(m_encrypt_then_mac)
-         .encode(m_master_secret, ASN1_Tag::OCTET_STRING)
-         .encode(peer_cert_bits, ASN1_Tag::OCTET_STRING)
-         .encode(ASN1_String(m_server_info.hostname(), ASN1_Tag::UTF8_STRING))
-         .encode(ASN1_String(m_server_info.service(), ASN1_Tag::UTF8_STRING))
+         .encode(m_master_secret, ASN1_Type::OCTET_STRING)
+         .encode(peer_cert_bits, ASN1_Type::OCTET_STRING)
+         .encode(ASN1_String(m_server_info.hostname(), ASN1_Type::UTF8_STRING))
+         .encode(ASN1_String(m_server_info.service(), ASN1_Type::UTF8_STRING))
          .encode(static_cast<size_t>(m_server_info.port()))
-         .encode(ASN1_String("", ASN1_Tag::UTF8_STRING)) // old srp identifier
+         .encode(ASN1_String("", ASN1_Type::UTF8_STRING)) // old srp identifier
          .encode(static_cast<size_t>(m_srtp_profile))
       .end_cons()
    .get_contents();
diff --git a/src/lib/x509/asn1_alt_name.cpp b/src/lib/x509/asn1_alt_name.cpp
index 8fa67a57b..fa54084d7 100644
--- a/src/lib/x509/asn1_alt_name.cpp
+++ b/src/lib/x509/asn1_alt_name.cpp
@@ -53,7 +53,7 @@ void AlternativeName::add_attribute(const std::string& type,
 * Add an OtherName field
 */
 void AlternativeName::add_othername(const OID& oid, const std::string& value,
-                                    ASN1_Tag type)
+                                    ASN1_Type type)
    {
    if(value.empty())
       return;
@@ -133,7 +133,7 @@ namespace {
 */
 void encode_entries(DER_Encoder& encoder,
                     const std::multimap<std::string, std::string>& attr,
-                    const std::string& type, ASN1_Tag tagging)
+                    const std::string& type, ASN1_Type tagging)
    {
    auto range = attr.equal_range(type);
 
@@ -141,15 +141,15 @@ void encode_entries(DER_Encoder& encoder,
       {
       if(type == "RFC822" || type == "DNS" || type == "URI")
          {
-         ASN1_String asn1_string(i->second, ASN1_Tag::IA5_STRING);
-         encoder.add_object(tagging, ASN1_Tag::CONTEXT_SPECIFIC, asn1_string.value());
+         ASN1_String asn1_string(i->second, ASN1_Type::IA5_STRING);
+         encoder.add_object(tagging, ASN1_Class::CONTEXT_SPECIFIC, asn1_string.value());
          }
       else if(type == "IP")
          {
          const uint32_t ip = string_to_ipv4(i->second);
          uint8_t ip_buf[4] = { 0 };
          store_be(ip, ip_buf);
-         encoder.add_object(tagging, ASN1_Tag::CONTEXT_SPECIFIC, ip_buf, 4);
+         encoder.add_object(tagging, ASN1_Class::CONTEXT_SPECIFIC, ip_buf, 4);
          }
       else if (type == "DN")
          {
@@ -170,11 +170,11 @@ void AlternativeName::encode_into(DER_Encoder& der) const
    {
    der.start_sequence();
 
-   encode_entries(der, m_alt_info, "RFC822", ASN1_Tag(1));
-   encode_entries(der, m_alt_info, "DNS", ASN1_Tag(2));
-   encode_entries(der, m_alt_info, "DN", ASN1_Tag(4));
-   encode_entries(der, m_alt_info, "URI", ASN1_Tag(6));
-   encode_entries(der, m_alt_info, "IP", ASN1_Tag(7));
+   encode_entries(der, m_alt_info, "RFC822", ASN1_Type(1));
+   encode_entries(der, m_alt_info, "DNS", ASN1_Type(2));
+   encode_entries(der, m_alt_info, "DN", ASN1_Type(4));
+   encode_entries(der, m_alt_info, "URI", ASN1_Type(6));
+   encode_entries(der, m_alt_info, "IP", ASN1_Type(7));
 
    for(auto i = m_othernames.begin(); i != m_othernames.end(); ++i)
       {
@@ -202,7 +202,7 @@ void AlternativeName::decode_from(BER_Decoder& source)
       {
       BER_Object obj = names.get_next_object();
 
-      if(obj.is_a(0, ASN1_Tag::CONTEXT_SPECIFIC))
+      if(obj.is_a(0, ASN1_Class::CONTEXT_SPECIFIC))
          {
          BER_Decoder othername(obj);
 
@@ -213,7 +213,7 @@ void AlternativeName::decode_from(BER_Decoder& source)
             BER_Object othername_value_outer = othername.get_next_object();
             othername.verify_end();
 
-            if(othername_value_outer.is_a(0, ASN1_Tag::PRIVATE) == false)
+            if(othername_value_outer.is_a(0, ASN1_Class::EXPLICIT_CONTEXT_SPECIFIC) == false)
                throw Decoding_Error("Invalid tags on otherName value");
 
             BER_Decoder othername_value_inner(othername_value_outer);
@@ -221,25 +221,25 @@ void AlternativeName::decode_from(BER_Decoder& source)
             BER_Object value = othername_value_inner.get_next_object();
             othername_value_inner.verify_end();
 
-            if(ASN1_String::is_string_type(value.type()) && value.get_class() == ASN1_Tag::UNIVERSAL)
+            if(ASN1_String::is_string_type(value.type()) && value.get_class() == ASN1_Class::UNIVERSAL)
                {
                add_othername(oid, ASN1::to_string(value), value.type());
                }
             }
          }
-      if(obj.is_a(1, ASN1_Tag::CONTEXT_SPECIFIC))
+      if(obj.is_a(1, ASN1_Class::CONTEXT_SPECIFIC))
          {
          add_attribute("RFC822", ASN1::to_string(obj));
          }
-      else if(obj.is_a(2, ASN1_Tag::CONTEXT_SPECIFIC))
+      else if(obj.is_a(2, ASN1_Class::CONTEXT_SPECIFIC))
          {
          add_attribute("DNS", ASN1::to_string(obj));
          }
-      else if(obj.is_a(6, ASN1_Tag::CONTEXT_SPECIFIC))
+      else if(obj.is_a(6, ASN1_Class::CONTEXT_SPECIFIC))
          {
          add_attribute("URI", ASN1::to_string(obj));
          }
-      else if(obj.is_a(4, ASN1_Tag::CONTEXT_SPECIFIC | ASN1_Tag::CONSTRUCTED))
+      else if(obj.is_a(4, ASN1_Class::CONTEXT_SPECIFIC | ASN1_Class::CONSTRUCTED))
          {
          BER_Decoder dec(obj);
          X509_DN dn;
@@ -250,7 +250,7 @@ void AlternativeName::decode_from(BER_Decoder& source)
 
          add_attribute("DN", ss.str());
          }
-      else if(obj.is_a(7, ASN1_Tag::CONTEXT_SPECIFIC))
+      else if(obj.is_a(7, ASN1_Class::CONTEXT_SPECIFIC))
          {
          if(obj.length() == 4)
             {
diff --git a/src/lib/x509/certstor_system_macos/certstor_macos.cpp b/src/lib/x509/certstor_system_macos/certstor_macos.cpp
index 9885e33a8..8283153d4 100644
--- a/src/lib/x509/certstor_system_macos/certstor_macos.cpp
+++ b/src/lib/x509/certstor_system_macos/certstor_macos.cpp
@@ -81,7 +81,7 @@ X509_DN normalize(const X509_DN& dn)
       const auto oid = rdn.first;
       auto str = rdn.second;
 
-      if(str.tagging() == ASN1_Tag::PRINTABLE_STRING)
+      if(str.tagging() == ASN1_Type::PRINTABLE_STRING)
          {
          std::string normalized;
          normalized.reserve(str.value().size());
diff --git a/src/lib/x509/name_constraint.cpp b/src/lib/x509/name_constraint.cpp
index 20f588411..d574e1327 100644
--- a/src/lib/x509/name_constraint.cpp
+++ b/src/lib/x509/name_constraint.cpp
@@ -41,22 +41,22 @@ void GeneralName::decode_from(class BER_Decoder& ber)
    {
    BER_Object obj = ber.get_next_object();
 
-   if(obj.is_a(1, ASN1_Tag::CONTEXT_SPECIFIC))
+   if(obj.is_a(1, ASN1_Class::CONTEXT_SPECIFIC))
       {
       m_type = "RFC822";
       m_name = ASN1::to_string(obj);
       }
-   else if(obj.is_a(2, ASN1_Tag::CONTEXT_SPECIFIC))
+   else if(obj.is_a(2, ASN1_Class::CONTEXT_SPECIFIC))
       {
       m_type = "DNS";
       m_name = ASN1::to_string(obj);
       }
-   else if(obj.is_a(6, ASN1_Tag::CONTEXT_SPECIFIC))
+   else if(obj.is_a(6, ASN1_Class::CONTEXT_SPECIFIC))
       {
       m_type = "URI";
       m_name = ASN1::to_string(obj);
       }
-   else if(obj.is_a(4, ASN1_Tag::CONTEXT_SPECIFIC | ASN1_Tag::CONSTRUCTED))
+   else if(obj.is_a(4, ASN1_Class::CONTEXT_SPECIFIC | ASN1_Class::CONSTRUCTED))
       {
       m_type = "DN";
       X509_DN dn;
@@ -68,7 +68,7 @@ void GeneralName::decode_from(class BER_Decoder& ber)
 
       m_name = ss.str();
       }
-   else if(obj.is_a(7, ASN1_Tag::CONTEXT_SPECIFIC))
+   else if(obj.is_a(7, ASN1_Class::CONTEXT_SPECIFIC))
       {
       if(obj.length() == 8)
          {
@@ -255,7 +255,7 @@ void GeneralSubtree::decode_from(class BER_Decoder& ber)
    {
    ber.start_sequence()
       .decode(m_base)
-      .decode_optional(m_minimum, ASN1_Tag(0), ASN1_Tag::CONTEXT_SPECIFIC, size_t(0))
+      .decode_optional(m_minimum, ASN1_Type(0), ASN1_Class::CONTEXT_SPECIFIC, size_t(0))
    .end_cons();
 
    if(m_minimum != 0)
diff --git a/src/lib/x509/ocsp.cpp b/src/lib/x509/ocsp.cpp
index 71d4e499c..1155c7a42 100644
--- a/src/lib/x509/ocsp.cpp
+++ b/src/lib/x509/ocsp.cpp
@@ -27,12 +27,12 @@ namespace {
 
 // TODO: should this be in a header somewhere?
 void decode_optional_list(BER_Decoder& ber,
-                          ASN1_Tag tag,
+                          ASN1_Type tag,
                           std::vector<X509_Certificate>& output)
    {
    BER_Object obj = ber.get_next_object();
 
-   if(obj.is_a(tag, ASN1_Tag::CONTEXT_SPECIFIC | ASN1_Tag::CONSTRUCTED) == false)
+   if(obj.is_a(tag, ASN1_Class::CONTEXT_SPECIFIC | ASN1_Class::CONSTRUCTED) == false)
       {
       ber.push_back(obj);
       return;
@@ -105,7 +105,7 @@ Response::Response(const uint8_t response_bits[], size_t response_bits_len) :
 
    size_t resp_status = 0;
 
-   response_outer.decode(resp_status, ASN1_Tag::ENUMERATED, ASN1_Tag::UNIVERSAL);
+   response_outer.decode(resp_status, ASN1_Type::ENUMERATED, ASN1_Class::UNIVERSAL);
 
    m_status = static_cast<Response_Status_Code>(resp_status);
 
@@ -115,7 +115,7 @@ Response::Response(const uint8_t response_bits[], size_t response_bits_len) :
    if(response_outer.more_items())
       {
       BER_Decoder response_bytes =
-         response_outer.start_cons(ASN1_Tag(0), ASN1_Tag::CONTEXT_SPECIFIC).start_sequence();
+         response_outer.start_cons(ASN1_Type(0), ASN1_Class::CONTEXT_SPECIFIC).start_sequence();
 
       response_bytes.decode_and_check(OID("1.3.6.1.5.5.7.48.1.1"),
                                       "Unknown response type in OCSP response");
@@ -127,28 +127,28 @@ Response::Response(const uint8_t response_bits[], size_t response_bits_len) :
            .raw_bytes(m_tbs_bits)
          .end_cons()
          .decode(m_sig_algo)
-         .decode(m_signature, ASN1_Tag::BIT_STRING);
-      decode_optional_list(basicresponse, ASN1_Tag(0), m_certs);
+         .decode(m_signature, ASN1_Type::BIT_STRING);
+      decode_optional_list(basicresponse, ASN1_Type(0), m_certs);
 
       size_t responsedata_version = 0;
       Extensions extensions;
 
       BER_Decoder(m_tbs_bits)
-         .decode_optional(responsedata_version, ASN1_Tag(0),
-                          ASN1_Tag::CONTEXT_SPECIFIC | ASN1_Tag::CONSTRUCTED)
+         .decode_optional(responsedata_version, ASN1_Type(0),
+                          ASN1_Class::CONTEXT_SPECIFIC | ASN1_Class::CONSTRUCTED)
 
-         .decode_optional(m_signer_name, ASN1_Tag(1),
-                          ASN1_Tag::CONTEXT_SPECIFIC | ASN1_Tag::CONSTRUCTED)
+         .decode_optional(m_signer_name, ASN1_Type(1),
+                          ASN1_Class::CONTEXT_SPECIFIC | ASN1_Class::CONSTRUCTED)
 
-         .decode_optional_string(m_key_hash, ASN1_Tag::OCTET_STRING, 2,
-                                 ASN1_Tag::CONTEXT_SPECIFIC | ASN1_Tag::CONSTRUCTED)
+         .decode_optional_string(m_key_hash, ASN1_Type::OCTET_STRING, 2,
+                                 ASN1_Class::CONTEXT_SPECIFIC | ASN1_Class::CONSTRUCTED)
 
          .decode(m_produced_at)
 
          .decode_list(m_responses)
 
-         .decode_optional(extensions, ASN1_Tag(1),
-                          ASN1_Tag::CONTEXT_SPECIFIC | ASN1_Tag::CONSTRUCTED);
+         .decode_optional(extensions, ASN1_Type(1),
+                          ASN1_Class::CONTEXT_SPECIFIC | ASN1_Class::CONSTRUCTED);
       }
 
    response_outer.end_cons();
diff --git a/src/lib/x509/ocsp_types.cpp b/src/lib/x509/ocsp_types.cpp
index c03261b59..946c4aaa6 100644
--- a/src/lib/x509/ocsp_types.cpp
+++ b/src/lib/x509/ocsp_types.cpp
@@ -59,8 +59,8 @@ void CertID::encode_into(class DER_Encoder& to) const
    {
    to.start_sequence()
       .encode(m_hash_id)
-      .encode(m_issuer_dn_hash, ASN1_Tag::OCTET_STRING)
-      .encode(m_issuer_key_hash, ASN1_Tag::OCTET_STRING)
+      .encode(m_issuer_dn_hash, ASN1_Type::OCTET_STRING)
+      .encode(m_issuer_key_hash, ASN1_Type::OCTET_STRING)
       .encode(m_subject_serial)
       .end_cons();
    }
@@ -69,8 +69,8 @@ void CertID::decode_from(class BER_Decoder& from)
    {
    from.start_sequence()
       .decode(m_hash_id)
-      .decode(m_issuer_dn_hash, ASN1_Tag::OCTET_STRING)
-      .decode(m_issuer_key_hash, ASN1_Tag::OCTET_STRING)
+      .decode(m_issuer_dn_hash, ASN1_Type::OCTET_STRING)
+      .decode(m_issuer_key_hash, ASN1_Type::OCTET_STRING)
       .decode(m_subject_serial)
       .end_cons();
 
@@ -90,11 +90,11 @@ void SingleResponse::decode_from(class BER_Decoder& from)
       .decode(m_certid)
       .get_next(cert_status)
       .decode(m_thisupdate)
-      .decode_optional(m_nextupdate, ASN1_Tag(0),
-                       ASN1_Tag::CONTEXT_SPECIFIC | ASN1_Tag::CONSTRUCTED)
+      .decode_optional(m_nextupdate, ASN1_Type(0),
+                       ASN1_Class::CONTEXT_SPECIFIC | ASN1_Class::CONSTRUCTED)
       .decode_optional(extensions,
-                       ASN1_Tag(1),
-                       ASN1_Tag::CONTEXT_SPECIFIC | ASN1_Tag::CONSTRUCTED)
+                       ASN1_Type(1),
+                       ASN1_Class::CONTEXT_SPECIFIC | ASN1_Class::CONSTRUCTED)
       .end_cons();
 
    /* CertStatus ::= CHOICE {
diff --git a/src/lib/x509/pkcs10.cpp b/src/lib/x509/pkcs10.cpp
index 274ded692..3a3fb0cb2 100644
--- a/src/lib/x509/pkcs10.cpp
+++ b/src/lib/x509/pkcs10.cpp
@@ -80,7 +80,7 @@ PKCS10_Request PKCS10_Request::create(const Private_Key& key,
    if(challenge.empty() == false)
       {
       std::vector<uint8_t> value;
-      DER_Encoder(value).encode(ASN1_String(challenge, ASN1_Tag::DIRECTORY_STRING));
+      DER_Encoder(value).encode(ASN1_String(challenge, ASN1_Type::DIRECTORY_STRING));
       tbs_req.encode(Attribute("PKCS9.ChallengePassword", value));
       }
 
@@ -118,8 +118,8 @@ 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.is_a(ASN1_Tag::SEQUENCE, ASN1_Tag::CONSTRUCTED) == false)
-      throw BER_Bad_Tag("PKCS10_Request: Unexpected tag for public key", public_key.tagging());
+   if(public_key.is_a(ASN1_Type::SEQUENCE, ASN1_Class::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(public_key.bits(), public_key.length());
 
@@ -127,7 +127,7 @@ std::unique_ptr<PKCS10_Data> decode_pkcs10(const std::vector<uint8_t>& body)
 
    std::set<std::string> pkcs9_email;
 
-   if(attr_bits.is_a(0, ASN1_Tag::CONSTRUCTED | ASN1_Tag::CONTEXT_SPECIFIC))
+   if(attr_bits.is_a(0, ASN1_Class::CONSTRUCTED | ASN1_Class::CONTEXT_SPECIFIC))
       {
       BER_Decoder attributes(attr_bits);
       while(attributes.more_items())
@@ -158,7 +158,7 @@ std::unique_ptr<PKCS10_Data> decode_pkcs10(const std::vector<uint8_t>& body)
       attributes.verify_end();
       }
    else if(attr_bits.is_set())
-      throw BER_Bad_Tag("PKCS10_Request: Unexpected tag for attributes", attr_bits.tagging());
+          throw BER_Bad_Tag("PKCS10_Request: Unexpected tag for attributes", attr_bits.tagging());
 
    cert_req_info.verify_end();
 
diff --git a/src/lib/x509/pkix_types.h b/src/lib/x509/pkix_types.h
index 64c746308..00c58acb6 100644
--- a/src/lib/x509/pkix_types.h
+++ b/src/lib/x509/pkix_types.h
@@ -135,7 +135,7 @@ class BOTAN_PUBLIC_API(2,0) AlternativeName final : public ASN1_Object
       std::string get_first_attribute(const std::string& attr) const;
 
       void add_attribute(const std::string& type, const std::string& value);
-      void add_othername(const OID& oid, const std::string& value, ASN1_Tag type);
+      void add_othername(const OID& oid, const std::string& value, ASN1_Type type);
 
       const std::multimap<std::string, std::string>& get_attributes() const
          {
diff --git a/src/lib/x509/x509_attribute.cpp b/src/lib/x509/x509_attribute.cpp
index 2f247e7f3..52ea23b14 100644
--- a/src/lib/x509/x509_attribute.cpp
+++ b/src/lib/x509/x509_attribute.cpp
@@ -36,7 +36,7 @@ void Attribute::encode_into(DER_Encoder& codec) const
    {
    codec.start_sequence()
       .encode(m_oid)
-      .start_cons(ASN1_Tag::SET)
+      .start_cons(ASN1_Type::SET)
          .raw_bytes(m_parameters)
       .end_cons()
    .end_cons();
@@ -49,7 +49,7 @@ void Attribute::decode_from(BER_Decoder& codec)
    {
    codec.start_sequence()
       .decode(m_oid)
-      .start_cons(ASN1_Tag::SET)
+      .start_cons(ASN1_Type::SET)
          .raw_bytes(m_parameters)
       .end_cons()
    .end_cons();
diff --git a/src/lib/x509/x509_crl.cpp b/src/lib/x509/x509_crl.cpp
index a0368c13c..a01891910 100644
--- a/src/lib/x509/x509_crl.cpp
+++ b/src/lib/x509/x509_crl.cpp
@@ -123,7 +123,7 @@ std::unique_ptr<CRL_Data> decode_crl_body(const std::vector<uint8_t>& body,
    BER_Decoder tbs_crl(body);
 
    size_t version;
-   tbs_crl.decode_optional(version, ASN1_Tag::INTEGER, ASN1_Tag::UNIVERSAL);
+   tbs_crl.decode_optional(version, ASN1_Type::INTEGER, ASN1_Class::UNIVERSAL);
 
    if(version != 0 && version != 1)
       throw Decoding_Error("Unknown X.509 CRL version " + std::to_string(version+1));
@@ -140,7 +140,7 @@ std::unique_ptr<CRL_Data> decode_crl_body(const std::vector<uint8_t>& body,
 
    BER_Object next = tbs_crl.get_next_object();
 
-   if(next.is_a(ASN1_Tag::SEQUENCE, ASN1_Tag::CONSTRUCTED))
+   if(next.is_a(ASN1_Type::SEQUENCE, ASN1_Class::CONSTRUCTED))
       {
       BER_Decoder cert_list(std::move(next));
 
@@ -153,7 +153,7 @@ std::unique_ptr<CRL_Data> decode_crl_body(const std::vector<uint8_t>& body,
       next = tbs_crl.get_next_object();
       }
 
-   if(next.is_a(0, ASN1_Tag::CONSTRUCTED | ASN1_Tag::CONTEXT_SPECIFIC))
+   if(next.is_a(0, ASN1_Class::CONSTRUCTED | ASN1_Class::CONTEXT_SPECIFIC))
       {
       BER_Decoder crl_options(std::move(next));
       crl_options.decode(data->m_extensions).verify_end();
diff --git a/src/lib/x509/x509_dn.cpp b/src/lib/x509/x509_dn.cpp
index 2fb2088d4..4c1b1e9e2 100644
--- a/src/lib/x509/x509_dn.cpp
+++ b/src/lib/x509/x509_dn.cpp
@@ -262,7 +262,7 @@ void X509_DN::encode_into(DER_Encoder& der) const
       {
       for(const auto& dn : m_rdn)
          {
-         der.start_cons(ASN1_Tag::SET)
+         der.start_cons(ASN1_Type::SET)
             .start_sequence()
             .encode(dn.first)
             .encode(dn.second)
@@ -291,7 +291,7 @@ void X509_DN::decode_from(BER_Decoder& source)
 
    while(sequence.more_items())
       {
-      BER_Decoder rdn = sequence.start_cons(ASN1_Tag::SET);
+      BER_Decoder rdn = sequence.start_cons(ASN1_Type::SET);
 
       while(rdn.more_items())
          {
diff --git a/src/lib/x509/x509_ext.cpp b/src/lib/x509/x509_ext.cpp
index 85124e982..c5713e3b6 100644
--- a/src/lib/x509/x509_ext.cpp
+++ b/src/lib/x509/x509_ext.cpp
@@ -257,7 +257,7 @@ void Extensions::encode_into(DER_Encoder& to_object) const
          to_object.start_sequence()
                .encode(oid)
                .encode_optional(is_critical, false)
-               .encode(ext_value, ASN1_Tag::OCTET_STRING)
+               .encode(ext_value, ASN1_Type::OCTET_STRING)
             .end_cons();
          }
       }
@@ -281,8 +281,8 @@ void Extensions::decode_from(BER_Decoder& from_source)
 
       sequence.start_sequence()
          .decode(oid)
-         .decode_optional(critical, ASN1_Tag::BOOLEAN, ASN1_Tag::UNIVERSAL, false)
-         .decode(bits, ASN1_Tag::OCTET_STRING)
+         .decode_optional(critical, ASN1_Type::BOOLEAN, ASN1_Class::UNIVERSAL, false)
+         .decode(bits, ASN1_Type::OCTET_STRING)
       .end_cons();
 
       std::unique_ptr<Certificate_Extension> obj = create_extn_obj(oid, critical, bits);
@@ -330,8 +330,8 @@ void Basic_Constraints::decode_inner(const std::vector<uint8_t>& in)
    {
    BER_Decoder(in)
       .start_sequence()
-         .decode_optional(m_is_ca, ASN1_Tag::BOOLEAN, ASN1_Tag::UNIVERSAL, false)
-         .decode_optional(m_path_limit, ASN1_Tag::INTEGER, ASN1_Tag::UNIVERSAL, NO_CERT_PATH_LIMIT)
+         .decode_optional(m_is_ca, ASN1_Type::BOOLEAN, ASN1_Class::UNIVERSAL, false)
+         .decode_optional(m_path_limit, ASN1_Type::INTEGER, ASN1_Class::UNIVERSAL, NO_CERT_PATH_LIMIT)
       .end_cons();
 
    if(m_is_ca == false)
@@ -349,7 +349,7 @@ std::vector<uint8_t> Key_Usage::encode_inner() const
    const size_t unused_bits = ctz(static_cast<uint32_t>(m_constraints));
 
    std::vector<uint8_t> der;
-   der.push_back(static_cast<uint8_t>(ASN1_Tag::BIT_STRING));
+   der.push_back(static_cast<uint8_t>(ASN1_Type::BIT_STRING));
    der.push_back(2 + ((unused_bits < 8) ? 1 : 0));
    der.push_back(unused_bits % 8);
    der.push_back((m_constraints >> 8) & 0xFF);
@@ -368,7 +368,7 @@ void Key_Usage::decode_inner(const std::vector<uint8_t>& in)
 
    BER_Object obj = ber.get_next_object();
 
-   obj.assert_is_a(ASN1_Tag::BIT_STRING, ASN1_Tag::UNIVERSAL, "usage constraint");
+   obj.assert_is_a(ASN1_Type::BIT_STRING, ASN1_Class::UNIVERSAL, "usage constraint");
 
    if(obj.length() != 2 && obj.length() != 3)
       throw BER_Decoding_Error("Bad size for BITSTRING in usage constraint");
@@ -400,7 +400,7 @@ void Key_Usage::decode_inner(const std::vector<uint8_t>& in)
 std::vector<uint8_t> Subject_Key_ID::encode_inner() const
    {
    std::vector<uint8_t> output;
-   DER_Encoder(output).encode(m_key_id, ASN1_Tag::OCTET_STRING);
+   DER_Encoder(output).encode(m_key_id, ASN1_Type::OCTET_STRING);
    return output;
    }
 
@@ -409,7 +409,7 @@ std::vector<uint8_t> Subject_Key_ID::encode_inner() const
 */
 void Subject_Key_ID::decode_inner(const std::vector<uint8_t>& in)
    {
-   BER_Decoder(in).decode(m_key_id, ASN1_Tag::OCTET_STRING).verify_end();
+   BER_Decoder(in).decode(m_key_id, ASN1_Type::OCTET_STRING).verify_end();
    }
 
 /*
@@ -438,7 +438,7 @@ std::vector<uint8_t> Authority_Key_ID::encode_inner() const
    std::vector<uint8_t> output;
    DER_Encoder(output)
       .start_sequence()
-         .encode(m_key_id, ASN1_Tag::OCTET_STRING, ASN1_Tag(0), ASN1_Tag::CONTEXT_SPECIFIC)
+         .encode(m_key_id, ASN1_Type::OCTET_STRING, ASN1_Type(0), ASN1_Class::CONTEXT_SPECIFIC)
       .end_cons();
    return output;
    }
@@ -450,7 +450,7 @@ void Authority_Key_ID::decode_inner(const std::vector<uint8_t>& in)
    {
    BER_Decoder(in)
       .start_sequence()
-      .decode_optional_string(m_key_id, ASN1_Tag::OCTET_STRING, 0);
+      .decode_optional_string(m_key_id, ASN1_Type::OCTET_STRING, 0);
    }
 
 /*
@@ -530,18 +530,18 @@ void Name_Constraints::decode_inner(const std::vector<uint8_t>& in)
    BER_Object per = ext.get_next_object();
 
    ext.push_back(per);
-   if(per.is_a(0, ASN1_Tag::CONSTRUCTED | ASN1_Tag::CONTEXT_SPECIFIC))
+   if(per.is_a(0, ASN1_Class::CONSTRUCTED | ASN1_Class::CONTEXT_SPECIFIC))
       {
-      ext.decode_list(permit, ASN1_Tag(0), ASN1_Tag::CONSTRUCTED | ASN1_Tag::CONTEXT_SPECIFIC);
+      ext.decode_list(permit, ASN1_Type(0), ASN1_Class::CONSTRUCTED | ASN1_Class::CONTEXT_SPECIFIC);
       if(permit.empty())
          throw Encoding_Error("Empty Name Contraint list");
       }
 
    BER_Object exc = ext.get_next_object();
    ext.push_back(exc);
-   if(per.is_a(1, ASN1_Tag::CONSTRUCTED | ASN1_Tag::CONTEXT_SPECIFIC))
+   if(per.is_a(1, ASN1_Class::CONSTRUCTED | ASN1_Class::CONTEXT_SPECIFIC))
       {
-      ext.decode_list(exclude, ASN1_Tag(1), ASN1_Tag::CONSTRUCTED | ASN1_Tag::CONTEXT_SPECIFIC);
+      ext.decode_list(exclude, ASN1_Type(1), ASN1_Class::CONSTRUCTED | ASN1_Class::CONTEXT_SPECIFIC);
       if(exclude.empty())
          throw Encoding_Error("Empty Name Contraint list");
       }
@@ -700,14 +700,14 @@ void Certificate_Policies::validate(
 
 std::vector<uint8_t> Authority_Information_Access::encode_inner() const
    {
-   ASN1_String url(m_ocsp_responder, ASN1_Tag::IA5_STRING);
+   ASN1_String url(m_ocsp_responder, ASN1_Type::IA5_STRING);
 
    std::vector<uint8_t> output;
    DER_Encoder(output)
       .start_sequence()
       .start_sequence()
       .encode(OID::from_string("PKIX.OCSP"))
-      .add_object(ASN1_Tag(6), ASN1_Tag::CONTEXT_SPECIFIC, url.value())
+      .add_object(ASN1_Type(6), ASN1_Class::CONTEXT_SPECIFIC, url.value())
       .end_cons()
       .end_cons();
    return output;
@@ -729,7 +729,7 @@ void Authority_Information_Access::decode_inner(const std::vector<uint8_t>& in)
          {
          BER_Object name = info.get_next_object();
 
-         if(name.is_a(6, ASN1_Tag::CONTEXT_SPECIFIC))
+         if(name.is_a(6, ASN1_Class::CONTEXT_SPECIFIC))
             {
             m_ocsp_responder = ASN1::to_string(name);
             }
@@ -739,7 +739,7 @@ void Authority_Information_Access::decode_inner(const std::vector<uint8_t>& in)
          {
          BER_Object name = info.get_next_object();
 
-         if(name.is_a(6, ASN1_Tag::CONTEXT_SPECIFIC))
+         if(name.is_a(6, ASN1_Class::CONTEXT_SPECIFIC))
             {
             m_ca_issuers.push_back(ASN1::to_string(name));
             }
@@ -792,7 +792,7 @@ void CRL_Number::decode_inner(const std::vector<uint8_t>& in)
 std::vector<uint8_t> CRL_ReasonCode::encode_inner() const
    {
    std::vector<uint8_t> output;
-   DER_Encoder(output).encode(static_cast<size_t>(m_reason), ASN1_Tag::ENUMERATED, ASN1_Tag::UNIVERSAL);
+   DER_Encoder(output).encode(static_cast<size_t>(m_reason), ASN1_Type::ENUMERATED, ASN1_Class::UNIVERSAL);
    return output;
    }
 
@@ -802,7 +802,7 @@ std::vector<uint8_t> CRL_ReasonCode::encode_inner() const
 void CRL_ReasonCode::decode_inner(const std::vector<uint8_t>& in)
    {
    size_t reason_code = 0;
-   BER_Decoder(in).decode(reason_code, ASN1_Tag::ENUMERATED, ASN1_Tag::UNIVERSAL);
+   BER_Decoder(in).decode(reason_code, ASN1_Type::ENUMERATED, ASN1_Class::UNIVERSAL);
    m_reason = static_cast<CRL_Code>(reason_code);
    }
 
@@ -840,10 +840,10 @@ void CRL_Distribution_Points::Distribution_Point::encode_into(class DER_Encoder&
 void CRL_Distribution_Points::Distribution_Point::decode_from(class BER_Decoder& ber)
    {
    ber.start_sequence()
-      .start_cons(ASN1_Tag(0), ASN1_Tag::CONTEXT_SPECIFIC)
-        .decode_optional_implicit(m_point, ASN1_Tag(0),
-                                  ASN1_Tag::CONTEXT_SPECIFIC | ASN1_Tag::CONSTRUCTED,
-                                  ASN1_Tag::SEQUENCE, ASN1_Tag::CONSTRUCTED)
+      .start_cons(ASN1_Type(0), ASN1_Class::CONTEXT_SPECIFIC)
+        .decode_optional_implicit(m_point, ASN1_Type(0),
+                                  ASN1_Class::CONTEXT_SPECIFIC | ASN1_Class::CONSTRUCTED,
+                                  ASN1_Type::SEQUENCE, ASN1_Class::CONSTRUCTED)
       .end_cons().end_cons();
    }
 
diff --git a/src/lib/x509/x509_obj.cpp b/src/lib/x509/x509_obj.cpp
index 4b53e249d..c83a2c3f8 100644
--- a/src/lib/x509/x509_obj.cpp
+++ b/src/lib/x509/x509_obj.cpp
@@ -34,10 +34,10 @@ Pss_params decode_pss_params(const std::vector<uint8_t>& encoded_pss_params)
    Pss_params pss_parameter;
    BER_Decoder(encoded_pss_params)
       .start_sequence()
-         .decode_optional(pss_parameter.hash_algo, ASN1_Tag(0), ASN1_Tag::PRIVATE, default_hash)
-         .decode_optional(pss_parameter.mask_gen_algo, ASN1_Tag(1), ASN1_Tag::PRIVATE, default_mgf)
-         .decode_optional(pss_parameter.salt_len, ASN1_Tag(2), ASN1_Tag::PRIVATE, size_t(20))
-         .decode_optional(pss_parameter.trailer_field, ASN1_Tag(3), ASN1_Tag::PRIVATE, size_t(1))
+         .decode_optional(pss_parameter.hash_algo, ASN1_Type(0), ASN1_Class::EXPLICIT_CONTEXT_SPECIFIC, default_hash)
+         .decode_optional(pss_parameter.mask_gen_algo, ASN1_Type(1), ASN1_Class::EXPLICIT_CONTEXT_SPECIFIC, default_mgf)
+         .decode_optional(pss_parameter.salt_len, ASN1_Type(2), ASN1_Class::EXPLICIT_CONTEXT_SPECIFIC, size_t(20))
+         .decode_optional(pss_parameter.trailer_field, ASN1_Type(3), ASN1_Class::EXPLICIT_CONTEXT_SPECIFIC, size_t(1))
       .end_cons();
 
    BER_Decoder(pss_parameter.mask_gen_algo.get_parameters()).decode(pss_parameter.mask_gen_hash);
@@ -96,7 +96,7 @@ void X509_Object::encode_into(DER_Encoder& to) const
             .raw_bytes(signed_body())
          .end_cons()
          .encode(signature_algorithm())
-         .encode(signature(), ASN1_Tag::BIT_STRING)
+         .encode(signature(), ASN1_Type::BIT_STRING)
       .end_cons();
    }
 
@@ -110,7 +110,7 @@ void X509_Object::decode_from(BER_Decoder& from)
             .raw_bytes(m_tbs_bits)
          .end_cons()
          .decode(m_sig_algo)
-         .decode(m_sig, ASN1_Tag::BIT_STRING)
+         .decode(m_sig, ASN1_Type::BIT_STRING)
       .end_cons();
 
    force_decode();
@@ -312,7 +312,7 @@ std::vector<uint8_t> X509_Object::make_signed(PK_Signer* signer,
       .start_sequence()
          .raw_bytes(tbs_bits)
          .encode(algo)
-         .encode(signature, ASN1_Tag::BIT_STRING)
+         .encode(signature, ASN1_Type::BIT_STRING)
       .end_cons();
 
    return output;
diff --git a/src/lib/x509/x509cert.cpp b/src/lib/x509/x509cert.cpp
index a22ba484d..ed4dd94fb 100644
--- a/src/lib/x509/x509cert.cpp
+++ b/src/lib/x509/x509cert.cpp
@@ -114,7 +114,7 @@ std::unique_ptr<X509_Certificate_Data> parse_x509_cert_body(const X509_Object& o
    BER_Object v3_exts_data;
 
    BER_Decoder(obj.signed_body())
-      .decode_optional(data->m_version, ASN1_Tag(0), ASN1_Tag::CONSTRUCTED | ASN1_Tag::CONTEXT_SPECIFIC)
+      .decode_optional(data->m_version, ASN1_Type(0), ASN1_Class::CONSTRUCTED | ASN1_Class::CONTEXT_SPECIFIC)
       .decode(serial_bn)
       .decode(data->m_sig_algo_inner)
       .decode(data->m_issuer_dn)
@@ -124,8 +124,8 @@ std::unique_ptr<X509_Certificate_Data> parse_x509_cert_body(const X509_Object& o
       .end_cons()
       .decode(data->m_subject_dn)
       .get_next(public_key)
-      .decode_optional_string(data->m_v2_issuer_key_id, ASN1_Tag::BIT_STRING, 1)
-      .decode_optional_string(data->m_v2_subject_key_id, ASN1_Tag::BIT_STRING, 2)
+      .decode_optional_string(data->m_v2_issuer_key_id, ASN1_Type::BIT_STRING, 1)
+      .decode_optional_string(data->m_v2_subject_key_id, ASN1_Type::BIT_STRING, 2)
       .get_next(v3_exts_data)
       .verify_end("TBSCertificate has extra data after extensions block");
 
@@ -134,7 +134,7 @@ std::unique_ptr<X509_Certificate_Data> parse_x509_cert_body(const X509_Object& o
    if(obj.signature_algorithm() != data->m_sig_algo_inner)
       throw Decoding_Error("X.509 Certificate had differing algorithm identifers in inner and outer ID fields");
 
-   public_key.assert_is_a(ASN1_Tag::SEQUENCE, ASN1_Tag::CONSTRUCTED, "X.509 certificate public key");
+   public_key.assert_is_a(ASN1_Type::SEQUENCE, ASN1_Class::CONSTRUCTED, "X.509 certificate public key");
 
    // crude method to save the serial's sign; will get lost during decoding, otherwise
    data->m_serial_negative = serial_bn.is_negative();
@@ -196,16 +196,16 @@ std::unique_ptr<X509_Certificate_Data> parse_x509_cert_body(const X509_Object& o
 
    BER_Decoder(data->m_subject_public_key_bits)
       .decode(data->m_subject_public_key_algid)
-      .decode(data->m_subject_public_key_bitstring, ASN1_Tag::BIT_STRING);
+      .decode(data->m_subject_public_key_bitstring, ASN1_Type::BIT_STRING);
 
-   if(v3_exts_data.is_a(3, ASN1_Tag::CONSTRUCTED | ASN1_Tag::CONTEXT_SPECIFIC))
+   if(v3_exts_data.is_a(3, ASN1_Class::CONSTRUCTED | ASN1_Class::CONTEXT_SPECIFIC))
       {
       // Path validation will reject a v1/v2 cert with v3 extensions
       BER_Decoder(v3_exts_data).decode(data->m_v3_extensions).verify_end();
       }
    else if(v3_exts_data.is_set())
       {
-      throw BER_Bad_Tag("Unknown tag in X.509 cert", v3_exts_data.tagging());
+          throw BER_Bad_Tag("Unknown tag in X.509 cert", v3_exts_data.tagging());
       }
 
    // Now cache some fields from the extensions
diff --git a/src/lib/x509/x509opt.cpp b/src/lib/x509/x509opt.cpp
index fcdb510c5..65ad0bb94 100644
--- a/src/lib/x509/x509opt.cpp
+++ b/src/lib/x509/x509opt.cpp
@@ -16,7 +16,7 @@ namespace Botan {
 */
 void X509_Cert_Options::not_before(const std::string& time_string)
    {
-   start = X509_Time(time_string, ASN1_Tag::UTC_OR_GENERALIZED_TIME);
+   start = X509_Time(time_string, ASN1_Type::UTC_OR_GENERALIZED_TIME);
    }
 
 /*
@@ -24,7 +24,7 @@ void X509_Cert_Options::not_before(const std::string& time_string)
 */
 void X509_Cert_Options::not_after(const std::string& time_string)
    {
-   end = X509_Time(time_string, ASN1_Tag::UTC_OR_GENERALIZED_TIME);
+   end = X509_Time(time_string, ASN1_Type::UTC_OR_GENERALIZED_TIME);
    }
 
 /*
diff --git a/src/lib/x509/x509self.cpp b/src/lib/x509/x509self.cpp
index e2282de9e..ac3c709e2 100644
--- a/src/lib/x509/x509self.cpp
+++ b/src/lib/x509/x509self.cpp
@@ -36,7 +36,7 @@ void load_info(const X509_Cert_Options& opts, X509_DN& subject_dn,
    subject_dn.add_attribute("X520.SerialNumber", opts.serial_number);
    subject_alt = AlternativeName(opts.email, opts.uri, opts.dns, opts.ip);
    subject_alt.add_othername(OID::from_string("PKIX.XMPPAddr"),
-                             opts.xmpp, ASN1_Tag::UTF8_STRING);
+                             opts.xmpp, ASN1_Type::UTF8_STRING);
 
    for(auto dns : opts.more_dns)
       subject_alt.add_attribute("DNS", dns);


Test patch:
diff --git a/src/tests/test_asn1.cpp b/src/tests/test_asn1.cpp
index 69ae643b2..a9b6c54bb 100644
--- a/src/tests/test_asn1.cpp
+++ b/src/tests/test_asn1.cpp
@@ -309,8 +309,8 @@ class ASN1_Time_Parsing_Tests final : public Text_Based_Test
             throw Test_Error("Invalid tag value in ASN1 date parsing test");
             }
 
-         const Botan::ASN1_Tag tag =
-            (tag_str == "UTC" || tag_str == "UTC.invalid") ? Botan::ASN1_Tag::UTC_TIME : Botan::ASN1_Tag::GENERALIZED_TIME;
+         const Botan::ASN1_Type tag =
+            (tag_str == "UTC" || tag_str == "UTC.invalid") ? Botan::ASN1_Type::UTC_TIME : Botan::ASN1_Type::GENERALIZED_TIME;
 
          const bool valid = tag_str.find(".invalid") == std::string::npos;
 
diff --git a/src/tests/test_hash_id.cpp b/src/tests/test_hash_id.cpp
index 9cc75d14e..68b5a2a31 100644
--- a/src/tests/test_hash_id.cpp
+++ b/src/tests/test_hash_id.cpp
@@ -56,7 +56,7 @@ class PKCS_HashID_Test final : public Test
 
                std::vector<uint8_t> bits;
                Botan::DER_Encoder der(bits);
-               der.start_sequence().encode(alg).encode(dummy_hash, Botan::ASN1_Tag::OCTET_STRING).end_cons();
+               der.start_sequence().encode(alg).encode(dummy_hash, Botan::ASN1_Type::OCTET_STRING).end_cons();
 
                result.test_eq("Dummy hash is expected size", bits.size() - pkcs_id.size(), dummy_hash.size());
 
diff --git a/src/tests/test_pkcs11_high_level.cpp b/src/tests/test_pkcs11_high_level.cpp
index db02d29a5..d6cade5ff 100644
--- a/src/tests/test_pkcs11_high_level.cpp
+++ b/src/tests/test_pkcs11_high_level.cpp
@@ -914,7 +914,7 @@ BOTAN_REGISTER_TEST("pkcs11", "pkcs11-rsa", PKCS11_RSA_Tests);
 std::vector<uint8_t> encode_ec_point_in_octet_str(const Botan::PointGFp& point)
    {
    std::vector<uint8_t> enc;
-   DER_Encoder(enc).encode(point.encode(PointGFp::UNCOMPRESSED), ASN1_Tag::OCTET_STRING);
+   DER_Encoder(enc).encode(point.encode(PointGFp::UNCOMPRESSED), ASN1_Type::OCTET_STRING);
    return enc;
    }
 #endif
diff --git a/src/tests/unit_x509.cpp b/src/tests/unit_x509.cpp
index 13bebc7d3..26eb6ab36 100644
--- a/src/tests/unit_x509.cpp
+++ b/src/tests/unit_x509.cpp
@@ -253,22 +253,22 @@ Test::Result test_x509_dates()
 
    Botan::X509_Time time;
    result.confirm("unset time not set", !time.time_is_set());
-   time = Botan::X509_Time("080201182200Z", Botan::ASN1_Tag::UTC_TIME);
+   time = Botan::X509_Time("080201182200Z", Botan::ASN1_Type::UTC_TIME);
    result.confirm("time set after construction", time.time_is_set());
    result.test_eq("time readable_string", time.readable_string(), "2008/02/01 18:22:00 UTC");
 
-   time = Botan::X509_Time("200305100350Z", Botan::ASN1_Tag::UTC_TIME);
+   time = Botan::X509_Time("200305100350Z", Botan::ASN1_Type::UTC_TIME);
    result.test_eq("UTC_TIME readable_string", time.readable_string(), "2020/03/05 10:03:50 UTC");
 
-   time = Botan::X509_Time("200305100350Z", Botan::ASN1_Tag::UTC_OR_GENERALIZED_TIME);
+   time = Botan::X509_Time("200305100350Z", Botan::ASN1_Type::UTC_OR_GENERALIZED_TIME);
    result.test_eq("UTC_OR_GENERALIZED_TIME from UTC_TIME readable_string", time.readable_string(),
                   "2020/03/05 10:03:50 UTC");
 
-   time = Botan::X509_Time("20200305100350Z", Botan::ASN1_Tag::UTC_OR_GENERALIZED_TIME);
+   time = Botan::X509_Time("20200305100350Z", Botan::ASN1_Type::UTC_OR_GENERALIZED_TIME);
    result.test_eq("UTC_OR_GENERALIZED_TIME from GENERALIZED_TIME readable_string", time.readable_string(),
                   "2020/03/05 10:03:50 UTC");
 
-   time = Botan::X509_Time("20200305100350Z", Botan::ASN1_Tag::GENERALIZED_TIME);
+   time = Botan::X509_Time("20200305100350Z", Botan::ASN1_Type::GENERALIZED_TIME);
    result.test_eq("GENERALIZED_TIME readable_string", time.readable_string(), "2020/03/05 10:03:50 UTC");
 
    // Dates that are valid per X.500 but rejected as unsupported
@@ -406,27 +406,27 @@ Test::Result test_x509_dates()
 
    for(const auto& v : valid_but_unsup)
       {
-      result.test_throws("valid but unsupported", [v]() { Botan::X509_Time t(v, Botan::ASN1_Tag::UTC_TIME); });
+      result.test_throws("valid but unsupported", [v]() { Botan::X509_Time t(v, Botan::ASN1_Type::UTC_TIME); });
       }
 
    for(const auto& v : valid_utc)
       {
-      Botan::X509_Time t(v, Botan::ASN1_Tag::UTC_TIME);
+      Botan::X509_Time t(v, Botan::ASN1_Type::UTC_TIME);
       }
 
    for(const auto& v : valid_generalized_time)
       {
-      Botan::X509_Time t(v, Botan::ASN1_Tag::GENERALIZED_TIME);
+      Botan::X509_Time t(v, Botan::ASN1_Type::GENERALIZED_TIME);
       }
 
    for(const auto& v : invalid_utc)
       {
-      result.test_throws("invalid", [v]() { Botan::X509_Time t(v, Botan::ASN1_Tag::UTC_TIME); });
+      result.test_throws("invalid", [v]() { Botan::X509_Time t(v, Botan::ASN1_Type::UTC_TIME); });
       }
 
    for(const auto& v : invalid_generalized)
       {
-      result.test_throws("invalid", [v]() { Botan::X509_Time t(v, Botan::ASN1_Tag::GENERALIZED_TIME); });
+      result.test_throws("invalid", [v]() { Botan::X509_Time t(v, Botan::ASN1_Type::GENERALIZED_TIME); });
       }
 
    return result;
@@ -1356,14 +1356,14 @@ class String_Extension final : public Botan::Certificate_Extension
       std::vector<uint8_t> encode_inner() const override
          {
          std::vector<uint8_t> bits;
-         Botan::DER_Encoder(bits).encode(Botan::ASN1_String(m_contents, Botan::ASN1_Tag::UTF8_STRING));
+         Botan::DER_Encoder(bits).encode(Botan::ASN1_String(m_contents, Botan::ASN1_Type::UTF8_STRING));
          return bits;
          }
 
       void decode_inner(const std::vector<uint8_t>& in) override
          {
          Botan::ASN1_String str;
-         Botan::BER_Decoder(in).decode(str, Botan::ASN1_Tag::UTF8_STRING).verify_end();
+         Botan::BER_Decoder(in).decode(str, Botan::ASN1_Type::UTF8_STRING).verify_end();
          m_contents = str.value();
          }
 
@@ -1391,8 +1391,8 @@ Test::Result test_custom_dn_attr(const Botan::Private_Key& ca_key,
 
    const Botan::OID attr1(Botan::OID("1.3.6.1.4.1.25258.9.1.1"));
    const Botan::OID attr2(Botan::OID("1.3.6.1.4.1.25258.9.1.2"));
-   const Botan::ASN1_String val1("Custom Attr 1", Botan::ASN1_Tag::PRINTABLE_STRING);
-   const Botan::ASN1_String val2("12345", Botan::ASN1_Tag::UTF8_STRING);
+   const Botan::ASN1_String val1("Custom Attr 1", Botan::ASN1_Type::PRINTABLE_STRING);
+   const Botan::ASN1_String val2("12345", Botan::ASN1_Type::UTF8_STRING);
 
    subject_dn.add_attribute(attr1, val1);
    subject_dn.add_attribute(attr2, val2);
@@ -1418,8 +1418,8 @@ Test::Result test_custom_dn_attr(const Botan::Private_Key& ca_key,
    result.confirm("Attr1 tag matches encoded", req_val1.tagging() == val1.tagging());
    result.confirm("Attr2 tag matches encoded", req_val2.tagging() == val2.tagging());
 
-   Botan::X509_Time not_before("100301123001Z", Botan::ASN1_Tag::UTC_TIME);
-   Botan::X509_Time not_after("300301123001Z", Botan::ASN1_Tag::UTC_TIME);
+   Botan::X509_Time not_before("100301123001Z", Botan::ASN1_Type::UTC_TIME);
+   Botan::X509_Time not_after("300301123001Z", Botan::ASN1_Type::UTC_TIME);
 
    auto cert = ca.sign_request(req, Test::rng(), not_before, not_after);