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