diff --git a/scapy/asn1/ber.py b/scapy/asn1/ber.py
index 499cda61fe43bc2b59600413de70741bfe0cf51f..f1cdcc64e9038a42a50bdccd7bdf4067ae33d38d 100644
--- a/scapy/asn1/ber.py
+++ b/scapy/asn1/ber.py
@@ -89,7 +89,8 @@ def BER_num_enc(l, size=1):
             l >>= 7
             size -= 1
         return "".join([chr(k) for k in x])
-def BER_num_dec(s, x=0):
+def BER_num_dec(s, cls_id=0):
+        x = cls_id
         for i, c in enumerate(s):
             c = ord(c)
             x <<= 7
@@ -100,20 +101,46 @@ def BER_num_dec(s, x=0):
             raise BER_Decoding_Error("BER_num_dec: unfinished number description", remaining=s)
         return x, s[i+1:]
 
-# The function below provides low-tag and high-tag identifier partial support.
-# Class and primitive/constructed bit decoding is not supported yet.
-# For now Scapy considers this information to always be part of the identifier
-# e.g. we need BER_id_dec("\x30") to be 0x30 so that Scapy calls a SEQUENCE,
-# even though the real id is 0x10 once bit 6 (constructed) has been removed.
 def BER_id_dec(s):
+    # This returns the tag ALONG WITH THE PADDED CLASS+CONSTRUCTIVE INFO.
+    # Let's recall that bits 8-7 from the first byte of the tag encode
+    # the class information, while bit 6 means primitive or constructive.
+    # For instance, with low-tag-number '\x81', class would be 0b10
+    # ('context-specific') and tag 0x01, but we return 0x81 as a whole.
+    # For '\xff\x02', class would be 0b11 ('private'), constructed, then
+    # padding, then tag 0x02, but we return (0xff>>5)*128^1 + 0x02*128^0.
+    # Why the 5-bit-shifting? Because it provides an unequivocal encoding
+    # on base 128 (note that 0xff would equal 1*128^1 + 127*128^0...),
+    # as we know that bits 5 to 1 are fixed to 1 anyway.
+    # As long as there is no class differentiation, we have to keep this info
+    # encoded in scapy's tag in order to reuse it for packet building.
+    # Note that tags thus may have to be hard-coded with their extended
+    # information, e.g. a SEQUENCE from asn1.py has a direct tag 0x20|16.
         x = ord(s[0])
         if x & 0x1f != 0x1f:
+            # low-tag-number
             return x,s[1:]
-        return BER_num_dec(s[1:], x&0xe0)
+        else:
+            # high-tag-number
+            return BER_num_dec(s[1:], cls_id=x>>5)
+def BER_id_enc(n):
+        if n < 256:
+            # low-tag-number
+            return chr(n)
+        else:
+            # high-tag-number
+            s = BER_num_enc(n)
+            tag = ord(s[0])             # first byte, as an int
+            tag &= 0x07                 # reset every bit from 8 to 4
+            tag <<= 5                   # move back the info bits on top
+            tag |= 0x1f                 # pad with 1s every bit from 5 to 1
+            return chr(tag) + s[1:]
 
 # The functions below provide implicit and explicit tagging support.
 def BER_tagging_dec(s, hidden_tag=None, implicit_tag=None,
                     explicit_tag=None, safe=False):
+    # We output the 'real_tag' if it is different from the (im|ex)plicit_tag.
+    real_tag = None
     if len(s) > 0:
         err_msg = "BER_tagging_dec: observed tag does not match expected tag"
         if implicit_tag is not None:
@@ -121,20 +148,24 @@ def BER_tagging_dec(s, hidden_tag=None, implicit_tag=None,
             if ber_id != implicit_tag:
                 if not safe:
                     raise BER_Decoding_Error(err_msg, remaining=s)
+                else:
+                    real_tag = ber_id
             s = chr(hidden_tag) + s
         elif explicit_tag is not None:
             ber_id,s = BER_id_dec(s)
             if ber_id != explicit_tag:
                 if not safe:
                     raise BER_Decoding_Error(err_msg, remaining=s)
+                else:
+                    real_tag = ber_id
             l,s = BER_len_dec(s)
-    return s
+    return real_tag, s
 def BER_tagging_enc(s, implicit_tag=None, explicit_tag=None):
     if len(s) > 0:
         if implicit_tag is not None:
-            s = chr(implicit_tag) + s[1:]
+            s = BER_id_enc(implicit_tag) + s[1:]
         elif explicit_tag is not None:
-            s = chr(explicit_tag) + BER_len_enc(len(s)) + s
+            s = BER_id_enc(explicit_tag) + BER_len_enc(len(s)) + s
     return s
 
 #####[ BER classes ]#####
diff --git a/scapy/asn1fields.py b/scapy/asn1fields.py
index 568022afada518efaf55b3d22bdecf01d775712c..78d4399a873d3dba13aea900bb0731886337af50 100644
--- a/scapy/asn1fields.py
+++ b/scapy/asn1fields.py
@@ -15,8 +15,6 @@ from volatile import *
 from base_classes import BasePacket
 from utils import binrepr
 
-FLEXIBLE_TAGS = False
-
 class ASN1F_badsequence(Exception):
     pass
 
@@ -35,7 +33,8 @@ class ASN1F_field(ASN1F_element):
     context = ASN1_Class_UNIVERSAL
     
     def __init__(self, name, default, context=None,
-                 implicit_tag=None, explicit_tag=None):
+                 implicit_tag=None, explicit_tag=None,
+                 flexible_tag=False):
         self.context = context
         self.name = name
         if default is None:
@@ -44,7 +43,7 @@ class ASN1F_field(ASN1F_element):
             self.default = default
         else:
             self.default = self.ASN1_tag.asn1_object(default)
-        self.flexible_tag = False or FLEXIBLE_TAGS
+        self.flexible_tag = flexible_tag
         if (implicit_tag is not None) and (explicit_tag is not None):
             err_msg = "field cannot be both implicitly and explicitly tagged"
             raise ASN1_Error(err_msg)
@@ -70,13 +69,18 @@ class ASN1F_field(ASN1F_element):
 
         Regarding other fields, we might need to know whether encoding went
         as expected or not. Noticeably, input methods from cert.py expect
-        certain exceptions to be raised. Hence default flexible_tag is False,
-        but we provide a FLEXIBLE_TAGS switch for debugging purposes.
+        certain exceptions to be raised. Hence default flexible_tag is False.
         """
-        s = BER_tagging_dec(s, hidden_tag=self.ASN1_tag,
-                            implicit_tag=self.implicit_tag,
-                            explicit_tag=self.explicit_tag,
-                            safe=self.flexible_tag)
+        diff_tag, s = BER_tagging_dec(s, hidden_tag=self.ASN1_tag,
+                                      implicit_tag=self.implicit_tag,
+                                      explicit_tag=self.explicit_tag,
+                                      safe=self.flexible_tag)
+        if diff_tag is not None:
+            # this implies that flexible_tag was True
+            if self.implicit_tag is not None:
+                self.implicit_tag = diff_tag
+            elif self.explicit_tag is not None:
+                self.explicit_tag = diff_tag
         codec = self.ASN1_tag.get_codec(pkt.ASN1_codec)
         if self.flexible_tag:
             return codec.safedec(s, context=self.context)
@@ -251,19 +255,32 @@ class ASN1F_BMP_STRING(ASN1F_STRING):
     ASN1_tag = ASN1_Class_UNIVERSAL.BMP_STRING
    
 class ASN1F_SEQUENCE(ASN1F_field):
+# Here is how you could decode a SEQUENCE
+# with an unknown, private high-tag prefix :
+# class PrivSeq(ASN1_Packet):
+#     ASN1_codec = ASN1_Codecs.BER
+#     ASN1_root = ASN1F_SEQUENCE(
+#                       <asn1 field #0>,
+#                       ...
+#                       <asn1 field #N>,
+#                       explicit_tag=0,
+#                       flexible_tag=True)
+# Because we use flexible_tag, the value of the explicit_tag does not matter.
     ASN1_tag = ASN1_Class_UNIVERSAL.SEQUENCE
     holds_packets = 1
     def __init__(self, *seq, **kwargs):
         name = "dummy_seq_name"
         default = [field.default for field in seq]
-        for kwarg in ["context", "implicit_tag", "explicit_tag"]:
+        for kwarg in ["context", "implicit_tag",
+                      "explicit_tag", "flexible_tag"]:
             if kwarg in kwargs:
                 setattr(self, kwarg, kwargs[kwarg])
             else:
                 setattr(self, kwarg, None)
         ASN1F_field.__init__(self, name, default, context=self.context,
                              implicit_tag=self.implicit_tag,
-                             explicit_tag=self.explicit_tag)
+                             explicit_tag=self.explicit_tag,
+                             flexible_tag=self.flexible_tag)
         self.seq = seq
         self.islist = len(seq) > 1
     def __repr__(self):
@@ -284,10 +301,15 @@ class ASN1F_SEQUENCE(ASN1F_field):
         Thus m2i returns an empty list (along with the proper remainder).
         It is discarded by dissect() and should not be missed elsewhere.
         """
-        s = BER_tagging_dec(s, hidden_tag=self.ASN1_tag,
-                            implicit_tag=self.implicit_tag,
-                            explicit_tag=self.explicit_tag,
-                            safe=self.flexible_tag)
+        diff_tag, s = BER_tagging_dec(s, hidden_tag=self.ASN1_tag,
+                                      implicit_tag=self.implicit_tag,
+                                      explicit_tag=self.explicit_tag,
+                                      safe=self.flexible_tag)
+        if diff_tag is not None:
+            if self.implicit_tag is not None:
+                self.implicit_tag = diff_tag
+            elif self.explicit_tag is not None:
+                self.explicit_tag = diff_tag
         codec = self.ASN1_tag.get_codec(pkt.ASN1_codec)
         i,s,remain = codec.check_type_check_len(s)
         if len(s) == 0:
@@ -325,10 +347,15 @@ class ASN1F_SEQUENCE_OF(ASN1F_field):
     def is_empty(self, pkt):
         return ASN1F_field.is_empty(self, pkt)
     def m2i(self, pkt, s):
-        s = BER_tagging_dec(s, hidden_tag=self.ASN1_tag,
-                            implicit_tag=self.implicit_tag,
-                            explicit_tag=self.explicit_tag,
-                            safe=self.flexible_tag)
+        diff_tag, s = BER_tagging_dec(s, hidden_tag=self.ASN1_tag,
+                                      implicit_tag=self.implicit_tag,
+                                      explicit_tag=self.explicit_tag,
+                                      safe=self.flexible_tag)
+        if diff_tag is not None:
+            if self.implicit_tag is not None:
+                self.implicit_tag = diff_tag
+            elif self.explicit_tag is not None:
+                self.explicit_tag = diff_tag
         codec = self.ASN1_tag.get_codec(pkt.ASN1_codec)
         i,s,remain = codec.check_type_check_len(s)
         lst = []
@@ -368,7 +395,7 @@ class ASN1F_TIME_TICKS(ASN1F_INTEGER):
 #############################
 
 class ASN1F_optional(ASN1F_element):
-    def __init__(self, field, by_default=False):
+    def __init__(self, field):
         field.flexible_tag = False
         self._field = field
     def __getattr__(self, attr):
@@ -440,9 +467,8 @@ class ASN1F_CHOICE(ASN1F_field):
         """
         if len(s) == 0:
             raise ASN1_Error("ASN1F_CHOICE: got empty string")
-        s = BER_tagging_dec(s, hidden_tag=self.ASN1_tag,
-                            explicit_tag=self.explicit_tag,
-                            safe=self.flexible_tag)
+        _,s = BER_tagging_dec(s, hidden_tag=self.ASN1_tag,
+                              explicit_tag=self.explicit_tag)
         tag,_ = BER_id_dec(s)
         if tag not in self.choices:
             if self.flexible_tag:
@@ -484,10 +510,15 @@ class ASN1F_PACKET(ASN1F_field):
                 self.network_tag = 16|0x20
         self.default = default
     def m2i(self, pkt, s):
-        s = BER_tagging_dec(s, hidden_tag=self.cls.ASN1_root.ASN1_tag,
-                            implicit_tag=self.implicit_tag,
-                            explicit_tag=self.explicit_tag,
-                            safe=self.flexible_tag)
+        diff_tag, s = BER_tagging_dec(s, hidden_tag=self.cls.ASN1_root.ASN1_tag,
+                                      implicit_tag=self.implicit_tag,
+                                      explicit_tag=self.explicit_tag,
+                                      safe=self.flexible_tag)
+        if diff_tag is not None:
+            if self.implicit_tag is not None:
+                self.implicit_tag = diff_tag
+            elif self.explicit_tag is not None:
+                self.explicit_tag = diff_tag
         p,s = self.extract_packet(self.cls, s)
         return p,s
     def i2m(self, pkt, x):
diff --git a/scapy/layers/x509.py b/scapy/layers/x509.py
index fa0389a555621e2a51b55f569abcc16093790605..1b4f078d9c9f84dde511f3a459129e3aa72801d6 100644
--- a/scapy/layers/x509.py
+++ b/scapy/layers/x509.py
@@ -19,6 +19,16 @@ class ASN1P_INTEGER(ASN1_Packet):
     ASN1_codec = ASN1_Codecs.BER
     ASN1_root = ASN1F_INTEGER("number", 0)
 
+class ASN1P_PRIVSEQ(ASN1_Packet):
+    # This class gets used in x509.uts
+    # It showcases the private high-tag decoding capacities of scapy.
+    ASN1_codec = ASN1_Codecs.BER
+    ASN1_root = ASN1F_SEQUENCE(
+            ASN1F_IA5_STRING("str", ""),
+            ASN1F_STRING("int", 0),
+            explicit_tag=0,
+            flexible_tag=True)
+
 
 #######################
 ##### RSA packets #####
@@ -36,7 +46,7 @@ class RSAPublicKey(ASN1_Packet):
                     ASN1F_INTEGER("publicExponent", 3))
 
 class RSAOtherPrimeInfo(ASN1_Packet):
-    ASN1_codec = ASN1_Codecs.DER
+    ASN1_codec = ASN1_Codecs.BER
     ASN1_root = ASN1F_SEQUENCE(
                     ASN1F_INTEGER("prime", 0),
                     ASN1F_INTEGER("exponent", 0),
@@ -610,9 +620,9 @@ class ASN1F_EXT_SEQUENCE(ASN1F_SEQUENCE):
                    explicit_tag=0x04)]
         ASN1F_SEQUENCE.__init__(self, *seq, **kargs)
     def dissect(self, pkt, s):
-        s = BER_tagging_dec(s, implicit_tag=self.implicit_tag,
-                            explicit_tag=self.explicit_tag,
-                            safe=self.flexible_tag)
+        _,s = BER_tagging_dec(s, implicit_tag=self.implicit_tag,
+                              explicit_tag=self.explicit_tag,
+                              safe=self.flexible_tag)
         codec = self.ASN1_tag.get_codec(pkt.ASN1_codec)
         i,s,remain = codec.check_type_check_len(s)
         extnID = self.seq[0]
diff --git a/test/x509.uts b/test/x509.uts
index 3505c10d99a0487795b51f2128b27e307474b0e5..8b42ac5382abc1b2bcf3bc49ea74397f9fb7e8f2 100644
--- a/test/x509.uts
+++ b/test/x509.uts
@@ -1,7 +1,15 @@
 % Tests for X.509 objects
 # 
-# Launch me with:
-# sudo bash test/run_tests -t test/x509.uts -F
+# Try me with:
+# bash test/run_tests -t test/x509.uts -F
+
+########### ASN.1 border case #######################################
+
++ General BER decoding tests
+= Decoding an ASN.1 SEQUENCE with an unknown, high-tag identifier
+s = '\xff\x84\x92\xb9\x86H\x1e0\x1c\x16\x04BNCH\x04\x14\xb7\xca\x01wO\x9b\xbaz\xbb\xb5\x92\x87>T\xb2\xc3g\xc1]\xfb'
+p = ASN1P_PRIVSEQ(s)
+
 
 ########### Key class ###############################################
 
@@ -136,7 +144,7 @@ str(x) == c
 tbs = x.tbsCertList
 tbs.version == None
 
-= CRL class : Signature algorithm (as advertised by TBSCRLificate)
+= CRL class : Signature algorithm (as advertised by TBSCertList)
 assert(type(tbs.signature) is X509_AlgorithmIdentifier)
 tbs.signature.algorithm == ASN1_OID("sha1-with-rsa-signature")
 
@@ -178,6 +186,7 @@ x.signatureAlgorithm.algorithm == ASN1_OID("sha1-with-rsa-signature")
 x.signatureValue == ASN1_BIT_STRING('"\xc9\xf6\xbb\x1d\xa1\xa5=$\xc7\xff\xb0"\x11\xb3p\x06[\xc5U\xdd3v\xa0\x98"\x08cDi\xcfOG%w\x99\x12\x84\xd2\x19\xae \x94\xca,T\x9ak\x81\xd2\x038\xa6Z\x95\x8d*\xe2a\xce\xdb\x19\xcdu\'Y&|V\xe1\xe4\x80q\x1aI\xb2\xaa\xcdI[\xda\x0f\xa8\xff\xce<\n\xfc\xc9\xad\xc6\xde\xc8@d\x0c&\t#\x90\xb7\x9c\xb9P\x03\x8fK\x18\x9f\xb0\xe0e\x0f`\x1c\x1ag\xe5\x85\xc4%\xf5\x0b\xc93\x82R\xe6', readable=True)
 
 = CRL class : Default X509_CRL from scratch
-str(X509_CRL(str(X509_CRL()))) == str(X509_CRL())
+s = str(X509_CRL())
+str(X509_CRL(s)) == s