1# 2# This file is part of pyasn1 software. 3# 4# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com> 5# License: http://snmplabs.com/pyasn1/license.html 6# 7from pyasn1 import error 8 9__all__ = ['tagClassUniversal', 'tagClassApplication', 'tagClassContext', 10 'tagClassPrivate', 'tagFormatSimple', 'tagFormatConstructed', 11 'tagCategoryImplicit', 'tagCategoryExplicit', 12 'tagCategoryUntagged', 'Tag', 'TagSet'] 13 14#: Identifier for ASN.1 class UNIVERSAL 15tagClassUniversal = 0x00 16 17#: Identifier for ASN.1 class APPLICATION 18tagClassApplication = 0x40 19 20#: Identifier for ASN.1 class context-specific 21tagClassContext = 0x80 22 23#: Identifier for ASN.1 class private 24tagClassPrivate = 0xC0 25 26#: Identifier for "simple" ASN.1 structure (e.g. scalar) 27tagFormatSimple = 0x00 28 29#: Identifier for "constructed" ASN.1 structure (e.g. may have inner components) 30tagFormatConstructed = 0x20 31 32tagCategoryImplicit = 0x01 33tagCategoryExplicit = 0x02 34tagCategoryUntagged = 0x04 35 36 37class Tag(object): 38 """Create ASN.1 tag 39 40 Represents ASN.1 tag that can be attached to a ASN.1 type to make 41 types distinguishable from each other. 42 43 *Tag* objects are immutable and duck-type Python :class:`tuple` objects 44 holding three integer components of a tag. 45 46 Parameters 47 ---------- 48 tagClass: :py:class:`int` 49 Tag *class* value 50 51 tagFormat: :py:class:`int` 52 Tag *format* value 53 54 tagId: :py:class:`int` 55 Tag ID value 56 """ 57 def __init__(self, tagClass, tagFormat, tagId): 58 if tagId < 0: 59 raise error.PyAsn1Error('Negative tag ID (%s) not allowed' % tagId) 60 self.__tagClass = tagClass 61 self.__tagFormat = tagFormat 62 self.__tagId = tagId 63 self.__tagClassId = tagClass, tagId 64 self.__hash = hash(self.__tagClassId) 65 66 def __repr__(self): 67 representation = '[%s:%s:%s]' % ( 68 self.__tagClass, self.__tagFormat, self.__tagId) 69 return '<%s object, tag %s>' % ( 70 self.__class__.__name__, representation) 71 72 def __eq__(self, other): 73 return self.__tagClassId == other 74 75 def __ne__(self, other): 76 return self.__tagClassId != other 77 78 def __lt__(self, other): 79 return self.__tagClassId < other 80 81 def __le__(self, other): 82 return self.__tagClassId <= other 83 84 def __gt__(self, other): 85 return self.__tagClassId > other 86 87 def __ge__(self, other): 88 return self.__tagClassId >= other 89 90 def __hash__(self): 91 return self.__hash 92 93 def __getitem__(self, idx): 94 if idx == 0: 95 return self.__tagClass 96 elif idx == 1: 97 return self.__tagFormat 98 elif idx == 2: 99 return self.__tagId 100 else: 101 raise IndexError() 102 103 def __iter__(self): 104 yield self.__tagClass 105 yield self.__tagFormat 106 yield self.__tagId 107 108 def __and__(self, otherTag): 109 return self.__class__(self.__tagClass & otherTag.tagClass, 110 self.__tagFormat & otherTag.tagFormat, 111 self.__tagId & otherTag.tagId) 112 113 def __or__(self, otherTag): 114 return self.__class__(self.__tagClass | otherTag.tagClass, 115 self.__tagFormat | otherTag.tagFormat, 116 self.__tagId | otherTag.tagId) 117 118 @property 119 def tagClass(self): 120 """ASN.1 tag class 121 122 Returns 123 ------- 124 : :py:class:`int` 125 Tag class 126 """ 127 return self.__tagClass 128 129 @property 130 def tagFormat(self): 131 """ASN.1 tag format 132 133 Returns 134 ------- 135 : :py:class:`int` 136 Tag format 137 """ 138 return self.__tagFormat 139 140 @property 141 def tagId(self): 142 """ASN.1 tag ID 143 144 Returns 145 ------- 146 : :py:class:`int` 147 Tag ID 148 """ 149 return self.__tagId 150 151 152class TagSet(object): 153 """Create a collection of ASN.1 tags 154 155 Represents a combination of :class:`~pyasn1.type.tag.Tag` objects 156 that can be attached to a ASN.1 type to make types distinguishable 157 from each other. 158 159 *TagSet* objects are immutable and duck-type Python :class:`tuple` objects 160 holding arbitrary number of :class:`~pyasn1.type.tag.Tag` objects. 161 162 Parameters 163 ---------- 164 baseTag: :class:`~pyasn1.type.tag.Tag` 165 Base *Tag* object. This tag survives IMPLICIT tagging. 166 167 *superTags: :class:`~pyasn1.type.tag.Tag` 168 Additional *Tag* objects taking part in subtyping. 169 170 Examples 171 -------- 172 .. code-block:: python 173 174 class OrderNumber(NumericString): 175 ''' 176 ASN.1 specification 177 178 Order-number ::= 179 [APPLICATION 5] IMPLICIT NumericString 180 ''' 181 tagSet = NumericString.tagSet.tagImplicitly( 182 Tag(tagClassApplication, tagFormatSimple, 5) 183 ) 184 185 orderNumber = OrderNumber('1234') 186 """ 187 def __init__(self, baseTag=(), *superTags): 188 self.__baseTag = baseTag 189 self.__superTags = superTags 190 self.__superTagsClassId = tuple( 191 [(superTag.tagClass, superTag.tagId) for superTag in superTags] 192 ) 193 self.__lenOfSuperTags = len(superTags) 194 self.__hash = hash(self.__superTagsClassId) 195 196 def __repr__(self): 197 representation = '-'.join(['%s:%s:%s' % (x.tagClass, x.tagFormat, x.tagId) 198 for x in self.__superTags]) 199 if representation: 200 representation = 'tags ' + representation 201 else: 202 representation = 'untagged' 203 204 return '<%s object, %s>' % (self.__class__.__name__, representation) 205 206 def __add__(self, superTag): 207 return self.__class__(self.__baseTag, *self.__superTags + (superTag,)) 208 209 def __radd__(self, superTag): 210 return self.__class__(self.__baseTag, *(superTag,) + self.__superTags) 211 212 def __getitem__(self, i): 213 if i.__class__ is slice: 214 return self.__class__(self.__baseTag, *self.__superTags[i]) 215 else: 216 return self.__superTags[i] 217 218 def __eq__(self, other): 219 return self.__superTagsClassId == other 220 221 def __ne__(self, other): 222 return self.__superTagsClassId != other 223 224 def __lt__(self, other): 225 return self.__superTagsClassId < other 226 227 def __le__(self, other): 228 return self.__superTagsClassId <= other 229 230 def __gt__(self, other): 231 return self.__superTagsClassId > other 232 233 def __ge__(self, other): 234 return self.__superTagsClassId >= other 235 236 def __hash__(self): 237 return self.__hash 238 239 def __len__(self): 240 return self.__lenOfSuperTags 241 242 @property 243 def baseTag(self): 244 """Return base ASN.1 tag 245 246 Returns 247 ------- 248 : :class:`~pyasn1.type.tag.Tag` 249 Base tag of this *TagSet* 250 """ 251 return self.__baseTag 252 253 @property 254 def superTags(self): 255 """Return ASN.1 tags 256 257 Returns 258 ------- 259 : :py:class:`tuple` 260 Tuple of :class:`~pyasn1.type.tag.Tag` objects that this *TagSet* contains 261 """ 262 return self.__superTags 263 264 def tagExplicitly(self, superTag): 265 """Return explicitly tagged *TagSet* 266 267 Create a new *TagSet* representing callee *TagSet* explicitly tagged 268 with passed tag(s). With explicit tagging mode, new tags are appended 269 to existing tag(s). 270 271 Parameters 272 ---------- 273 superTag: :class:`~pyasn1.type.tag.Tag` 274 *Tag* object to tag this *TagSet* 275 276 Returns 277 ------- 278 : :class:`~pyasn1.type.tag.TagSet` 279 New *TagSet* object 280 """ 281 if superTag.tagClass == tagClassUniversal: 282 raise error.PyAsn1Error("Can't tag with UNIVERSAL class tag") 283 if superTag.tagFormat != tagFormatConstructed: 284 superTag = Tag(superTag.tagClass, tagFormatConstructed, superTag.tagId) 285 return self + superTag 286 287 def tagImplicitly(self, superTag): 288 """Return implicitly tagged *TagSet* 289 290 Create a new *TagSet* representing callee *TagSet* implicitly tagged 291 with passed tag(s). With implicit tagging mode, new tag(s) replace the 292 last existing tag. 293 294 Parameters 295 ---------- 296 superTag: :class:`~pyasn1.type.tag.Tag` 297 *Tag* object to tag this *TagSet* 298 299 Returns 300 ------- 301 : :class:`~pyasn1.type.tag.TagSet` 302 New *TagSet* object 303 """ 304 if self.__superTags: 305 superTag = Tag(superTag.tagClass, self.__superTags[-1].tagFormat, superTag.tagId) 306 return self[:-1] + superTag 307 308 def isSuperTagSetOf(self, tagSet): 309 """Test type relationship against given *TagSet* 310 311 The callee is considered to be a supertype of given *TagSet* 312 tag-wise if all tags in *TagSet* are present in the callee and 313 they are in the same order. 314 315 Parameters 316 ---------- 317 tagSet: :class:`~pyasn1.type.tag.TagSet` 318 *TagSet* object to evaluate against the callee 319 320 Returns 321 ------- 322 : :py:class:`bool` 323 :obj:`True` if callee is a supertype of *tagSet* 324 """ 325 if len(tagSet) < self.__lenOfSuperTags: 326 return False 327 return self.__superTags == tagSet[:self.__lenOfSuperTags] 328 329 # Backward compatibility 330 331 def getBaseTag(self): 332 return self.__baseTag 333 334def initTagSet(tag): 335 return TagSet(tag, tag) 336