├── .gitignore ├── README.md ├── iec61850_mms ├── __init__.py ├── _internal.py ├── cotp.py ├── iso_8327_1.py ├── iso_8650_1 │ ├── __init__.py │ ├── ber.py │ ├── fields.py │ ├── packets.py │ ├── tags.py │ └── types.py ├── iso_8823 │ ├── __init__.py │ ├── ber.py │ ├── fields.py │ ├── packets.py │ ├── tags.py │ └── types.py ├── mms │ ├── __init__.py │ ├── ber.py │ ├── fields.py │ ├── packets.py │ ├── tags.py │ └── types.py └── tpkt.py └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.toptal.com/developers/gitignore/api/macos,linux,vim,pycharm+all,windows,sublimetext,visualstudiocode 3 | # Edit at https://www.toptal.com/developers/gitignore?templates=macos,linux,vim,pycharm+all,windows,sublimetext,visualstudiocode 4 | 5 | ### Linux ### 6 | *~ 7 | 8 | # temporary files which can be created if a process still has a handle open of a deleted file 9 | .fuse_hidden* 10 | 11 | # KDE directory preferences 12 | .directory 13 | 14 | # Linux trash folder which might appear on any partition or disk 15 | .Trash-* 16 | 17 | # .nfs files are created when an open file is removed but is still being accessed 18 | .nfs* 19 | 20 | ### macOS ### 21 | # General 22 | .DS_Store 23 | .AppleDouble 24 | .LSOverride 25 | 26 | # Icon must end with two \r 27 | Icon 28 | 29 | # Thumbnails 30 | ._* 31 | 32 | # Files that might appear in the root of a volume 33 | .DocumentRevisions-V100 34 | .fseventsd 35 | .Spotlight-V100 36 | .TemporaryItems 37 | .Trashes 38 | .VolumeIcon.icns 39 | .com.apple.timemachine.donotpresent 40 | 41 | # Directories potentially created on remote AFP share 42 | .AppleDB 43 | .AppleDesktop 44 | Network Trash Folder 45 | Temporary Items 46 | .apdisk 47 | 48 | ### PyCharm+all ### 49 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 50 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 51 | 52 | # User-specific stuff 53 | .idea/**/workspace.xml 54 | .idea/**/tasks.xml 55 | .idea/**/usage.statistics.xml 56 | .idea/**/dictionaries 57 | .idea/**/shelf 58 | 59 | # Generated files 60 | .idea/**/contentModel.xml 61 | 62 | # Sensitive or high-churn files 63 | .idea/**/dataSources/ 64 | .idea/**/dataSources.ids 65 | .idea/**/dataSources.local.xml 66 | .idea/**/sqlDataSources.xml 67 | .idea/**/dynamic.xml 68 | .idea/**/uiDesigner.xml 69 | .idea/**/dbnavigator.xml 70 | 71 | # Gradle 72 | .idea/**/gradle.xml 73 | .idea/**/libraries 74 | 75 | # Gradle and Maven with auto-import 76 | # When using Gradle or Maven with auto-import, you should exclude module files, 77 | # since they will be recreated, and may cause churn. Uncomment if using 78 | # auto-import. 79 | # .idea/artifacts 80 | # .idea/compiler.xml 81 | # .idea/jarRepositories.xml 82 | # .idea/modules.xml 83 | # .idea/*.iml 84 | # .idea/modules 85 | # *.iml 86 | # *.ipr 87 | 88 | # CMake 89 | cmake-build-*/ 90 | 91 | # Mongo Explorer plugin 92 | .idea/**/mongoSettings.xml 93 | 94 | # File-based project format 95 | *.iws 96 | 97 | # IntelliJ 98 | out/ 99 | 100 | # mpeltonen/sbt-idea plugin 101 | .idea_modules/ 102 | 103 | # JIRA plugin 104 | atlassian-ide-plugin.xml 105 | 106 | # Cursive Clojure plugin 107 | .idea/replstate.xml 108 | 109 | # Crashlytics plugin (for Android Studio and IntelliJ) 110 | com_crashlytics_export_strings.xml 111 | crashlytics.properties 112 | crashlytics-build.properties 113 | fabric.properties 114 | 115 | # Editor-based Rest Client 116 | .idea/httpRequests 117 | 118 | # Android studio 3.1+ serialized cache file 119 | .idea/caches/build_file_checksums.ser 120 | 121 | ### PyCharm+all Patch ### 122 | # Ignores the whole .idea folder and all .iml files 123 | # See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 124 | 125 | .idea/ 126 | 127 | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 128 | 129 | *.iml 130 | modules.xml 131 | .idea/misc.xml 132 | *.ipr 133 | 134 | # Sonarlint plugin 135 | .idea/sonarlint 136 | 137 | ### SublimeText ### 138 | # Cache files for Sublime Text 139 | *.tmlanguage.cache 140 | *.tmPreferences.cache 141 | *.stTheme.cache 142 | 143 | # Workspace files are user-specific 144 | *.sublime-workspace 145 | 146 | # Project files should be checked into the repository, unless a significant 147 | # proportion of contributors will probably not be using Sublime Text 148 | # *.sublime-project 149 | 150 | # SFTP configuration file 151 | sftp-config.json 152 | 153 | # Package control specific files 154 | Package Control.last-run 155 | Package Control.ca-list 156 | Package Control.ca-bundle 157 | Package Control.system-ca-bundle 158 | Package Control.cache/ 159 | Package Control.ca-certs/ 160 | Package Control.merged-ca-bundle 161 | Package Control.user-ca-bundle 162 | oscrypto-ca-bundle.crt 163 | bh_unicode_properties.cache 164 | 165 | # Sublime-github package stores a github token in this file 166 | # https://packagecontrol.io/packages/sublime-github 167 | GitHub.sublime-settings 168 | 169 | ### Vim ### 170 | # Swap 171 | [._]*.s[a-v][a-z] 172 | !*.svg # comment out if you don't need vector files 173 | [._]*.sw[a-p] 174 | [._]s[a-rt-v][a-z] 175 | [._]ss[a-gi-z] 176 | [._]sw[a-p] 177 | 178 | # Session 179 | Session.vim 180 | Sessionx.vim 181 | 182 | # Temporary 183 | .netrwhist 184 | # Auto-generated tag files 185 | tags 186 | # Persistent undo 187 | [._]*.un~ 188 | 189 | ### VisualStudioCode ### 190 | .vscode/* 191 | !.vscode/settings.json 192 | !.vscode/tasks.json 193 | !.vscode/launch.json 194 | !.vscode/extensions.json 195 | *.code-workspace 196 | 197 | ### VisualStudioCode Patch ### 198 | # Ignore all local history of files 199 | .history 200 | 201 | ### Windows ### 202 | # Windows thumbnail cache files 203 | Thumbs.db 204 | Thumbs.db:encryptable 205 | ehthumbs.db 206 | ehthumbs_vista.db 207 | 208 | # Dump file 209 | *.stackdump 210 | 211 | # Folder config file 212 | [Dd]esktop.ini 213 | 214 | # Recycle Bin used on file shares 215 | $RECYCLE.BIN/ 216 | 217 | # Windows Installer files 218 | *.cab 219 | *.msi 220 | *.msix 221 | *.msm 222 | *.msp 223 | 224 | # Windows shortcuts 225 | *.lnk 226 | 227 | ### Python ### 228 | # Byte-compiled / optimized / DLL files 229 | __pycache__/ 230 | *.py[cod] 231 | *$py.class 232 | 233 | # C extensions 234 | *.so 235 | 236 | # Distribution / packaging 237 | .Python 238 | build/ 239 | develop-eggs/ 240 | dist/ 241 | downloads/ 242 | eggs/ 243 | .eggs/ 244 | lib/ 245 | lib64/ 246 | parts/ 247 | sdist/ 248 | var/ 249 | wheels/ 250 | pip-wheel-metadata/ 251 | share/python-wheels/ 252 | *.egg-info/ 253 | .installed.cfg 254 | *.egg 255 | MANIFEST 256 | 257 | # PyInstaller 258 | # Usually these files are written by a python script from a template 259 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 260 | *.manifest 261 | *.spec 262 | 263 | # Installer logs 264 | pip-log.txt 265 | pip-delete-this-directory.txt 266 | 267 | # Unit test / coverage reports 268 | htmlcov/ 269 | .tox/ 270 | .nox/ 271 | .coverage 272 | .coverage.* 273 | .cache 274 | nosetests.xml 275 | coverage.xml 276 | *.cover 277 | *.py,cover 278 | .hypothesis/ 279 | .pytest_cache/ 280 | pytestdebug.log 281 | 282 | # Translations 283 | *.mo 284 | *.pot 285 | 286 | # Django stuff: 287 | *.log 288 | local_settings.py 289 | db.sqlite3 290 | db.sqlite3-journal 291 | 292 | # Flask stuff: 293 | instance/ 294 | .webassets-cache 295 | 296 | # Scrapy stuff: 297 | .scrapy 298 | 299 | # Sphinx documentation 300 | docs/_build/ 301 | doc/_build/ 302 | 303 | # PyBuilder 304 | target/ 305 | 306 | # Jupyter Notebook 307 | .ipynb_checkpoints 308 | 309 | # IPython 310 | profile_default/ 311 | ipython_config.py 312 | 313 | # pyenv 314 | .python-version 315 | 316 | # pipenv 317 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 318 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 319 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 320 | # install all needed dependencies. 321 | #Pipfile.lock 322 | 323 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 324 | __pypackages__/ 325 | 326 | # Celery stuff 327 | celerybeat-schedule 328 | celerybeat.pid 329 | 330 | # SageMath parsed files 331 | *.sage.py 332 | 333 | # Environments 334 | .env 335 | .venv 336 | env/ 337 | venv/ 338 | ENV/ 339 | env.bak/ 340 | venv.bak/ 341 | 342 | # Spyder project settings 343 | .spyderproject 344 | .spyproject 345 | 346 | # Rope project settings 347 | .ropeproject 348 | 349 | # mkdocs documentation 350 | /site 351 | 352 | # mypy 353 | .mypy_cache/ 354 | .dmypy.json 355 | dmypy.json 356 | 357 | # Pyre type checker 358 | .pyre/ 359 | 360 | # pytype static type analyzer 361 | .pytype/ 362 | 363 | # End of https://www.toptal.com/developers/gitignore/api/macos,linux,vim,pycharm+all,windows,sublimetext,visualstudiocode 364 | 365 | # sorry, those are mine :-) 366 | *.asn 367 | *.pcap 368 | test.py 369 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iec61850_mms_scapy 2 | 3 | Scapy definitions (partially ASN.1) for a small subset of IEC 61850-8-1 MMS messages. 4 | Basic functionality of intermediary layers (tpkt, cotp, iso8327-1, iso8823, and iso8650-1) has been implemented. 5 | 6 | To bind layers, run: 7 | 8 | ```python 9 | import iec61850_mms 10 | iec61850_mms.bind_layers() 11 | ``` 12 | 13 | ### Supported packet types 14 | ```plain 15 | MMS: 16 | - ConfirmedRequest (read, write, getnamelist) 17 | - InitiateRequest 18 | - InitiateResponse 19 | 20 | ACSE/ISO 8650-1: 21 | - AARQ 22 | - AARE 23 | 24 | ISO 8823: 25 | - CP 26 | - CPA 27 | - CPC 28 | 29 | ISO 8327-1: 30 | - User Data (DT) 31 | - Connect (CN) 32 | - Accept (AC) 33 | 34 | COTP: 35 | - Data (DT) 36 | - Connection Requests (CR) 37 | - Connection Responses (CC) 38 | ``` 39 | -------------------------------------------------------------------------------- /iec61850_mms/__init__.py: -------------------------------------------------------------------------------- 1 | from . import tpkt 2 | from . import cotp 3 | from . import iso_8327_1 4 | from . import iso_8823 5 | from . import iso_8650_1 6 | 7 | from .tpkt import TPKT 8 | from .cotp import COTP_Data, COTP_Connection_Confirm, COTP, COTP_Connection_Request 9 | from .iso_8327_1 import ISO_8327_1_Session, ISO_8327_1_Session_User_Data, ISO_8327_1_Session_Accept, \ 10 | ISO_8327_1_Session_Connect 11 | from .iso_8823 import ISO_8823_Presentation_CP_Type, ISO_8823_Presentation_CPA_Type, ISO_8823_Presentation_CPC_Type 12 | from .iso_8650_1 import AARE, AARQ, ACSE 13 | from .mms import MMS, MMS_Confirmed_Request_PDU, MMS_Initiate_Response_PDU, MMS_Initiate_Request_PDU 14 | 15 | 16 | def bind_layers(): 17 | from scapy.all import bind_layers 18 | from scapy.layers.inet import TCP 19 | from .iso_8327_1 import ISO_8327_1_Session_Dummy 20 | from ._internal import Pseudo_Layer 21 | # TPKT is nowadays above tcp and usually on port 102 22 | bind_layers(TCP, TPKT, sport=tpkt.TPKT_ISO_TSAP_PORT) 23 | bind_layers(TCP, TPKT, dport=tpkt.TPKT_ISO_TSAP_PORT) 24 | # cotp 25 | bind_layers(TPKT, COTP) 26 | # ISO 8327_1, Session establishment should be in a COTP Data PDU 27 | # YET!! MMS may be layered right on top of COTP in a minimized network stack... so bind the next layer to a 28 | # pseudo-layer that guesses the right class. 29 | bind_layers(COTP_Data, Pseudo_Layer) 30 | # ISO 8823, this is where it gets tricky... 31 | bind_layers(ISO_8327_1_Session_Accept, ISO_8823_Presentation_CPA_Type) 32 | bind_layers(ISO_8327_1_Session_Dummy, ISO_8823_Presentation_CPC_Type) 33 | bind_layers(ISO_8327_1_Session_Connect, ISO_8823_Presentation_CP_Type) 34 | # Up to ISO 8823, everything is a tidy scapy layer. However, all layers including and above ISO 8823 is ASN.1. 35 | # I didn't find another way than injecting ASN.1-defined PDUs into each other. Thus, everything above presentation 36 | # layer is a cluster of nested scapy ASN.1-engine objects. Harder to dissect in scripts :-/ any suggestions? 37 | -------------------------------------------------------------------------------- /iec61850_mms/_internal.py: -------------------------------------------------------------------------------- 1 | from scapy.packet import Packet, Raw 2 | from .mms import MMS 3 | from .iso_8327_1 import ISO_8327_1_Session 4 | 5 | 6 | class Pseudo_Layer(Packet): 7 | def guess_payload_class(self, payload): 8 | res = ISO_8327_1_Session().guess_payload_class(payload) 9 | return res if res != Raw else MMS 10 | -------------------------------------------------------------------------------- /iec61850_mms/cotp.py: -------------------------------------------------------------------------------- 1 | """ 2 | Basic Scapy Definitions for COTP (ISO 8327/X.225 - Connection-Oriented Transport Protocol) 3 | 4 | Source documents for these definitions: 5 | - https://www.itu.int/rec/T-REC-X.225-199511-I/en 6 | - https://www.fit.vut.cz/research/publication-file/11832/TR-61850.pdf 7 | 8 | Limited Support for: 9 | - Data (DT) 10 | - Connection Requests (CR) 11 | - Connection Responses (CC) 12 | """ 13 | 14 | 15 | from scapy.packet import Packet 16 | from scapy.fields import ByteField, LenField, ShortField, StrLenField, \ 17 | BitField, PacketListField, FieldLenField 18 | 19 | 20 | class COTP_Parameter(Packet): 21 | name = "COTP Parameter" 22 | fields_desc = [ByteField("code", None), 23 | FieldLenField("length", None, fmt="B", length_of="value"), 24 | StrLenField("value", None, length_from=lambda x: x.length)] 25 | 26 | def extract_padding(self, s): 27 | return '', s 28 | 29 | 30 | class COTP_Connection_Request(Packet): 31 | name = "COTP Connection Request (CR)" 32 | fields_desc = [LenField("length", None, fmt="!B", adjust=lambda x: x + 5), 33 | ByteField("tpdu_code", 0xd0), 34 | ShortField("destination_reference", None), 35 | ShortField("source_reference", None), 36 | BitField("class", 0, 4), 37 | BitField("reserved", 0, 2), 38 | BitField("extended_format", 0, 1), 39 | BitField("explicit", 0, 1), 40 | PacketListField("parameters", None, COTP_Parameter)] 41 | 42 | 43 | class COTP_Connection_Confirm(Packet): 44 | name = "COTP Connection Confirm (CC)" 45 | fields_desc = COTP_Connection_Request.fields_desc 46 | 47 | 48 | class COTP_Data(Packet): 49 | name = "COTP Data (DT)" 50 | fields_desc = [ByteField("length", 2), 51 | ByteField("tpdu_code", 0x0f), 52 | BitField("last_data_unit", 1, 1), 53 | BitField("tpdu_number", 0, 7)] 54 | 55 | 56 | masked_tpdu_types = { 57 | 0b1110: COTP_Connection_Request, # CR 58 | 0b1101: COTP_Connection_Confirm, # CC 59 | # 0b0110: None, # AK, not required for MMS 60 | # 0b0101: None, # RJ, not required for MMS 61 | } 62 | 63 | 64 | fixed_tpdu_types = { 65 | # 0b10000000: None, # DR, not required for MMS 66 | # 0b11000000: None, # DC, not required for MMS 67 | 0b11110000: COTP_Data, # DT 68 | # 0b00010000: None, # ED, not required for MMS 69 | # 0b00100000: None, # EA, not required for MMS 70 | # 0b01110000: None, # ER, not required for MMS 71 | } 72 | 73 | 74 | class COTP(Packet): 75 | def guess_payload_class(self, payload): 76 | ln = len(payload) 77 | if ln < 2: 78 | return self.default_payload_class(payload) 79 | tpdu_code = int(payload[1]) 80 | cls = None 81 | 82 | if tpdu_code in fixed_tpdu_types: 83 | cls = fixed_tpdu_types[tpdu_code] 84 | 85 | if cls is not None: 86 | return cls 87 | tpdu_code >>= 0x04 88 | if tpdu_code in masked_tpdu_types: 89 | cls = masked_tpdu_types[tpdu_code] 90 | 91 | return cls if cls is not None else self.default_payload_class(payload) 92 | 93 | 94 | -------------------------------------------------------------------------------- /iec61850_mms/iso_8327_1.py: -------------------------------------------------------------------------------- 1 | """ 2 | Basic Scapy Definitions for the ISO 8327-1 session protocol 3 | 4 | Source documents for these definitions: 5 | - https://github.com/boundary/wireshark/blob/master/epan/dissectors/packet-ses.h 6 | - https://github.com/boundary/wireshark/blob/master/epan/dissectors/packet-ses.c 7 | 8 | Limited Support for: 9 | - User Data (DT) 10 | - Connect (CN) 11 | - Accept (AC) 12 | - A Dummy to skip multi-layered DT / GIVE-PDU 13 | """ 14 | 15 | 16 | from scapy.packet import Packet 17 | from scapy.fields import ByteField, LenField, StrLenField, PacketField, FieldLenField, PacketListField 18 | 19 | 20 | class ISO_8327_1_Session_Protocol_Parameter(Packet): 21 | name = "ISO 8327-1 Session Protocol Parameter" 22 | fields_desc = [ByteField("type", 0x05), 23 | FieldLenField("length", None, fmt="B", 24 | length_of="parameter_value"), 25 | StrLenField("value", None, 26 | length_from=lambda x: x.length)] 27 | 28 | def extract_padding(self, s): 29 | return '', s 30 | 31 | 32 | class ISO_8327_1_Session_User_Data(Packet): 33 | name = "ISO 8327-1 User Data" 34 | fields_desc = [ByteField("spdu_type", 193), 35 | ByteField("length", None)] 36 | 37 | def extract_padding(self, s): 38 | return '', s 39 | 40 | 41 | class ISO_8327_1_Session_Dummy(Packet): 42 | name = "ISO 8327-1 Dummy PDU" 43 | fields_desc = [ByteField("pdu_type", 1), 44 | ByteField("length1", None), 45 | ByteField("spdu_type", 1), 46 | ByteField("length2", None)] 47 | 48 | 49 | class ISO_8327_1_Session_Connect(Packet): 50 | name = "ISO 8327-1 Session Connect" 51 | fields_desc = [ByteField("spdu_type", 0x0d), 52 | LenField("length", None, 53 | fmt="!B", adjust=lambda pkt, x: len(pkt) + x), 54 | PacketListField("parameters", None, 55 | ISO_8327_1_Session_Protocol_Parameter, 56 | count_from=lambda x: 4), 57 | PacketField("user_data", None, ISO_8327_1_Session_User_Data)] 58 | 59 | 60 | class ISO_8327_1_Session_Accept(Packet): 61 | name = "ISO 8327-1 Session Accept" 62 | fields_desc = [ByteField("spdu_type", 0x0e), 63 | LenField("length", None, 64 | fmt="!B", adjust=lambda pkt, x: len(pkt) + x), 65 | PacketListField("parameters", None, 66 | ISO_8327_1_Session_Protocol_Parameter, 67 | count_from=lambda x: 3), 68 | PacketField("user_data", None, ISO_8327_1_Session_User_Data)] 69 | 70 | 71 | SPDU_TYPES = { 72 | 0x0d: ISO_8327_1_Session_Connect, # Connect SPDU (CN) 73 | 0x0e: ISO_8327_1_Session_Accept, # Accept SPDU (AC) 74 | 0x01: ISO_8327_1_Session_Dummy, # Dummy (in order to skip right to data) 75 | } 76 | 77 | 78 | class ISO_8327_1_Session(Packet): 79 | def guess_payload_class(self, payload): 80 | ln = len(payload) 81 | if ln < 1 or int(payload[0]) not in SPDU_TYPES: 82 | return self.default_payload_class(payload) 83 | return SPDU_TYPES[int(payload[0])] 84 | -------------------------------------------------------------------------------- /iec61850_mms/iso_8650_1/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Basic scapy asn.1 defintions for ISO 8650-1 (ACSE) 3 | 4 | Source documents for these definitions: 5 | - https://www.itu.int/ITU-T/formal-language/itu-t/x/x227/1995/ACSE-1.html 6 | - https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-X.227-199504-I!!PDF-E&type=items 7 | 8 | Supported types: 9 | - AARQ 10 | - AARE 11 | """ 12 | from .tags import * 13 | from .ber import * 14 | from .fields import * 15 | from .types import * 16 | from .packets import * 17 | 18 | from .packets import ACSE, AARQ, AARE 19 | -------------------------------------------------------------------------------- /iec61850_mms/iso_8650_1/ber.py: -------------------------------------------------------------------------------- 1 | """ 2 | BER codec en-/decoders for ISO 8650-1 / ACSE 3 | """ 4 | from scapy.asn1.ber import * 5 | from .tags import ASN1_Tags_ACSE 6 | 7 | 8 | class BER_Codec_AARQ_TYPE(BERcodec_SEQUENCE): 9 | tag = ASN1_Tags_ACSE.AARQ_TYPE_TAG 10 | 11 | 12 | class BER_Codec_APPLICATION_CONTEXT_NAME(BERcodec_OID): 13 | tag = ASN1_Tags_ACSE.APPLICATION_CONTEXT_NAME_TAG 14 | 15 | 16 | class BER_Codec_CALLED_AP_TITLE_FORM_2(BERcodec_OID): 17 | tag = ASN1_Tags_ACSE.CALLED_AP_TITLE_FORM_2_TAG 18 | 19 | 20 | class BER_Codec_CALLED_AE_QUALIFIER_FORM_2(BERcodec_INTEGER): 21 | tag = ASN1_Tags_ACSE.CALLED_AE_QUALIFIER_FORM_2_TAG 22 | 23 | 24 | class BER_Codec_CALLING_AP_TITLE_FORM_2(BERcodec_OID): 25 | tag = ASN1_Tags_ACSE.CALLING_AP_TITLE_FORM_2_TAG 26 | 27 | 28 | class BER_Codec_CALLING_AE_QUALIFIER_FORM_2(BERcodec_INTEGER): 29 | tag = ASN1_Tags_ACSE.CALLING_AE_QUALIFIER_FORM_2_TAG 30 | 31 | 32 | class BER_Codec_USER_INFORMATION(BERcodec_SEQUENCE): 33 | tag = ASN1_Tags_ACSE.USER_INFORMATION_TAG 34 | 35 | 36 | class BER_Codec_EXTERNAL_T(BERcodec_SEQUENCE): 37 | tag = ASN1_Tags_ACSE.EXTERNAL_T_TAG 38 | 39 | 40 | class BER_Codec_INDIRECT_REFERENCE(BERcodec_INTEGER): 41 | tag = ASN1_Tags_ACSE.INDIRECT_REFERENCE_TAG 42 | 43 | 44 | class BER_Codec_ACSE_MMS_DATA(BERcodec_SEQUENCE): 45 | tag = ASN1_Tags_ACSE.MMS_DATA_TAG 46 | 47 | 48 | class BER_Codec_AARE_TYPE(BERcodec_SEQUENCE): 49 | tag = ASN1_Tags_ACSE.AARE_TYPE_TAG 50 | 51 | 52 | class BER_Codec_AARE_RESULT_TYPE(BERcodec_INTEGER): 53 | tag = ASN1_Tags_ACSE.AARE_RESULT_TYPE_TAG 54 | 55 | 56 | 57 | class BER_Codec_ACSE_SERVICE_USER(BERcodec_INTEGER): 58 | tag = ASN1_Tags_ACSE.ACSE_SERVICE_USER_TAG 59 | -------------------------------------------------------------------------------- /iec61850_mms/iso_8650_1/fields.py: -------------------------------------------------------------------------------- 1 | """ 2 | ISO 8650-1 (ACSE) Fields 3 | """ 4 | from scapy.asn1fields import * 5 | from .tags import ASN1_Tags_ACSE 6 | 7 | 8 | class ASN1F_AARQ_TYPE(ASN1F_SEQUENCE): 9 | ASN1_tag = ASN1_Tags_ACSE.AARQ_TYPE_TAG 10 | 11 | 12 | class ASN1F_AARE_TYPE(ASN1F_SEQUENCE): 13 | ASN1_tag = ASN1_Tags_ACSE.AARE_TYPE_TAG 14 | 15 | 16 | class ASN1F_APPLICATION_CONTEXT_NAME(ASN1F_OID): 17 | ASN1_tag = ASN1_Tags_ACSE.APPLICATION_CONTEXT_NAME_TAG 18 | 19 | 20 | class ASN1F_CALLED_AP_TITLE_FORM_2(ASN1F_OID): 21 | ASN1_tag = ASN1_Tags_ACSE.CALLED_AP_TITLE_FORM_2_TAG 22 | 23 | 24 | class ASN1F_CALLED_AE_QUALIFIER_FORM_2(ASN1F_INTEGER): 25 | ASN1_tag = ASN1_Tags_ACSE.CALLED_AE_QUALIFIER_FORM_2_TAG 26 | 27 | 28 | class ASN1F_AARE_RESULT_TYPE(ASN1F_enum_INTEGER): 29 | ASN1_tag = ASN1_Tags_ACSE.AARE_RESULT_TYPE_TAG 30 | 31 | 32 | class ASN1F_ACSE_SERVICE_USER(ASN1F_enum_INTEGER): 33 | ASN1_tag = ASN1_Tags_ACSE.ACSE_SERVICE_USER_TAG 34 | 35 | 36 | class ASN1F_CALLING_AP_TITLE_FORM_2(ASN1F_OID): 37 | ASN1_tag = ASN1_Tags_ACSE.CALLING_AP_TITLE_FORM_2_TAG 38 | 39 | 40 | class ASN1F_CALLING_AE_QUALIFIER_FORM_2(ASN1F_INTEGER): 41 | ASN1_tag = ASN1_Tags_ACSE.CALLING_AE_QUALIFIER_FORM_2_TAG 42 | 43 | 44 | class ASN1F_USER_INFORMATION(ASN1F_SEQUENCE): 45 | ASN1_tag = ASN1_Tags_ACSE.USER_INFORMATION_TAG 46 | 47 | 48 | class ASN1F_EXTERNAL_T(ASN1F_SEQUENCE): 49 | ASN1_tag = ASN1_Tags_ACSE.EXTERNAL_T_TAG 50 | 51 | 52 | class ASN1F_INDIRECT_REFERENCE(ASN1F_INTEGER): 53 | ASN1_tag = ASN1_Tags_ACSE.INDIRECT_REFERENCE_TAG 54 | 55 | 56 | class ASN1F_ACSE_MMS_DATA(ASN1F_SEQUENCE): 57 | ASN1_tag = ASN1_Tags_ACSE.MMS_DATA_TAG 58 | -------------------------------------------------------------------------------- /iec61850_mms/iso_8650_1/packets.py: -------------------------------------------------------------------------------- 1 | """ 2 | ISO 8650-1 (ACSE) Packet/PDU Definitions 3 | """ 4 | from scapy.asn1packet import * 5 | from scapy.asn1.asn1 import ASN1_Codecs 6 | from .fields import * 7 | from ..mms import MMS 8 | 9 | 10 | class CALLED_AP_TITLE_FORM_2(ASN1_Packet): 11 | ASN1_codec = ASN1_Codecs.BER 12 | ASN1_root = ASN1F_CALLED_AP_TITLE_FORM_2("called_ap_title_form_2", None) 13 | 14 | 15 | class CALLED_AE_QUALIFIER_FORM_2(ASN1_Packet): 16 | ASN1_codec = ASN1_Codecs.BER 17 | ASN1_root = ASN1F_CALLED_AE_QUALIFIER_FORM_2( 18 | "called_ae_qualifier_form_2", 0) 19 | 20 | 21 | class CALLING_AP_TITLE_FORM_2(ASN1_Packet): 22 | ASN1_codec = ASN1_Codecs.BER 23 | ASN1_root = ASN1F_CALLING_AP_TITLE_FORM_2("calling_ap_title_form_2", None) 24 | 25 | 26 | class CALLING_AE_QUALIFIER_FORM_2(ASN1_Packet): 27 | ASN1_codec = ASN1_Codecs.BER 28 | ASN1_root = ASN1F_CALLING_AE_QUALIFIER_FORM_2( 29 | "calling_ae_qualifier_form_2", 0) 30 | 31 | 32 | class ACSE_SERVICE_USER(ASN1_Packet): 33 | ASN1_codec = ASN1_Codecs.BER 34 | ASN1_root = ASN1F_ACSE_SERVICE_USER( 35 | "service_user", 0, enum=[x for x in range(0, 15)]) 36 | 37 | 38 | class AARE(ASN1_Packet): 39 | ASN1_codec = ASN1_Codecs.BER 40 | ASN1_root = ASN1F_AARE_TYPE( 41 | ASN1F_APPLICATION_CONTEXT_NAME("application_context_name", None), 42 | ASN1F_AARE_RESULT_TYPE("result", 0, enum=[0, 1, 2]), 43 | ASN1F_CHOICE( 44 | "acse_service_user", 45 | None, 46 | ACSE_SERVICE_USER 47 | ), 48 | ASN1F_USER_INFORMATION( 49 | ASN1F_EXTERNAL_T( 50 | ASN1F_INDIRECT_REFERENCE("indirect_reference", 0), 51 | ASN1F_ACSE_MMS_DATA( 52 | ASN1F_CHOICE( 53 | "MMS_PDU", 54 | None, 55 | MMS 56 | ) 57 | ) 58 | ), 59 | ) 60 | ) 61 | 62 | 63 | class AARQ(ASN1_Packet): 64 | ASN1_codec = ASN1_Codecs.BER 65 | ASN1_root = ASN1F_AARQ_TYPE( 66 | ASN1F_APPLICATION_CONTEXT_NAME("application_context_name", None), 67 | ASN1F_CHOICE( 68 | "called_ap_title", 69 | None, 70 | CALLED_AP_TITLE_FORM_2 71 | ), 72 | ASN1F_CHOICE( 73 | "called_ae_qualifier", 74 | None, 75 | CALLED_AE_QUALIFIER_FORM_2 76 | ), 77 | ASN1F_CHOICE( 78 | "calling_ap_title", 79 | None, 80 | CALLING_AP_TITLE_FORM_2 81 | ), 82 | ASN1F_CHOICE( 83 | "calling_ae_qualifier", 84 | None, 85 | CALLING_AE_QUALIFIER_FORM_2 86 | ), 87 | ASN1F_USER_INFORMATION( 88 | ASN1F_EXTERNAL_T( 89 | ASN1F_INDIRECT_REFERENCE("indirect_reference", 0), 90 | ASN1F_ACSE_MMS_DATA( 91 | ASN1F_CHOICE( 92 | "MMS_PDU", 93 | None, 94 | MMS 95 | ) 96 | ) 97 | ), 98 | ) 99 | ) 100 | 101 | 102 | class ACSE(ASN1_Packet): 103 | ASN1_codec = ASN1_Codecs.BER 104 | ASN1_root = ASN1F_CHOICE( 105 | "ACSE", # name 106 | AARQ(), # default 107 | AARQ, 108 | AARE 109 | ) 110 | -------------------------------------------------------------------------------- /iec61850_mms/iso_8650_1/tags.py: -------------------------------------------------------------------------------- 1 | """ 2 | ISO 8650-1 (ACSE) Tags 3 | 4 | Tags from: 5 | - https://www.itu.int/ITU-T/formal-language/itu-t/x/x227/1995/ACSE-1.html 6 | """ 7 | from scapy.asn1.asn1 import * 8 | 9 | 10 | class ASN1_Tags_ACSE(ASN1_Class_UNIVERSAL): 11 | name = "ACSE" 12 | 13 | AARQ_TYPE_TAG = 0x60 14 | AARE_TYPE_TAG = 0x61 15 | APPLICATION_CONTEXT_NAME_TAG = 0xa1 16 | CALLED_AP_TITLE_FORM_2_TAG = 0xa2 17 | CALLED_AE_QUALIFIER_FORM_2_TAG = 0xa3 18 | CALLING_AP_TITLE_FORM_2_TAG = 0xa6 19 | CALLING_AE_QUALIFIER_FORM_2_TAG = 0xa7 20 | USER_INFORMATION_TAG = 0xbe 21 | EXTERNAL_T_TAG = 0x28 22 | AARE_RESULT_TYPE_TAG = 0xa2 23 | ACSE_SERVICE_USER_TAG = 0xa3 24 | INDIRECT_REFERENCE_TAG = 0x02 25 | MMS_DATA_TAG = 0xa0 26 | 27 | 28 | 29 | 30 | # CP-type ::= SET { 31 | # mode-selector [0] IMPLICIT Mode-selector, #### <-------- DONE 32 | # normal-mode-parameters #### <-------- CHECK 33 | # [2] IMPLICIT SEQUENCE { 34 | # calling-presentation-selector #### <-------- CHECK 35 | # [1] IMPLICIT Calling-presentation-selector 36 | # OPTIONAL, 37 | # called-presentation-selector #### <-------- CHECK 38 | # [2] IMPLICIT Called-presentation-selector OPTIONAL, 39 | # presentation-context-definition-list #### <-------- CHECK 40 | # [4] IMPLICIT Presentation-context-definition-list 41 | # OPTIONAL, 42 | # user-data #### <-------- CHECK 43 | # User-data OPTIONAL} OPTIONAL 44 | # -- Shall be used for normal mode only. 45 | # -- Shall be the parameters of the CP PPDU. 46 | # } 47 | 48 | 49 | # CPA-PPDU ::= SET { 50 | # mode-selector [0] IMPLICIT Mode-selector, 51 | # x410-mode-parameters 52 | # [1] IMPLICIT SET {COMPONENTS OF Reliable-Transfer-APDU.RTOACapdu} OPTIONAL-- This OPTIONAL element shall be absent for a 53 | # -- nested presentation connection. 54 | # -- Shall be used for X.410 mode only. Shall be bitwise 55 | # -- compatible with CCITT Recommendation X.410-1984. 56 | # -- This shall be the User data parameter of the CPA PPDU1) --, 57 | # normal-mode-parameters 58 | # [2] IMPLICIT SEQUENCE {protocol-version 59 | # [0] IMPLICIT Protocol-version DEFAULT {version-1}, 60 | # responding-presentation-selector 61 | # [3] IMPLICIT Responding-presentation-selector 62 | # OPTIONAL, 63 | # presentation-context-definition-result-list 64 | # [5] IMPLICIT Presentation-context-definition-result-list 65 | # OPTIONAL, 66 | # presentation-requirements 67 | # [8] IMPLICIT Presentation-requirements OPTIONAL, 68 | # user-session-requirements 69 | # [9] IMPLICIT User-session-requirements OPTIONAL, 70 | # -- shall not be present if equal to the Revised session 71 | # -- requirements parameter 72 | # protocol-options 73 | # [11] Protocol-options DEFAULT {}, 74 | # -- shall be absent if no options are selected 75 | # responders-nominated-context 76 | # [13] Presentation-context-identifier OPTIONAL, 77 | # -- shall only be present if nominated-context is 78 | # -- selected in protocol-options 79 | # user-data 80 | # User-data OPTIONAL} OPTIONAL 81 | # -- Shall be used for normal mode only. 82 | # } 83 | -------------------------------------------------------------------------------- /iec61850_mms/iso_8650_1/types.py: -------------------------------------------------------------------------------- 1 | """ 2 | ISO 8650-1 (ACSE) Types 3 | """ 4 | from scapy.asn1.asn1 import * 5 | from .tags import ASN1_Tags_ACSE 6 | 7 | 8 | class ASN1_AARQ_TYPE(ASN1_SEQUENCE): 9 | tag = ASN1_Tags_ACSE.AARQ_TYPE_TAG 10 | 11 | 12 | class ASN1F_APPLICATION_CONTEXT_NAME(ASN1_OID): 13 | tag = ASN1_Tags_ACSE.APPLICATION_CONTEXT_NAME_TAG 14 | 15 | 16 | class ASN1_CALLED_AP_TITLE_FORM_2(ASN1_OID): 17 | tag = ASN1_Tags_ACSE.CALLED_AP_TITLE_FORM_2_TAG 18 | 19 | 20 | class ASN1_CALLED_AE_QUALIFIER_FORM_2(ASN1_INTEGER): 21 | tag = ASN1_Tags_ACSE.CALLED_AE_QUALIFIER_FORM_2_TAG 22 | 23 | 24 | class ASN1_CALLING_AP_TITLE_FORM_2(ASN1_OID): 25 | tag = ASN1_Tags_ACSE.CALLING_AP_TITLE_FORM_2_TAG 26 | 27 | 28 | class ASN1_CALLING_AE_QUALIFIER_FORM_2(ASN1_INTEGER): 29 | tag = ASN1_Tags_ACSE.CALLING_AE_QUALIFIER_FORM_2_TAG 30 | 31 | 32 | class ASN1_USER_INFORMATION(ASN1_SEQUENCE): 33 | tag = ASN1_Tags_ACSE.USER_INFORMATION_TAG 34 | 35 | 36 | class ASN1_EXTERNAL_T(ASN1_SEQUENCE): 37 | tag = ASN1_Tags_ACSE.EXTERNAL_T_TAG 38 | 39 | 40 | class ASN1_INDIRECT_REFERENCE(ASN1_INTEGER): 41 | tag = ASN1_Tags_ACSE.INDIRECT_REFERENCE_TAG 42 | 43 | 44 | class ASN1_ACSE_MMS_DATA(ASN1_SEQUENCE): 45 | tag = ASN1_Tags_ACSE.MMS_DATA_TAG 46 | 47 | 48 | class ASN1_AARE_TYPE(ASN1_SEQUENCE): 49 | tag = ASN1_Tags_ACSE.AARE_TYPE_TAG 50 | 51 | 52 | class ASN1_AARE_RESULT_TYPE(ASN1_INTEGER): 53 | tag = ASN1_Tags_ACSE.AARE_RESULT_TYPE_TAG 54 | 55 | 56 | class ASN1F_ACSE_SERVICE_USER(ASN1_INTEGER): 57 | tag = ASN1_Tags_ACSE.ACSE_SERVICE_USER_TAG 58 | -------------------------------------------------------------------------------- /iec61850_mms/iso_8823/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Basic scapy asn.1 defintions for the ISO 8823 presentation layer 3 | 4 | Source documents for these definitions: 5 | - https://github.com/wireshark/wireshark/blob/master/epan/dissectors/asn1/atn-ulcs/atn-ulcs.asn 6 | - https://github.com/mz-automation/libiec61850/blob/v1.4/src/mms/iso_presentation/iso_presentation.c 7 | 8 | Supported types: 9 | - CP 10 | - CPA 11 | - CPC 12 | """ 13 | 14 | from .tags import * 15 | from .ber import * 16 | from .fields import * 17 | from .types import * 18 | from .packets import * 19 | 20 | from .packets import ISO_8823_Presentation_CP_Type, ISO_8823_Presentation_CPA_Type, ISO_8823_Presentation_CPC_Type 21 | -------------------------------------------------------------------------------- /iec61850_mms/iso_8823/ber.py: -------------------------------------------------------------------------------- 1 | """ 2 | BER codec en-/decoders for ISO 8823 3 | """ 4 | from scapy.asn1.ber import BERcodec_SET, BERcodec_SEQUENCE, BERcodec_INTEGER, BERcodec_STRING, BERcodec_OID 5 | from .tags import ASN1_Tags_ISO_8823 6 | 7 | 8 | class BER_Codec_MODE_SELECTOR(BERcodec_SET): 9 | tag = ASN1_Tags_ISO_8823.MODE_SELECTOR_TAG 10 | 11 | 12 | class BER_Codec_NORMAL_MODE_PARAMETERS(BERcodec_SEQUENCE): 13 | tag = ASN1_Tags_ISO_8823.NORMAL_MODE_PARAMETERS_TAG 14 | 15 | 16 | class BER_Codec_MODE_VALUE(BERcodec_INTEGER): 17 | tag = ASN1_Tags_ISO_8823.MODE_VALUE_TAG 18 | 19 | 20 | class BER_Codec_CP_TYPE(BERcodec_SET): 21 | tag = ASN1_Tags_ISO_8823.CP_TYPE_TAG 22 | 23 | 24 | class BER_Codec_CALLING_PRESENTATION_SELECTOR(BERcodec_STRING): 25 | tag = ASN1_Tags_ISO_8823.CALLING_PRESENTATION_SELECTOR_TAG 26 | 27 | 28 | class BER_Codec_CALLED_PRESENTATION_SELECTOR(BERcodec_STRING): 29 | tag = ASN1_Tags_ISO_8823.CALLED_PRESENTATION_SELECTOR_TAG 30 | 31 | 32 | class BER_Codec_PRESENTATION_CONTEXT_DEFINITION_LIST(BERcodec_SEQUENCE): 33 | tag = ASN1_Tags_ISO_8823.PRESENTATION_CONTEXT_DEFINITION_LIST_TAG 34 | 35 | 36 | class BER_Codec_PRESENTATION_CONTEXT_IDENTIFIER(BERcodec_INTEGER): 37 | tag = ASN1_Tags_ISO_8823.PRESENTATION_CONTEXT_IDENTIFIER_TAG 38 | 39 | 40 | class BER_Codec_ABSTRACT_SYNTAX_NAME(BERcodec_OID): 41 | tag = ASN1_Tags_ISO_8823.ABSTRACT_SYNTAX_NAME_TAG 42 | 43 | 44 | class BER_Codec_TRANSFER_SYNTAX_NAME(BERcodec_OID): 45 | tag = ASN1_Tags_ISO_8823.TRANSFER_SYNTAX_NAME_TAG 46 | 47 | 48 | class BER_Codec_FULLY_ENCODED_DATA(BERcodec_SEQUENCE): 49 | tag = ASN1_Tags_ISO_8823.FULLY_ENCODED_DATA_TAG 50 | 51 | 52 | class BER_Codec_CONTENT(BERcodec_SEQUENCE): 53 | tag = ASN1_Tags_ISO_8823.CONTENT_TAG 54 | 55 | 56 | class BER_Codec_RESPONDING_PRESENTATION_SELECTOR(BERcodec_STRING): 57 | tag = ASN1_Tags_ISO_8823.RESPONDING_PRESENTATION_SELECTOR_TAG 58 | 59 | 60 | class BER_Codec_PRESENTATION_CONTEXT_DEFINITION_RESULT_LIST(BERcodec_STRING): 61 | tag = ASN1_Tags_ISO_8823.PRESENTATION_CONTEXT_DEFINITION_RESULT_LIST_TAG 62 | 63 | 64 | class BER_Codec_RESULT(BERcodec_INTEGER): 65 | tag = ASN1_Tags_ISO_8823.RESULT_TAG 66 | 67 | 68 | class BER_Codec_RESULT_LIST_TRANSFER_SYNTAX(BERcodec_OID): 69 | tag = ASN1_Tags_ISO_8823.RESULT_LIST_TRANSFER_SYNTAX_TAG 70 | -------------------------------------------------------------------------------- /iec61850_mms/iso_8823/fields.py: -------------------------------------------------------------------------------- 1 | """ 2 | ISO 8823 ASN1 field definitions 3 | """ 4 | from scapy.asn1fields import * 5 | from .tags import ASN1_Tags_ISO_8823 6 | 7 | 8 | class ASN1F_MODE_SELECTOR(ASN1F_SET): 9 | ASN1_tag = ASN1_Tags_ISO_8823.MODE_SELECTOR_TAG 10 | 11 | 12 | class ASN1F_NORMAL_MODE_PARAMETERS(ASN1F_SEQUENCE): 13 | ASN1_tag = ASN1_Tags_ISO_8823.NORMAL_MODE_PARAMETERS_TAG 14 | 15 | 16 | class ASN1F_MODE_VALUE(ASN1F_INTEGER): 17 | ASN1_tag = ASN1_Tags_ISO_8823.MODE_VALUE_TAG 18 | 19 | 20 | class ASN1F_CP_TYPE(ASN1F_SET): 21 | ASN1_tag = ASN1_Tags_ISO_8823.CP_TYPE_TAG 22 | 23 | 24 | class ASN1F_CALLING_PRESENTATION_SELECTOR(ASN1F_STRING): 25 | ASN1_tag = ASN1_Tags_ISO_8823.CALLING_PRESENTATION_SELECTOR_TAG 26 | 27 | 28 | class ASN1F_RESPONDING_PRESENTATION_SELECTOR(ASN1F_STRING): 29 | ASN1_tag = ASN1_Tags_ISO_8823.RESPONDING_PRESENTATION_SELECTOR_TAG 30 | 31 | 32 | class ASN1F_CALLED_PRESENTATION_SELECTOR(ASN1F_STRING): 33 | ASN1_tag = ASN1_Tags_ISO_8823.CALLED_PRESENTATION_SELECTOR_TAG 34 | 35 | 36 | class ASN1F_PRESENTATION_CONTEXT_DEFINITION_LIST(ASN1F_SEQUENCE_OF): 37 | ASN1_tag = ASN1_Tags_ISO_8823.PRESENTATION_CONTEXT_DEFINITION_LIST_TAG 38 | 39 | 40 | class ASN1F_PRESENTATION_CONTEXT_DEFINITION_RESULT_LIST(ASN1F_SEQUENCE_OF): 41 | ASN1_tag = ASN1_Tags_ISO_8823.PRESENTATION_CONTEXT_DEFINITION_RESULT_LIST_TAG 42 | 43 | 44 | class ASN1F_PRESENTATION_CONTEXT_IDENTIFIER(ASN1F_INTEGER): 45 | ASN1_tag = ASN1_Tags_ISO_8823.PRESENTATION_CONTEXT_IDENTIFIER_TAG 46 | 47 | 48 | class ASN1F_ABSTRACT_SYNTAX_NAME(ASN1F_OID): 49 | ASN1_tag = ASN1_Tags_ISO_8823.ABSTRACT_SYNTAX_NAME_TAG 50 | 51 | 52 | class ASN1F_TRANSFER_SYNTAX_NAME(ASN1F_OID): 53 | ASN1_tag = ASN1_Tags_ISO_8823.TRANSFER_SYNTAX_NAME_TAG 54 | 55 | 56 | class ASN1F_USER_DATA(ASN1F_CHOICE): 57 | ASN1_tag = ASN1_Tags_ISO_8823.USER_DATA_TAG 58 | 59 | 60 | class ASN1F_FULLY_ENCODED_DATA(ASN1F_SEQUENCE): 61 | ASN1_tag = ASN1_Tags_ISO_8823.FULLY_ENCODED_DATA_TAG 62 | 63 | 64 | class ASN1F_PDV_LIST(ASN1F_SEQUENCE): 65 | ASN1_tag = ASN1_Tags_ISO_8823.PDV_LIST_TAG 66 | 67 | 68 | class ASN1F_CONTENT(ASN1F_SEQUENCE): 69 | ASN1_tag = ASN1_Tags_ISO_8823.CONTENT_TAG 70 | 71 | 72 | class ASN1F_RESULT(ASN1F_INTEGER): 73 | ASN1_tag = ASN1_Tags_ISO_8823.RESULT_TAG 74 | 75 | 76 | class ASN1F_RESULT_LIST_TRANSFER_SYNTAX(ASN1F_OID): 77 | ASN1_tag = ASN1_Tags_ISO_8823.RESULT_LIST_TRANSFER_SYNTAX_TAG 78 | -------------------------------------------------------------------------------- /iec61850_mms/iso_8823/packets.py: -------------------------------------------------------------------------------- 1 | """ 2 | ISO 8823 Packet/PDU Definitions 3 | """ 4 | from scapy.asn1packet import * 5 | from .fields import * 6 | from ..iso_8650_1 import ACSE, ASN1_Codecs 7 | from ..mms import MMS 8 | 9 | 10 | class ISO_8823_Presentation_PMV(ASN1_Packet): 11 | ASN1_codec = ASN1_Codecs.BER 12 | ASN1_root = ASN1F_SEQUENCE( 13 | ASN1F_PRESENTATION_CONTEXT_IDENTIFIER( 14 | "presentation_context_identifier", 0), 15 | ) 16 | 17 | 18 | class ISO_8823_Presentation_Result(ASN1_Packet): 19 | ASN1_codec = ASN1_Codecs.BER 20 | ASN1_root = ASN1F_SEQUENCE( 21 | ASN1F_RESULT("result", 0), 22 | ASN1F_RESULT_LIST_TRANSFER_SYNTAX("transfer_syntax_name", None) 23 | ) 24 | 25 | 26 | class ISO_8823_Presentation_Definition(ASN1_Packet): 27 | ASN1_codec = ASN1_Codecs.BER 28 | ASN1_root = ASN1F_SEQUENCE( 29 | ASN1F_PRESENTATION_CONTEXT_IDENTIFIER( 30 | "presentation_context_identifier", 0), 31 | ASN1F_ABSTRACT_SYNTAX_NAME("abstract_syntax_name", None), 32 | ASN1F_SEQUENCE( 33 | ASN1F_TRANSFER_SYNTAX_NAME("transfer_syntax_name", None) 34 | ) 35 | ) 36 | 37 | 38 | class ISO_8823_Presentation_Fully_Encoded_Data(ASN1_Packet): 39 | ASN1_codec = ASN1_Codecs.BER 40 | ASN1_root = ASN1F_FULLY_ENCODED_DATA( 41 | ASN1F_SEQUENCE( 42 | ASN1F_PRESENTATION_CONTEXT_IDENTIFIER( 43 | "presentation_context_identifier", 0), 44 | ASN1F_CONTENT( 45 | ASN1F_CHOICE( 46 | "fully_encoded_data", 47 | None, 48 | ACSE, # may contain ACSE -> MMS 49 | MMS # or direct MMS 50 | ) 51 | ) 52 | ), 53 | ) 54 | 55 | 56 | class ISO_8823_Presentation_CPC_Type(ASN1_Packet): 57 | ASN1_codec = ASN1_Codecs.BER 58 | ASN1_root = ASN1F_USER_DATA( 59 | "user_data", 60 | None, 61 | ISO_8823_Presentation_Fully_Encoded_Data 62 | ) 63 | 64 | 65 | class ISO_8823_Presentation_CPA_Type(ASN1_Packet): 66 | ASN1_codec = ASN1_Codecs.BER 67 | ASN1_root = ASN1F_CP_TYPE( 68 | ASN1F_MODE_SELECTOR( 69 | ASN1F_MODE_VALUE("mode_value", 1), 70 | ), 71 | ASN1F_NORMAL_MODE_PARAMETERS( 72 | ASN1F_RESPONDING_PRESENTATION_SELECTOR( 73 | "responding_presentation_selector", "\x00\x00\x00\x01"), 74 | ASN1F_PRESENTATION_CONTEXT_DEFINITION_RESULT_LIST( 75 | "presentation_context_definition_result_list", 76 | None, 77 | ISO_8823_Presentation_Result 78 | ), 79 | ASN1F_USER_DATA( 80 | "user_data", 81 | None, 82 | ISO_8823_Presentation_Fully_Encoded_Data 83 | ) 84 | ) 85 | ) 86 | 87 | 88 | class ISO_8823_Presentation_CP_Type(ASN1_Packet): 89 | ASN1_codec = ASN1_Codecs.BER 90 | ASN1_root = ASN1F_CP_TYPE( 91 | ASN1F_MODE_SELECTOR( 92 | ASN1F_MODE_VALUE("mode_value", 1), 93 | ), 94 | ASN1F_NORMAL_MODE_PARAMETERS( 95 | ASN1F_CALLING_PRESENTATION_SELECTOR( 96 | "calling_presentation_selector", "\x00\x00\x00\x01"), 97 | ASN1F_CALLED_PRESENTATION_SELECTOR( 98 | "called_presentation_selector", "\x00\x00\x00\x01"), 99 | ASN1F_PRESENTATION_CONTEXT_DEFINITION_LIST( 100 | "presentation_context_definition_list", 101 | None, 102 | ISO_8823_Presentation_Definition 103 | ), 104 | ASN1F_USER_DATA( 105 | "user_data", 106 | None, 107 | ISO_8823_Presentation_Fully_Encoded_Data 108 | ) 109 | ) 110 | ) 111 | 112 | 113 | class ISO_8823_Presentation(ASN1_Packet): 114 | ASN1_codec = ASN1_Codecs.BER 115 | ASN1_root = ASN1F_CHOICE( 116 | "ISO_8823_Presentation", 117 | ISO_8823_Presentation_CP_Type(), # default 118 | ISO_8823_Presentation_CP_Type, 119 | ) 120 | -------------------------------------------------------------------------------- /iec61850_mms/iso_8823/tags.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASN1 ISO 8823 scapy tag definitions 3 | 4 | Values extracted from: 5 | - https://github.com/mz-automation/libiec61850/blob/v1.4/src/mms/iso_presentation/iso_presentation.c 6 | """ 7 | from scapy.asn1.asn1 import * 8 | 9 | 10 | class ASN1_Tags_ISO_8823(ASN1_Class_UNIVERSAL): 11 | name = "ISO 8823 OSI Presentation" 12 | 13 | CP_TYPE_TAG = 0x31 14 | MODE_SELECTOR_TAG = 0xa0 15 | CONTENT_TAG = 0xa0 16 | MODE_VALUE_TAG = 0x80 17 | NORMAL_MODE_PARAMETERS_TAG = 0xa2 18 | PRESENTATION_CONTEXT_IDENTIFIER_TAG = 0x02 19 | FULLY_ENCODED_DATA_TAG = 0x61 20 | PARSE_PCD_ENTRY_TAG = 0x30 21 | ABSTRACT_SYNTAX_NAME_TAG = 0x06 22 | TRANSFER_SYNTAX_NAME_TAG = 0x06 23 | CALLING_PRESENTATION_SELECTOR_TAG = 0x81 24 | CALLED_PRESENTATION_SELECTOR_TAG = 0x82 25 | RESPONDING_PRESENTATION_SELECTOR_TAG = 0x83 26 | PRESENTATION_CONTEXT_DEFINITION_LIST_TAG = 0xa4 27 | PRESENTATION_CONTEXT_DEFINITION_RESULT_LIST_TAG = 0xa5 28 | RESULT_TAG = 0x80 29 | RESULT_LIST_TRANSFER_SYNTAX_TAG = 0x81 30 | USER_DATA_TAG = 0x61 31 | PDV_LIST_TAG = 0x30 32 | 33 | 34 | 35 | 36 | 37 | # CP-type ::= SET { 38 | # mode-selector [0] IMPLICIT Mode-selector, #### <-------- DONE 39 | # normal-mode-parameters #### <-------- CHECK 40 | # [2] IMPLICIT SEQUENCE { 41 | # calling-presentation-selector #### <-------- CHECK 42 | # [1] IMPLICIT Calling-presentation-selector 43 | # OPTIONAL, 44 | # called-presentation-selector #### <-------- CHECK 45 | # [2] IMPLICIT Called-presentation-selector OPTIONAL, 46 | # presentation-context-definition-list #### <-------- CHECK 47 | # [4] IMPLICIT Presentation-context-definition-list 48 | # OPTIONAL, 49 | # user-data #### <-------- CHECK 50 | # User-data OPTIONAL} OPTIONAL 51 | # -- Shall be used for normal mode only. 52 | # -- Shall be the parameters of the CP PPDU. 53 | # } 54 | 55 | 56 | # CPA-PPDU ::= SET { 57 | # mode-selector [0] IMPLICIT Mode-selector, 58 | # x410-mode-parameters 59 | # [1] IMPLICIT SET {COMPONENTS OF Reliable-Transfer-APDU.RTOACapdu} OPTIONAL-- This OPTIONAL element shall be absent for a 60 | # -- nested presentation connection. 61 | # -- Shall be used for X.410 mode only. Shall be bitwise 62 | # -- compatible with CCITT Recommendation X.410-1984. 63 | # -- This shall be the User data parameter of the CPA PPDU1) --, 64 | # normal-mode-parameters 65 | # [2] IMPLICIT SEQUENCE {protocol-version 66 | # [0] IMPLICIT Protocol-version DEFAULT {version-1}, 67 | # responding-presentation-selector 68 | # [3] IMPLICIT Responding-presentation-selector 69 | # OPTIONAL, 70 | # presentation-context-definition-result-list 71 | # [5] IMPLICIT Presentation-context-definition-result-list 72 | # OPTIONAL, 73 | # presentation-requirements 74 | # [8] IMPLICIT Presentation-requirements OPTIONAL, 75 | # user-session-requirements 76 | # [9] IMPLICIT User-session-requirements OPTIONAL, 77 | # -- shall not be present if equal to the Revised session 78 | # -- requirements parameter 79 | # protocol-options 80 | # [11] Protocol-options DEFAULT {}, 81 | # -- shall be absent if no options are selected 82 | # responders-nominated-context 83 | # [13] Presentation-context-identifier OPTIONAL, 84 | # -- shall only be present if nominated-context is 85 | # -- selected in protocol-options 86 | # user-data 87 | # User-data OPTIONAL} OPTIONAL 88 | # -- Shall be used for normal mode only. 89 | # } 90 | -------------------------------------------------------------------------------- /iec61850_mms/iso_8823/types.py: -------------------------------------------------------------------------------- 1 | """ 2 | MMS ASN1 Type Mappings 3 | """ 4 | from scapy.asn1.asn1 import * 5 | from .tags import ASN1_Tags_ISO_8823 6 | 7 | 8 | class ASN1_MODE_SELECTOR(ASN1_SET): 9 | tag = ASN1_Tags_ISO_8823.MODE_SELECTOR_TAG 10 | 11 | 12 | class ASN1_NORMAL_MODE_PARAMETERS(ASN1_SEQUENCE): 13 | tag = ASN1_Tags_ISO_8823.NORMAL_MODE_PARAMETERS_TAG 14 | 15 | 16 | class ASN1_MODE_VALUE(ASN1_INTEGER): 17 | tag = ASN1_Tags_ISO_8823.MODE_VALUE_TAG 18 | 19 | 20 | class ASN1_CP_TYPE(ASN1_SET): 21 | tag = ASN1_Tags_ISO_8823.CP_TYPE_TAG 22 | 23 | 24 | class ASN1_CALLING_PRESENTATION_SELECTOR(ASN1_STRING): 25 | tag = ASN1_Tags_ISO_8823.CALLING_PRESENTATION_SELECTOR_TAG 26 | 27 | 28 | class ASN1_CALLED_PRESENTATION_SELECTOR(ASN1_STRING): 29 | tag = ASN1_Tags_ISO_8823.CALLED_PRESENTATION_SELECTOR_TAG 30 | 31 | 32 | class ASN1_PRESENTATION_CONTEXT_IDENTIFIER(ASN1_INTEGER): 33 | tag = ASN1_Tags_ISO_8823.PRESENTATION_CONTEXT_IDENTIFIER_TAG 34 | 35 | 36 | class ASN1_ABSTRACT_SYNTAX_NAME(ASN1_OID): 37 | tag = ASN1_Tags_ISO_8823.ABSTRACT_SYNTAX_NAME_TAG 38 | 39 | 40 | class ASN1_TRANSFER_SYNTAX_NAME(ASN1_OID): 41 | tag = ASN1_Tags_ISO_8823.TRANSFER_SYNTAX_NAME_TAG 42 | 43 | 44 | class ASN1_FULLY_ENCODED_DATA(ASN1_SEQUENCE): 45 | tag = ASN1_Tags_ISO_8823.FULLY_ENCODED_DATA_TAG 46 | 47 | 48 | class ASN1_PDV_LIST(ASN1_SEQUENCE): 49 | tag = ASN1_Tags_ISO_8823.PDV_LIST_TAG 50 | 51 | 52 | class ASN1_CONTENT(ASN1_SEQUENCE): 53 | tag = ASN1_Tags_ISO_8823.CONTENT_TAG 54 | 55 | 56 | class ASN1_RESPONDING_PRESENTATION_SELECTOR(ASN1_STRING): 57 | tag = ASN1_Tags_ISO_8823.RESPONDING_PRESENTATION_SELECTOR_TAG 58 | 59 | 60 | class ASN1_PRESENTATION_CONTEXT_DEFINITION_RESULT_LIST(ASN1_SEQUENCE): 61 | tag = ASN1_Tags_ISO_8823.PRESENTATION_CONTEXT_DEFINITION_RESULT_LIST_TAG 62 | 63 | 64 | class ASN1_RESULT_LIST_TRANSFER_SYNTAX(ASN1_OID): 65 | tag = ASN1_Tags_ISO_8823.RESULT_LIST_TRANSFER_SYNTAX_TAG 66 | 67 | 68 | class ASN1_RESULT(ASN1_INTEGER): 69 | tag = ASN1_Tags_ISO_8823.RESULT_TAG 70 | -------------------------------------------------------------------------------- /iec61850_mms/mms/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Limited MMS ASN.1 definitions for scapy. 3 | 4 | Source documents for these definitions: 5 | - ISO 68150-2 6 | - https://github.com/wireshark/wireshark/blob/master/epan/dissectors/asn1/mms/mms.asn 7 | 8 | supported types: 9 | - ConfirmedRequest (read, write, getnamelist) 10 | - InitiateRequest 11 | - InitiateResponse 12 | """ 13 | from . import tags 14 | from . import ber 15 | from . import fields 16 | from . import types 17 | from . import packets 18 | from .packets import MMS, MMS_Confirmed_Request_PDU, MMS_Initiate_Response_PDU, MMS_Initiate_Request_PDU 19 | -------------------------------------------------------------------------------- /iec61850_mms/mms/ber.py: -------------------------------------------------------------------------------- 1 | """ 2 | BER codec en-/decoders FOR MMS 3 | """ 4 | 5 | from .tags import ASN_Tags_MMS 6 | from scapy.asn1.ber import BERcodec_SEQUENCE, BERcodec_INTEGER, BERcodec_ISO646_STRING, BERcodec_BIT_STRING, \ 7 | BERcodec_NULL, BERcodec_BOOLEAN, BERcodec_STRING, BERcodec_UTF8_STRING 8 | 9 | 10 | class BER_CODEC_CONFIRMED_REQUEST_PDU(BERcodec_SEQUENCE): 11 | tag = ASN_Tags_MMS.CONFIRMED_REQUEST_PDU 12 | 13 | 14 | class BERcodec_UNCONFIRMED_PDU(BERcodec_SEQUENCE): 15 | tag = ASN_Tags_MMS.UNCONFIRMED_PDU 16 | 17 | 18 | class BER_CODEC_INITIATE_REQUEST_PDU(BERcodec_SEQUENCE): 19 | tag = ASN_Tags_MMS.INITIATE_REQUEST_PDU 20 | 21 | 22 | class BER_CODEC_INITIATE_RESPONSE_PDU(BERcodec_SEQUENCE): 23 | tag = ASN_Tags_MMS.INITIATE_RESPONSE_PDU 24 | 25 | 26 | # UnconfirmedService 27 | class BERcodec_INFORMATION_REPORT(BERcodec_SEQUENCE): 28 | tag = ASN_Tags_MMS.INFORMATION_REPORT 29 | 30 | # InformationReport 31 | 32 | 33 | class BERcodec_INFORMATION_REPORT_LIST_OF_ACCESS_RESULT(BERcodec_SEQUENCE): 34 | tag = ASN_Tags_MMS.INFORMATION_REPORT_LIST_OF_ACCESS_RESULT 35 | 36 | 37 | class BER_CODEC_GET_NAME_LIST_REQUEST(BERcodec_SEQUENCE): 38 | tag = ASN_Tags_MMS.GET_NAME_LIST_REQUEST 39 | 40 | 41 | class BER_CODEC_READ_REQUEST(BERcodec_SEQUENCE): 42 | tag = ASN_Tags_MMS.READ_REQUEST 43 | 44 | 45 | class BER_CODEC_WRITE_REQUEST(BERcodec_SEQUENCE): 46 | tag = ASN_Tags_MMS.WRITE_REQUEST 47 | 48 | 49 | class BER_CODEC_VMD_SPECIFIC(BERcodec_ISO646_STRING): 50 | tag = ASN_Tags_MMS.VMD_SPECIFIC 51 | 52 | 53 | class BER_CODEC_DOMAIN_SPECIFIC(BERcodec_SEQUENCE): 54 | tag = ASN_Tags_MMS.DOMAIN_SPECIFIC 55 | 56 | 57 | class BER_CODEC_AA_SPECIFIC(BERcodec_ISO646_STRING): 58 | tag = ASN_Tags_MMS.AA_SPECIFIC 59 | 60 | 61 | class BER_CODEC_LOCAL_DETAIL_CALLING(BERcodec_INTEGER): 62 | tag = ASN_Tags_MMS.LOCAL_DETAIL_CALLING 63 | 64 | 65 | class BER_CODEC_PROPOSED_MAX_SERV_OUTSTANDING_CALLING(BERcodec_INTEGER): 66 | tag = ASN_Tags_MMS.PROPOSED_MAX_SERV_OUTSTANDING_CALLING 67 | 68 | 69 | class BER_CODEC_PROPOSED_MAX_SERV_OUTSTANDING_CALLED(BERcodec_INTEGER): 70 | tag = ASN_Tags_MMS.PROPOSED_MAX_SERV_OUTSTANDING_CALLED 71 | 72 | 73 | class BER_CODEC_PROPOSED_DATA_STRUCTURE_NESTING_LEVEL(BERcodec_INTEGER): 74 | tag = ASN_Tags_MMS.PROPOSED_DATA_STRUCTURE_NESTING_LEVEL 75 | 76 | 77 | class BER_CODEC_MMS_INIT_REQUEST_DETAIL(BERcodec_SEQUENCE): 78 | tag = ASN_Tags_MMS.MMS_INIT_REQUEST_DETAIL 79 | 80 | 81 | class BER_CODEC_PROPOSED_VERSION_NUMBER(BERcodec_INTEGER): 82 | tag = ASN_Tags_MMS.PROPOSED_VERSION_NUMBER 83 | 84 | 85 | class BER_CODEC_PROPOSED_PARAMETER_CBB(BERcodec_BIT_STRING): 86 | tag = ASN_Tags_MMS.PROPOSED_PARAMETER_CBB 87 | 88 | 89 | class BER_CODEC_SERVICES_SUPPORTED_CALLING(BERcodec_BIT_STRING): 90 | tag = ASN_Tags_MMS.SERVICES_SUPPORTED_CALLING 91 | 92 | 93 | class BER_CODEC_LOCAL_DETAIL_CALLED(BERcodec_INTEGER): 94 | tag = ASN_Tags_MMS.LOCAL_DETAIL_CALLED 95 | 96 | 97 | class BER_CODEC_NEGOTIATED_MAX_SERV_OUTSTANDING_CALLING(BERcodec_INTEGER): 98 | tag = ASN_Tags_MMS.NEGOTIATED_MAX_SERV_OUTSTANDING_CALLING 99 | 100 | 101 | class BER_CODEC_NEGOTIATED_MAX_SERV_OUTSTANDING_CALLED(BERcodec_INTEGER): 102 | tag = ASN_Tags_MMS.NEGOTIATED_MAX_SERV_OUTSTANDING_CALLED 103 | 104 | 105 | class BER_CODEC_NEGOTIATED_DATA_STRUCTURE_NESTING_LEVEL(BERcodec_INTEGER): 106 | tag = ASN_Tags_MMS.NEGOTIATED_DATA_STRUCTURE_NESTING_LEVEL 107 | 108 | 109 | class BER_CODEC_MMS_INIT_RESPONSE_DETAIL(BERcodec_SEQUENCE): 110 | tag = ASN_Tags_MMS.MMS_INIT_RESPONSE_DETAIL 111 | 112 | 113 | class BER_CODEC_NEGOTIATED_VERSION_NUMBER(BERcodec_INTEGER): 114 | tag = ASN_Tags_MMS.NEGOTIATED_VERSION_NUMBER 115 | 116 | 117 | class BER_CODEC_NEGOTIATED_PARAMETER_CBB(BERcodec_BIT_STRING): 118 | tag = ASN_Tags_MMS.NEGOTIATED_PARAMETER_CBB 119 | 120 | 121 | class BER_CODEC_SERVICES_SUPPORTED_CALLED(BERcodec_BIT_STRING): 122 | tag = ASN_Tags_MMS.SERVICES_SUPPORTED_CALLED 123 | 124 | 125 | class BER_CODEC_VMD_STATE(BERcodec_INTEGER): 126 | tag = ASN_Tags_MMS.VMD_STATE 127 | 128 | 129 | class BER_CODEC_OBJECT_CLASS(BERcodec_SEQUENCE): 130 | tag = ASN_Tags_MMS.OBJECT_CLASS 131 | 132 | 133 | class BER_CODEC_OBJECT_SCOPE(BERcodec_SEQUENCE): 134 | tag = ASN_Tags_MMS.OBJECT_SCOPE 135 | 136 | 137 | class BER_CODEC_OBJECT_SCOPE_VMD_SPECIFIC(BERcodec_NULL): 138 | tag = ASN_Tags_MMS.OBJECT_SCOPE_VMD_SPECIFIC 139 | 140 | 141 | class BER_CODEC_OBJECT_SCOPE_DOMAIN_SPECIFIC(BERcodec_ISO646_STRING): 142 | tag = ASN_Tags_MMS.OBJECT_SCOPE_DOMAIN_SPECIFIC 143 | 144 | 145 | class BER_CODEC_OBJECT_SCOPE_AA_SPECIFIC(BERcodec_NULL): 146 | tag = ASN_Tags_MMS.OBJECT_SCOPE_AA_SPECIFIC 147 | 148 | 149 | class BER_CODEC_BASIC_OBJECT_CLASS(BERcodec_INTEGER): 150 | tag = ASN_Tags_MMS.BASIC_OBJECT_CLASS 151 | 152 | 153 | class BER_CODEC_TYPE_SPECIFICATION_MMS_STRING(BERcodec_INTEGER): 154 | tag = ASN_Tags_MMS.TYPE_SPECIFICATION_MMS_STRING 155 | 156 | 157 | class BER_CODEC_READ_REQUEST_SPECIFICATION_WITH_RESULT(BERcodec_BOOLEAN): 158 | tag = ASN_Tags_MMS.READ_REQUEST_SPECIFICATION_WITH_RESULT 159 | 160 | 161 | class BER_CODEC_READ_REQUEST_VARIABLE_ACCESS_SPECIFICATION(BERcodec_SEQUENCE): 162 | tag = ASN_Tags_MMS.READ_REQUEST_VARIABLE_ACCESS_SPECIFICATION 163 | 164 | 165 | class BER_CODEC_LIST_OF_DATA(BERcodec_SEQUENCE): 166 | tag = ASN_Tags_MMS.LIST_OF_DATA 167 | 168 | 169 | class BER_CODEC_NAME(BERcodec_SEQUENCE): 170 | tag = ASN_Tags_MMS.NAME 171 | 172 | 173 | class BERcodec_DATA_ARRAY(BERcodec_SEQUENCE): 174 | tag = ASN_Tags_MMS.DATA_TYPE_ARRAY 175 | 176 | 177 | class BERcodec_DATA_STRUCTURE(BERcodec_SEQUENCE): 178 | tag = ASN_Tags_MMS.DATA_TYPE_STRUCTURE 179 | 180 | 181 | class BER_CODEC_DATA_TYPE_BOOLEAN_(BERcodec_BOOLEAN): 182 | tag = ASN_Tags_MMS.DATA_TYPE_BOOLEAN_ 183 | 184 | 185 | class BER_CODEC_DATA_TYPE_BIT_STRING(BERcodec_BIT_STRING): 186 | tag = ASN_Tags_MMS.DATA_TYPE_BIT_STRING 187 | 188 | 189 | class BER_CODEC_DATA_TYPE_INTEGER(BERcodec_INTEGER): 190 | tag = ASN_Tags_MMS.DATA_TYPE_INTEGER 191 | 192 | 193 | class BER_CODEC_DATA_TYPE_UNSIGNED(BERcodec_INTEGER): 194 | tag = ASN_Tags_MMS.DATA_TYPE_UNSIGNED 195 | 196 | 197 | class BER_CODEC_DATA_TYPE_FLOATING_POINT(BERcodec_STRING): 198 | tag = ASN_Tags_MMS.DATA_TYPE_FLOATING_POINT 199 | 200 | 201 | class BER_CODEC_DATA_TYPE_OCTET_STRING(BERcodec_STRING): 202 | tag = ASN_Tags_MMS.DATA_TYPE_OCTET_STRING 203 | 204 | 205 | class BER_CODEC_DATA_TYPE_VISIBLE_STRING(BERcodec_ISO646_STRING): 206 | tag = ASN_Tags_MMS.DATA_TYPE_VISIBLE_STRING 207 | 208 | 209 | class BER_CODEC_DATA_TYPE_BINARY_TIME(BERcodec_STRING): 210 | tag = ASN_Tags_MMS.DATA_TYPE_BINARY_TIME 211 | 212 | 213 | class BER_CODEC_DATA_TYPE_MMS_STRING(BERcodec_UTF8_STRING): 214 | tag = ASN_Tags_MMS.DATA_TYPE_MMS_STRING 215 | 216 | 217 | class BER_CODEC_DATA_TYPE_UTC_TIME(BERcodec_STRING): 218 | tag = ASN_Tags_MMS.DATA_TYPE_UTC_TIME 219 | 220 | 221 | class BER_CODEC_LIST_OF_VARIABLES(BERcodec_SEQUENCE): 222 | tag = ASN_Tags_MMS.VARIABLE_ACCESS_SPECIFICATION_LIST_OF_VARIABLE 223 | 224 | 225 | class BER_CODEC_VARIABLES_LIST_NAMES(BERcodec_SEQUENCE): 226 | tag = ASN_Tags_MMS.VARIABLE_ACCESS_SPECIFICATION_VARIABLE_LIST_NAME 227 | 228 | # AccessResult 229 | 230 | 231 | class BERcodec_FAILURE(BERcodec_INTEGER): 232 | tag = ASN_Tags_MMS.FAILURE 233 | -------------------------------------------------------------------------------- /iec61850_mms/mms/fields.py: -------------------------------------------------------------------------------- 1 | """ 2 | MMS ASN1 field definitions 3 | """ 4 | from scapy.asn1fields import * 5 | from .tags import ASN_Tags_MMS 6 | 7 | 8 | class ASN1F_CONFIRMED_REQUEST_PDU(ASN1F_SEQUENCE): 9 | ASN1_tag = ASN_Tags_MMS.CONFIRMED_REQUEST_PDU 10 | 11 | 12 | class ASN1F_INITIATE_REQUEST_PDU(ASN1F_SEQUENCE): 13 | ASN1_tag = ASN_Tags_MMS.INITIATE_REQUEST_PDU 14 | 15 | 16 | class ASN1F_INITIATE_RESPONSE_PDU(ASN1F_SEQUENCE): 17 | ASN1_tag = ASN_Tags_MMS.INITIATE_RESPONSE_PDU 18 | 19 | 20 | class ASN1F_UNCONFIRMED_PDU(ASN1F_SEQUENCE): 21 | ASN1_tag = ASN_Tags_MMS.UNCONFIRMED_PDU 22 | 23 | 24 | class ASN1F_FAILURE(ASN1F_INTEGER): 25 | ASN1_tag = ASN_Tags_MMS.FAILURE 26 | 27 | 28 | class ASN1F_INFORMATION_REPORT_LIST_OF_ACCESS_RESULT(ASN1F_SEQUENCE_OF): 29 | ASN1_tag = ASN_Tags_MMS.INFORMATION_REPORT_LIST_OF_ACCESS_RESULT 30 | 31 | 32 | class ASN1F_INFORMATION_REPORT(ASN1F_SEQUENCE): 33 | ASN1_tag = ASN_Tags_MMS.INFORMATION_REPORT 34 | 35 | 36 | class ASN1F_GET_NAME_LIST_REQUEST(ASN1F_SEQUENCE): 37 | ASN1_tag = ASN_Tags_MMS.GET_NAME_LIST_REQUEST 38 | 39 | 40 | class ASN1F_READ_REQUEST(ASN1F_SET): 41 | ASN1_tag = ASN_Tags_MMS.READ_REQUEST 42 | 43 | 44 | class ASN1F_WRITE_REQUEST(ASN1F_SEQUENCE): 45 | ASN1_tag = ASN_Tags_MMS.WRITE_REQUEST 46 | 47 | 48 | class ASN1F_VMD_SPECIFIC(ASN1F_ISO646_STRING): 49 | ASN1_tag = ASN_Tags_MMS.VMD_SPECIFIC 50 | 51 | 52 | class ASN1F_DOMAIN_SPECIFIC(ASN1F_SEQUENCE): 53 | ASN1_tag = ASN_Tags_MMS.DOMAIN_SPECIFIC 54 | 55 | 56 | class ASN1F_AA_SPECIFIC(ASN1F_ISO646_STRING): 57 | ASN1_tag = ASN_Tags_MMS.AA_SPECIFIC 58 | 59 | 60 | class ASN1F_LOCAL_DETAIL_CALLING(ASN1F_INTEGER): 61 | ASN1_tag = ASN_Tags_MMS.LOCAL_DETAIL_CALLING 62 | 63 | 64 | class ASN1F_PROPOSED_MAX_SERV_OUTSTANDING_CALLING(ASN1F_INTEGER): 65 | ASN1_tag = ASN_Tags_MMS.PROPOSED_MAX_SERV_OUTSTANDING_CALLING 66 | 67 | 68 | class ASN1F_PROPOSED_MAX_SERV_OUTSTANDING_CALLED(ASN1F_INTEGER): 69 | ASN1_tag = ASN_Tags_MMS.PROPOSED_MAX_SERV_OUTSTANDING_CALLED 70 | 71 | 72 | class ASN1F_PROPOSED_DATA_STRUCTURE_NESTING_LEVEL(ASN1F_INTEGER): 73 | ASN1_tag = ASN_Tags_MMS.PROPOSED_DATA_STRUCTURE_NESTING_LEVEL 74 | 75 | 76 | class ASN1F_MMS_INIT_REQUEST_DETAIL(ASN1F_SEQUENCE): 77 | ASN1_tag = ASN_Tags_MMS.MMS_INIT_REQUEST_DETAIL 78 | 79 | 80 | class ASN1F_PROPOSED_VERSION_NUMBER(ASN1F_INTEGER): 81 | ASN1_tag = ASN_Tags_MMS.PROPOSED_VERSION_NUMBER 82 | 83 | 84 | class ASN1F_PROPOSED_PARAMETER_CBB(ASN1F_BIT_STRING): 85 | ASN1_tag = ASN_Tags_MMS.PROPOSED_PARAMETER_CBB 86 | 87 | 88 | class ASN1F_SERVICES_SUPPORTED_CALLING(ASN1F_BIT_STRING): 89 | ASN1_tag = ASN_Tags_MMS.SERVICES_SUPPORTED_CALLING 90 | 91 | 92 | class ASN1F_LOCAL_DETAIL_CALLED(ASN1F_INTEGER): 93 | ASN1_tag = ASN_Tags_MMS.LOCAL_DETAIL_CALLED 94 | 95 | 96 | class ASN1F_NEGOTIATED_MAX_SERV_OUTSTANDING_CALLING(ASN1F_INTEGER): 97 | ASN1_tag = ASN_Tags_MMS.NEGOTIATED_MAX_SERV_OUTSTANDING_CALLING 98 | 99 | 100 | class ASN1F_NEGOTIATED_MAX_SERV_OUTSTANDING_CALLED(ASN1F_INTEGER): 101 | ASN1_tag = ASN_Tags_MMS.NEGOTIATED_MAX_SERV_OUTSTANDING_CALLED 102 | 103 | 104 | class ASN1F_NEGOTIATED_DATA_STRUCTURE_NESTING_LEVEL(ASN1F_INTEGER): 105 | ASN1_tag = ASN_Tags_MMS.NEGOTIATED_DATA_STRUCTURE_NESTING_LEVEL 106 | 107 | 108 | class ASN1F_MMS_INIT_RESPONSE_DETAIL(ASN1F_SEQUENCE): 109 | ASN1_tag = ASN_Tags_MMS.MMS_INIT_RESPONSE_DETAIL 110 | 111 | 112 | class ASN1F_NEGOTIATED_VERSION_NUMBER(ASN1F_INTEGER): 113 | ASN1_tag = ASN_Tags_MMS.NEGOTIATED_VERSION_NUMBER 114 | 115 | 116 | class ASN1F_NEGOTIATED_PARAMETER_CBB(ASN1F_BIT_STRING): 117 | ASN1_tag = ASN_Tags_MMS.NEGOTIATED_PARAMETER_CBB 118 | 119 | 120 | class ASN1F_SERVICES_SUPPORTED_CALLED(ASN1F_BIT_STRING): 121 | ASN1_tag = ASN_Tags_MMS.SERVICES_SUPPORTED_CALLED 122 | 123 | 124 | class ASN1F_VMD_STATE(ASN1F_INTEGER): 125 | ASN1_tag = ASN_Tags_MMS.VMD_STATE 126 | 127 | 128 | class ASN1F_OBJECT_CLASS(ASN1F_SEQUENCE): 129 | ASN1_tag = ASN_Tags_MMS.OBJECT_CLASS 130 | 131 | 132 | class ASN1F_OBJECT_SCOPE(ASN1F_SEQUENCE): 133 | ASN1_tag = ASN_Tags_MMS.OBJECT_SCOPE 134 | 135 | 136 | class ASN1F_OBJECT_SCOPE_VMD_SPECIFIC(ASN1F_NULL): 137 | ASN1_tag = ASN_Tags_MMS.OBJECT_SCOPE_VMD_SPECIFIC 138 | 139 | 140 | class ASN1F_OBJECT_SCOPE_DOMAIN_SPECIFIC(ASN1F_ISO646_STRING): 141 | ASN1_tag = ASN_Tags_MMS.OBJECT_SCOPE_DOMAIN_SPECIFIC 142 | 143 | 144 | class ASN1F_OBJECT_SCOPE_AA_SPECIFIC(ASN1F_NULL): 145 | ASN1_tag = ASN_Tags_MMS.OBJECT_SCOPE_AA_SPECIFIC 146 | 147 | 148 | class ASN1F_BASIC_OBJECT_CLASS(ASN1F_INTEGER): 149 | ASN1_tag = ASN_Tags_MMS.BASIC_OBJECT_CLASS 150 | 151 | 152 | class ASN1F_TYPE_SPECIFICATION_MMS_STRING(ASN1F_INTEGER): 153 | ASN1_tag = ASN_Tags_MMS.TYPE_SPECIFICATION_MMS_STRING 154 | 155 | 156 | class ASN1F_READ_REQUEST_SPECIFICATION_WITH_RESULT(ASN1F_BOOLEAN): 157 | ASN1_tag = ASN_Tags_MMS.READ_REQUEST_SPECIFICATION_WITH_RESULT 158 | 159 | 160 | class ASN1F_READ_REQUEST_VARIABLE_ACCESS_SPECIFICATION(ASN1F_SEQUENCE): 161 | ASN1_tag = ASN_Tags_MMS.READ_REQUEST_VARIABLE_ACCESS_SPECIFICATION 162 | 163 | 164 | class ASN1F_LIST_OF_DATA(ASN1F_SEQUENCE_OF): 165 | ASN1_tag = ASN_Tags_MMS.LIST_OF_DATA 166 | 167 | 168 | class ASN1F_NAME(ASN1F_SEQUENCE): 169 | ASN1_tag = ASN_Tags_MMS.NAME 170 | 171 | 172 | class ASN1F_DATA_ARRAY(ASN1F_SEQUENCE_OF): 173 | ASN1_tag = ASN_Tags_MMS.DATA_TYPE_ARRAY 174 | 175 | 176 | class ASN1F_DATA_STRUCTURE(ASN1F_SEQUENCE_OF): 177 | ASN1_tag = ASN_Tags_MMS.DATA_TYPE_STRUCTURE 178 | 179 | 180 | class ASN1F_DATA_TYPE_BOOLEAN_(ASN1F_BOOLEAN): 181 | ASN1_tag = ASN_Tags_MMS.DATA_TYPE_BOOLEAN_ 182 | 183 | 184 | class ASN1F_DATA_TYPE_BIT_STRING(ASN1F_BIT_STRING): 185 | ASN1_tag = ASN_Tags_MMS.DATA_TYPE_BIT_STRING 186 | 187 | 188 | class ASN1F_DATA_TYPE_INTEGER(ASN1F_INTEGER): 189 | ASN1_tag = ASN_Tags_MMS.DATA_TYPE_INTEGER 190 | 191 | 192 | class ASN1F_DATA_TYPE_UNSIGNED(ASN1F_INTEGER): 193 | ASN1_tag = ASN_Tags_MMS.DATA_TYPE_UNSIGNED 194 | 195 | 196 | class ASN1F_DATA_TYPE_FLOATING_POINT(ASN1F_STRING): 197 | ASN1_tag = ASN_Tags_MMS.DATA_TYPE_FLOATING_POINT 198 | 199 | 200 | class ASN1F_DATA_TYPE_OCTET_STRING(ASN1F_STRING): 201 | ASN1_tag = ASN_Tags_MMS.DATA_TYPE_OCTET_STRING 202 | 203 | 204 | class ASN1F_DATA_TYPE_VISIBLE_STRING(ASN1F_ISO646_STRING): 205 | ASN1_tag = ASN_Tags_MMS.DATA_TYPE_VISIBLE_STRING 206 | 207 | 208 | class ASN1F_DATA_TYPE_BINARY_TIME(ASN1F_STRING): 209 | ASN1_tag = ASN_Tags_MMS.DATA_TYPE_BINARY_TIME 210 | 211 | 212 | class ASN1F_DATA_TYPE_MMS_STRING(ASN1F_UTF8_STRING): 213 | ASN1_tag = ASN_Tags_MMS.DATA_TYPE_MMS_STRING 214 | 215 | 216 | class ASN1F_DATA_TYPE_UTC_TIME(ASN1F_STRING): 217 | ASN1_tag = ASN_Tags_MMS.DATA_TYPE_UTC_TIME 218 | 219 | 220 | class ASN1F_LIST_OF_VARIABLES(ASN1F_SEQUENCE_OF): 221 | ASN1_tag = ASN_Tags_MMS.VARIABLE_ACCESS_SPECIFICATION_LIST_OF_VARIABLE 222 | 223 | 224 | class ASN1F_VARIABLES_LIST_NAMES(ASN1F_SEQUENCE): 225 | ASN1_tag = ASN_Tags_MMS.VARIABLE_ACCESS_SPECIFICATION_VARIABLE_LIST_NAME 226 | -------------------------------------------------------------------------------- /iec61850_mms/mms/packets.py: -------------------------------------------------------------------------------- 1 | """ 2 | MMS Packet/PDU Definitions 3 | """ 4 | from scapy.asn1packet import ASN1_Packet 5 | from scapy.asn1.asn1 import ASN1_Codecs 6 | from .fields import * 7 | 8 | 9 | class MMS_VMD_Specific(ASN1_Packet): 10 | ASN1_codec = ASN1_Codecs.BER 11 | ASN1_root = ASN1F_VMD_SPECIFIC("vmd_specific", "") 12 | 13 | 14 | class MMS_Domain_Specific(ASN1_Packet): 15 | ASN1_codec = ASN1_Codecs.BER 16 | ASN1_root = ASN1F_DOMAIN_SPECIFIC( 17 | ASN1F_ISO646_STRING("domain_specific1", ""), 18 | ASN1F_ISO646_STRING("domain_specific2", "") 19 | ) 20 | 21 | 22 | class MMS_AA_Specific(ASN1_Packet): 23 | ASN1_codec = ASN1_Codecs.BER 24 | ASN1_root = ASN1F_AA_SPECIFIC("aa_specific", "".encode("ascii")) 25 | 26 | 27 | class MMS_Name(ASN1_Packet): 28 | ASN1_codec = ASN1_Codecs.BER 29 | ASN1_root = ASN1F_NAME( 30 | ASN1F_CHOICE( 31 | 'name', 32 | None, 33 | MMS_VMD_Specific, 34 | MMS_Domain_Specific, 35 | MMS_AA_Specific 36 | ) 37 | ) 38 | 39 | 40 | class MMS_Variable_Entry(ASN1_Packet): 41 | ASN1_codec = ASN1_Codecs.BER 42 | ASN1_root = ASN1F_SEQUENCE( 43 | ASN1F_CHOICE( 44 | "variableSpecification", 45 | None, 46 | MMS_Name, 47 | ), 48 | ) 49 | 50 | 51 | class MMS_List_Of_Variables(ASN1_Packet): 52 | ASN1_codec = ASN1_Codecs.BER 53 | ASN1_root = ASN1F_LIST_OF_VARIABLES( 54 | "listOfVariables", 55 | None, 56 | MMS_Variable_Entry 57 | ) 58 | 59 | 60 | class MMS_Variables_List_Names(ASN1_Packet): 61 | ASN1_codec = ASN1_Codecs.BER 62 | ASN1_root = ASN1F_VARIABLES_LIST_NAMES( 63 | ASN1F_CHOICE( 64 | "accessSpecificationVariablesListEntry", 65 | MMS_VMD_Specific(), 66 | MMS_VMD_Specific, 67 | MMS_Domain_Specific, 68 | MMS_AA_Specific 69 | ) 70 | ) 71 | 72 | 73 | class MMS_VMD_state(ASN1_Packet): 74 | ASN1_codec = ASN1_Codecs.BER 75 | ASN1_root = ASN1F_VMD_STATE("vmd_state", 0) 76 | 77 | 78 | class MMS_Object_Scope_VMD_Specific(ASN1_Packet): 79 | ASN1_codec = ASN1_Codecs.BER 80 | ASN1_root = ASN1F_OBJECT_SCOPE_VMD_SPECIFIC("objectScopeVMDSpecific", 0) 81 | 82 | 83 | class MMS_Object_Scope_Domain_Specific(ASN1_Packet): 84 | ASN1_codec = ASN1_Codecs.BER 85 | ASN1_root = ASN1F_OBJECT_SCOPE_DOMAIN_SPECIFIC( 86 | "objectScopeDomainSpecific", 0) 87 | 88 | 89 | class MMS_Object_Scope_AA_Specific(ASN1_Packet): 90 | ASN1_codec = ASN1_Codecs.BER 91 | ASN1_root = ASN1F_OBJECT_SCOPE_AA_SPECIFIC("objectScopeAASpecific", 0) 92 | 93 | 94 | class MMS_Object_Scope(ASN1_Packet): 95 | ASN1_codec = ASN1_Codecs.BER 96 | ASN1_root = ASN1F_OBJECT_SCOPE( 97 | ASN1F_CHOICE( 98 | "objectScope", 99 | MMS_Object_Scope_VMD_Specific(), 100 | MMS_Object_Scope_VMD_Specific, 101 | MMS_Object_Scope_Domain_Specific, 102 | MMS_Object_Scope_AA_Specific 103 | ) 104 | ) 105 | 106 | 107 | class MMS_Basic_Object_Class(ASN1_Packet): 108 | ASN1_codec = ASN1_Codecs.BER 109 | ASN1_root = ASN1F_BASIC_OBJECT_CLASS("basicObjectClass", 0) 110 | 111 | 112 | class MMS_Object_Class(ASN1_Packet): 113 | ASN1_codec = ASN1_Codecs.BER 114 | ASN1_root = ASN1F_OBJECT_CLASS( 115 | ASN1F_CHOICE( 116 | "objectClass", 117 | MMS_Basic_Object_Class(), 118 | MMS_Basic_Object_Class 119 | ) 120 | ) 121 | 122 | 123 | class MMS_Get_Name_List_Request(ASN1_Packet): 124 | ASN1_codec = ASN1_Codecs.BER 125 | ASN1_root = ASN1F_GET_NAME_LIST_REQUEST( 126 | ASN1F_OBJECT_CLASS( 127 | ASN1F_CHOICE( 128 | "objectClass", 129 | MMS_Basic_Object_Class(), 130 | MMS_Basic_Object_Class 131 | ) 132 | ), 133 | ASN1F_OBJECT_SCOPE( 134 | ASN1F_CHOICE( 135 | "objectScope", 136 | MMS_Object_Scope_VMD_Specific(), 137 | MMS_Object_Scope_VMD_Specific, 138 | MMS_Object_Scope_Domain_Specific, 139 | MMS_Object_Scope_AA_Specific 140 | ) 141 | ), 142 | ) 143 | 144 | 145 | class MMS_Data_Boolean(ASN1_Packet): 146 | ASN1_codec = ASN1_Codecs.BER 147 | ASN1_root = ASN1F_DATA_TYPE_BOOLEAN_("bool", False) 148 | 149 | 150 | class MMS_Data_BitString(ASN1_Packet): 151 | ASN1_codec = ASN1_Codecs.BER 152 | ASN1_root = ASN1F_DATA_TYPE_BIT_STRING("bit_string", None) 153 | 154 | 155 | class MMS_Data_Int(ASN1_Packet): 156 | ASN1_codec = ASN1_Codecs.BER 157 | ASN1_root = ASN1F_DATA_TYPE_INTEGER("integer", 0) 158 | 159 | 160 | class MMS_Data_UInt(ASN1_Packet): 161 | ASN1_codec = ASN1_Codecs.BER 162 | ASN1_root = ASN1F_DATA_TYPE_UNSIGNED("unsigned", 0) 163 | 164 | 165 | class MMS_Data_Float(ASN1_Packet): 166 | ASN1_codec = ASN1_Codecs.BER 167 | ASN1_root = ASN1F_DATA_TYPE_FLOATING_POINT("floating_point", 0) 168 | 169 | 170 | class MMS_Data_OctetString(ASN1_Packet): 171 | ASN1_codec = ASN1_Codecs.BER 172 | ASN1_root = ASN1F_DATA_TYPE_OCTET_STRING("data_octet", None) 173 | 174 | 175 | class MMS_Data_VisibleString(ASN1_Packet): 176 | ASN1_codec = ASN1_Codecs.BER 177 | ASN1_root = ASN1F_DATA_TYPE_VISIBLE_STRING("visible_str", "") 178 | 179 | 180 | class MMS_Data_BinaryTime(ASN1_Packet): 181 | ASN1_codec = ASN1_Codecs.BER 182 | ASN1_root = ASN1F_DATA_TYPE_BINARY_TIME("binary_time", None) 183 | 184 | 185 | class MMS_Data_MMSString(ASN1_Packet): 186 | ASN1_codec = ASN1_Codecs.BER 187 | ASN1_root = ASN1F_DATA_TYPE_MMS_STRING("mms_str", None) 188 | 189 | 190 | class MMS_Data_UTCTime(ASN1_Packet): 191 | ASN1_codec = ASN1_Codecs.BER 192 | ASN1_root = ASN1F_DATA_TYPE_UTC_TIME("utc_time", None) 193 | 194 | 195 | class MMS_Data(ASN1_Packet): 196 | ASN1_codec = ASN1_Codecs.BER 197 | ASN1_root = ASN1F_CHOICE( 198 | 'data', 199 | None, 200 | # MMS_Data_Array, -- not implemented 201 | # MMS_Data_Structure, -- not implemented 202 | MMS_Data_Boolean, 203 | MMS_Data_BitString, 204 | MMS_Data_Int, 205 | MMS_Data_UInt, 206 | MMS_Data_Float, 207 | MMS_Data_OctetString, 208 | MMS_Data_VisibleString, 209 | MMS_Data_BinaryTime, 210 | MMS_Data_MMSString, 211 | MMS_Data_UTCTime 212 | ) 213 | 214 | 215 | class MMS_Write_Request(ASN1_Packet): 216 | ASN1_codec = ASN1_Codecs.BER 217 | ASN1_root = ASN1F_WRITE_REQUEST( 218 | ASN1F_CHOICE( 219 | "variableAccessSpecification", 220 | None, 221 | MMS_List_Of_Variables, 222 | MMS_Variables_List_Names 223 | ), 224 | ASN1F_LIST_OF_DATA( 225 | "listOfData", 226 | None, 227 | MMS_Data 228 | ) 229 | ) 230 | 231 | 232 | class MMS_Read_Request(ASN1_Packet): 233 | ASN1_codec = ASN1_Codecs.BER 234 | ASN1_root = ASN1F_READ_REQUEST( 235 | ASN1F_optional(ASN1F_READ_REQUEST_SPECIFICATION_WITH_RESULT( 236 | "specificationWithResult", False)), 237 | ASN1F_READ_REQUEST_VARIABLE_ACCESS_SPECIFICATION( 238 | ASN1F_CHOICE( 239 | "variableAccessSpecification", 240 | None, 241 | MMS_List_Of_Variables, 242 | MMS_Variables_List_Names 243 | ), 244 | ) 245 | ) 246 | 247 | 248 | class MMS_Confirmed_Request_PDU(ASN1_Packet): 249 | ASN1_codec = ASN1_Codecs.BER 250 | ASN1_root = ASN1F_CONFIRMED_REQUEST_PDU( 251 | ASN1F_INTEGER("invokeID", 0), 252 | ASN1F_CHOICE( 253 | "confirmedServiceRequest", 254 | MMS_Get_Name_List_Request(), 255 | MMS_Get_Name_List_Request, 256 | MMS_Read_Request, 257 | MMS_Write_Request, 258 | ) 259 | ) 260 | 261 | 262 | class MMS_Initiate_Response_PDU(ASN1_Packet): 263 | ASN1_codec = ASN1_Codecs.BER 264 | ASN1_root = ASN1F_INITIATE_RESPONSE_PDU( 265 | ASN1F_LOCAL_DETAIL_CALLED("localDetailCalled", 0), 266 | ASN1F_NEGOTIATED_MAX_SERV_OUTSTANDING_CALLING( 267 | "negotiatedMaxServOutstandingCalling", 0), 268 | ASN1F_NEGOTIATED_MAX_SERV_OUTSTANDING_CALLED( 269 | "negotiatedMaxServOutstandingCalled", 0), 270 | ASN1F_NEGOTIATED_DATA_STRUCTURE_NESTING_LEVEL( 271 | "negotiatedDataStructureNestingLevel", 0), 272 | ASN1F_MMS_INIT_RESPONSE_DETAIL( 273 | ASN1F_NEGOTIATED_VERSION_NUMBER("negotiatedVersionNumber", 0), 274 | ASN1F_NEGOTIATED_PARAMETER_CBB("negotiatedParameterCBB", None), 275 | ASN1F_SERVICES_SUPPORTED_CALLED("servicesSupportedCalled", None) 276 | ) 277 | ) 278 | 279 | 280 | class MMS_Initiate_Request_PDU(ASN1_Packet): 281 | ASN1_codec = ASN1_Codecs.BER 282 | ASN1_root = ASN1F_INITIATE_REQUEST_PDU( 283 | ASN1F_LOCAL_DETAIL_CALLING("localDetailCalling", 0), 284 | ASN1F_PROPOSED_MAX_SERV_OUTSTANDING_CALLING( 285 | "proposedMaxServOutstandingCalling", 0), 286 | ASN1F_PROPOSED_MAX_SERV_OUTSTANDING_CALLED( 287 | "proposedMaxServOutstandingCalled", 0), 288 | ASN1F_PROPOSED_DATA_STRUCTURE_NESTING_LEVEL( 289 | "proposedDataStructureNestingLevel", 0), 290 | ASN1F_MMS_INIT_REQUEST_DETAIL( 291 | ASN1F_PROPOSED_VERSION_NUMBER("proposedVersionNumber", 0), 292 | ASN1F_PROPOSED_PARAMETER_CBB("proposedParameterCBB", None), 293 | ASN1F_SERVICES_SUPPORTED_CALLING("servicesSupportedCalling", None) 294 | ) 295 | ) 296 | 297 | 298 | class MMS_FAILURE(ASN1_Packet): 299 | ASN1_codec = ASN1_Codecs.BER 300 | ASN1_root = ASN1F_FAILURE("failure", None) 301 | 302 | 303 | class MMS_ACCESS_RESULT(ASN1_Packet): 304 | ASN1_codec = ASN1_Codecs.BER 305 | ASN1_root = ASN1F_CHOICE( 306 | "accessResult", 307 | None, 308 | MMS_FAILURE, 309 | MMS_Data 310 | ) 311 | 312 | 313 | class MMS_Information_Report(ASN1_Packet): 314 | ASN1_codec = ASN1_Codecs.BER 315 | ASN1_root = ASN1F_INFORMATION_REPORT( 316 | ASN1F_CHOICE( 317 | "variableAccessSpecification", 318 | None, 319 | MMS_List_Of_Variables, 320 | MMS_Variables_List_Names, 321 | ), 322 | ASN1F_INFORMATION_REPORT_LIST_OF_ACCESS_RESULT( 323 | "listOfAccessResult", 324 | None, 325 | MMS_ACCESS_RESULT 326 | ), 327 | ) 328 | 329 | 330 | class MMS_Unconfirmed_PDU(ASN1_Packet): 331 | ASN1_codec = ASN1_Codecs.BER 332 | ASN1_root = ASN1F_UNCONFIRMED_PDU( 333 | ASN1F_CHOICE( 334 | "informationReport", 335 | None, 336 | MMS_Information_Report 337 | ), 338 | ) 339 | 340 | 341 | class MMS(ASN1_Packet): 342 | ASN1_codec = ASN1_Codecs.BER 343 | ASN1_root = ASN1F_CHOICE( 344 | "MMS", 345 | MMS_Confirmed_Request_PDU(), 346 | MMS_Confirmed_Request_PDU, 347 | MMS_Unconfirmed_PDU, 348 | MMS_Initiate_Request_PDU, 349 | MMS_Initiate_Response_PDU, 350 | ) 351 | -------------------------------------------------------------------------------- /iec61850_mms/mms/tags.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASN1 MMS Class Tag Definitions. 3 | 4 | Values extracted from: https://github.com/ljy5490/scapy61850/blob/master/mms.py 5 | """ 6 | from scapy.asn1.asn1 import ASN1_Class_UNIVERSAL 7 | 8 | 9 | class ASN_Tags_MMS(ASN1_Class_UNIVERSAL): 10 | name = "MMS" 11 | 12 | # PDUs 13 | CONFIRMED_REQUEST_PDU = 0xa0 14 | CONFIRMED_RESPONSE_PDU = 0xa1 15 | UNCONFIRMED_PDU = 0xa3 16 | INITIATE_REQUEST_PDU = 0xa8 17 | INITIATE_RESPONSE_PDU = 0xa9 18 | 19 | # UnconfirmedService 20 | INFORMATION_REPORT = 0xa0 21 | 22 | # InformationReport 23 | INFORMATION_REPORT_LIST_OF_ACCESS_RESULT = 0xa0 24 | 25 | # AccessResult 26 | FAILURE = 0x80 27 | 28 | # Requests 29 | GET_NAME_LIST_REQUEST = 0xa1 30 | READ_REQUEST = 0xa4 31 | WRITE_REQUEST = 0xa5 32 | GET_VARIABLE_ACCESS_ATTRIBUTES_REQUEST = 0xa6 33 | DEFINE_NAMED_VARIABLE_LIST_REQUEST = 0xab 34 | GET_NAMED_VARIABLE_LIST_ATTRIBUTES_REQUEST = 0xac 35 | DELETE_NAMED_VARIABLE_LIST_REQUEST = 0xad 36 | 37 | # Specifics 38 | VMD_SPECIFIC = 0x80 39 | DOMAIN_SPECIFIC = 0xa1 40 | AA_SPECIFIC = 0x82 41 | 42 | # InitiateRequestPdu 43 | LOCAL_DETAIL_CALLING = 0x80 44 | PROPOSED_MAX_SERV_OUTSTANDING_CALLING = 0x81 45 | PROPOSED_MAX_SERV_OUTSTANDING_CALLED = 0x82 46 | PROPOSED_DATA_STRUCTURE_NESTING_LEVEL = 0x83 47 | MMS_INIT_REQUEST_DETAIL = 0xa4 48 | 49 | # InitRequestDetail 50 | PROPOSED_VERSION_NUMBER = 0x80 51 | PROPOSED_PARAMETER_CBB = 0x81 52 | SERVICES_SUPPORTED_CALLING = 0x82 53 | 54 | # InitiateResponsePdu 55 | LOCAL_DETAIL_CALLED = 0x80 56 | NEGOTIATED_MAX_SERV_OUTSTANDING_CALLING = 0x81 57 | NEGOTIATED_MAX_SERV_OUTSTANDING_CALLED = 0x82 58 | NEGOTIATED_DATA_STRUCTURE_NESTING_LEVEL = 0x83 59 | MMS_INIT_RESPONSE_DETAIL = 0xa4 60 | 61 | # InitResponseDetail 62 | NEGOTIATED_VERSION_NUMBER = 0x80 63 | NEGOTIATED_PARAMETER_CBB = 0x81 64 | SERVICES_SUPPORTED_CALLED = 0x82 65 | 66 | VMD_STATE = 0x80 67 | 68 | # GetNameListRequest 69 | OBJECT_CLASS = 0xa0 70 | OBJECT_SCOPE = 0xa1 71 | CONTINUE_AFTER = 0x82 72 | 73 | # objectScope 74 | OBJECT_SCOPE_VMD_SPECIFIC = 0x80 75 | OBJECT_SCOPE_DOMAIN_SPECIFIC = 0x81 76 | OBJECT_SCOPE_AA_SPECIFIC = 0x82 77 | 78 | # ObjectClass 79 | BASIC_OBJECT_CLASS = 0x80 80 | 81 | # ReadRequest 82 | READ_REQUEST_SPECIFICATION_WITH_RESULT = 0x80 83 | READ_REQUEST_VARIABLE_ACCESS_SPECIFICATION = 0xa1 84 | 85 | # WriteRequest 86 | LIST_OF_DATA = 0xa0 87 | 88 | # GetVariableAccessAttributesRequest 89 | NAME = 0xa0 90 | 91 | # Data 92 | DATA_TYPE_ARRAY = 0xa1 93 | DATA_TYPE_STRUCTURE = 0xa2 94 | DATA_TYPE_BOOLEAN_ = 0x83 95 | DATA_TYPE_BIT_STRING = 0x84 96 | DATA_TYPE_INTEGER = 0x85 97 | DATA_TYPE_UNSIGNED = 0x86 98 | DATA_TYPE_FLOATING_POINT = 0x87 99 | DATA_TYPE_OCTET_STRING = 0x89 100 | DATA_TYPE_VISIBLE_STRING = 0x8a 101 | DATA_TYPE_BINARY_TIME = 0x8c 102 | DATA_TYPE_MMS_STRING = 0x90 103 | DATA_TYPE_UTC_TIME = 0x91 104 | 105 | # VariableAccessSpecification 106 | VARIABLE_ACCESS_SPECIFICATION_LIST_OF_VARIABLE = 0xa0 107 | VARIABLE_ACCESS_SPECIFICATION_VARIABLE_LIST_NAME = 0xa1 108 | 109 | TYPE_SPECIFICATION_ARRAY = 0xa1 110 | TYPE_SPECIFICATION_STRUCTURE = 0xa2 111 | TYPE_SPECIFICATION_BOOLEAN_ = 0x83 112 | TYPE_SPECIFICATION_BIT_STRING = 0x84 113 | TYPE_SPECIFICATION_INTEGER = 0x85 114 | TYPE_SPECIFICATION_UNSIGNED = 0x86 115 | TYPE_SPECIFICATION_FLOATING_POINT = 0xa7 116 | TYPE_SPECIFICATION_OCTET_STRING = 0x89 117 | TYPE_SPECIFICATION_VISIBLE_STRING = 0x8a 118 | TYPE_SPECIFICATION_BINARY_TIME = 0x8c 119 | TYPE_SPECIFICATION_MMS_STRING = 0x90 120 | TYPE_SPECIFICATION_UTC_TIME = 0x91 121 | -------------------------------------------------------------------------------- /iec61850_mms/mms/types.py: -------------------------------------------------------------------------------- 1 | """ 2 | MMS ASN1 Type Mappings 3 | """ 4 | from scapy.asn1.asn1 import ASN1_SEQUENCE, ASN1_INTEGER, ASN1_ISO646_STRING, ASN1_BOOLEAN, ASN1_BIT_STRING, ASN1_NULL, \ 5 | ASN1_STRING, ASN1_UTF8_STRING 6 | from .tags import ASN_Tags_MMS 7 | 8 | 9 | class ASN1_CONFIRMED_REQUEST_PDU(ASN1_SEQUENCE): 10 | tag = ASN_Tags_MMS.CONFIRMED_REQUEST_PDU 11 | 12 | 13 | class ASN1_UNCONFIRMED_PDU(ASN1_SEQUENCE): 14 | tag = ASN_Tags_MMS.UNCONFIRMED_PDU 15 | 16 | 17 | class ASN1_INITIATE_REQUEST_PDU(ASN1_SEQUENCE): 18 | tag = ASN_Tags_MMS.INITIATE_REQUEST_PDU 19 | 20 | 21 | class ASN1_INITIATE_RESPONSE_PDU(ASN1_SEQUENCE): 22 | tag = ASN_Tags_MMS.INITIATE_RESPONSE_PDU 23 | 24 | 25 | class ASN1_GET_NAME_LIST_REQUEST(ASN1_SEQUENCE): 26 | tag = ASN_Tags_MMS.GET_NAME_LIST_REQUEST 27 | 28 | 29 | class ASN1_READ_REQUEST(ASN1_SEQUENCE): 30 | tag = ASN_Tags_MMS.READ_REQUEST 31 | 32 | 33 | class ASN1_WRITE_REQUEST(ASN1_SEQUENCE): 34 | tag = ASN_Tags_MMS.WRITE_REQUEST 35 | 36 | 37 | class ASN1_VMD_SPECIFIC(ASN1_ISO646_STRING): 38 | tag = ASN_Tags_MMS.VMD_SPECIFIC 39 | 40 | 41 | class ASN1_DOMAIN_SPECIFIC(ASN1_SEQUENCE): 42 | tag = ASN_Tags_MMS.DOMAIN_SPECIFIC 43 | 44 | 45 | class ASN1_AA_SPECIFIC(ASN1_ISO646_STRING): 46 | tag = ASN_Tags_MMS.AA_SPECIFIC 47 | 48 | 49 | class ASN1_LOCAL_DETAIL_CALLING(ASN1_INTEGER): 50 | tag = ASN_Tags_MMS.LOCAL_DETAIL_CALLING 51 | 52 | 53 | class ASN1_PROPOSED_MAX_SERV_OUTSTANDING_CALLING(ASN1_INTEGER): 54 | tag = ASN_Tags_MMS.PROPOSED_MAX_SERV_OUTSTANDING_CALLING 55 | 56 | 57 | class ASN1_PROPOSED_MAX_SERV_OUTSTANDING_CALLED(ASN1_INTEGER): 58 | tag = ASN_Tags_MMS.PROPOSED_MAX_SERV_OUTSTANDING_CALLED 59 | 60 | 61 | class ASN1_PROPOSED_DATA_STRUCTURE_NESTING_LEVEL(ASN1_INTEGER): 62 | tag = ASN_Tags_MMS.PROPOSED_DATA_STRUCTURE_NESTING_LEVEL 63 | 64 | 65 | class ASN1_MMS_INIT_REQUEST_DETAIL(ASN1_SEQUENCE): 66 | tag = ASN_Tags_MMS.MMS_INIT_REQUEST_DETAIL 67 | 68 | 69 | class ASN1_PROPOSED_VERSION_NUMBER(ASN1_INTEGER): 70 | tag = ASN_Tags_MMS.PROPOSED_VERSION_NUMBER 71 | 72 | 73 | class ASN1_PROPOSED_PARAMETER_CBB(ASN1_BIT_STRING): 74 | tag = ASN_Tags_MMS.PROPOSED_PARAMETER_CBB 75 | 76 | 77 | class ASN1_SERVICES_SUPPORTED_CALLING(ASN1_BIT_STRING): 78 | tag = ASN_Tags_MMS.SERVICES_SUPPORTED_CALLING 79 | 80 | 81 | class ASN1_LOCAL_DETAIL_CALLED(ASN1_INTEGER): 82 | tag = ASN_Tags_MMS.LOCAL_DETAIL_CALLED 83 | 84 | 85 | class ASN1_NEGOTIATED_MAX_SERV_OUTSTANDING_CALLING(ASN1_INTEGER): 86 | tag = ASN_Tags_MMS.NEGOTIATED_MAX_SERV_OUTSTANDING_CALLING 87 | 88 | 89 | class ASN1_NEGOTIATED_MAX_SERV_OUTSTANDING_CALLED(ASN1_INTEGER): 90 | tag = ASN_Tags_MMS.NEGOTIATED_MAX_SERV_OUTSTANDING_CALLED 91 | 92 | 93 | class ASN1_NEGOTIATED_DATA_STRUCTURE_NESTING_LEVEL(ASN1_INTEGER): 94 | tag = ASN_Tags_MMS.NEGOTIATED_DATA_STRUCTURE_NESTING_LEVEL 95 | 96 | 97 | class ASN1_MMS_INIT_RESPONSE_DETAIL(ASN1_SEQUENCE): 98 | tag = ASN_Tags_MMS.MMS_INIT_RESPONSE_DETAIL 99 | 100 | 101 | class ASN1_NEGOTIATED_VERSION_NUMBER(ASN1_INTEGER): 102 | tag = ASN_Tags_MMS.NEGOTIATED_VERSION_NUMBER 103 | 104 | 105 | class ASN1_NEGOTIATED_PARAMETER_CBB(ASN1_BIT_STRING): 106 | tag = ASN_Tags_MMS.NEGOTIATED_PARAMETER_CBB 107 | 108 | 109 | class ASN1_SERVICES_SUPPORTED_CALLED(ASN1_BIT_STRING): 110 | tag = ASN_Tags_MMS.SERVICES_SUPPORTED_CALLED 111 | 112 | 113 | class ASN1_VMD_STATE(ASN1_INTEGER): 114 | tag = ASN_Tags_MMS.VMD_STATE 115 | 116 | 117 | class ASN1_OBJECT_CLASS(ASN1_SEQUENCE): 118 | tag = ASN_Tags_MMS.OBJECT_CLASS 119 | 120 | 121 | class ASN1_OBJECT_SCOPE(ASN1_SEQUENCE): 122 | tag = ASN_Tags_MMS.OBJECT_SCOPE 123 | 124 | 125 | class ASN1_OBJECT_SCOPE_VMD_SPECIFIC(ASN1_NULL): 126 | tag = ASN_Tags_MMS.OBJECT_SCOPE_VMD_SPECIFIC 127 | 128 | 129 | class ASN1_OBJECT_SCOPE_DOMAIN_SPECIFIC(ASN1_ISO646_STRING): 130 | tag = ASN_Tags_MMS.OBJECT_SCOPE_DOMAIN_SPECIFIC 131 | 132 | 133 | class ASN1_OBJECT_SCOPE_AA_SPECIFIC(ASN1_NULL): 134 | tag = ASN_Tags_MMS.OBJECT_SCOPE_AA_SPECIFIC 135 | 136 | 137 | class ASN1_BASIC_OBJECT_CLASS(ASN1_INTEGER): 138 | tag = ASN_Tags_MMS.BASIC_OBJECT_CLASS 139 | 140 | 141 | class ASN1_TYPE_SPECIFICATION_MMS_STRING(ASN1_INTEGER): 142 | tag = ASN_Tags_MMS.TYPE_SPECIFICATION_MMS_STRING 143 | 144 | 145 | class ASN1_READ_REQUEST_SPECIFICATION_WITH_RESULT(ASN1_BOOLEAN): 146 | tag = ASN_Tags_MMS.READ_REQUEST_SPECIFICATION_WITH_RESULT 147 | 148 | 149 | class ASN1_READ_REQUEST_VARIABLE_ACCESS_SPECIFICATION(ASN1_SEQUENCE): 150 | tag = ASN_Tags_MMS.READ_REQUEST_VARIABLE_ACCESS_SPECIFICATION 151 | 152 | 153 | class ASN1_LIST_OF_DATA(ASN1_SEQUENCE): 154 | tag = ASN_Tags_MMS.LIST_OF_DATA 155 | 156 | 157 | class ASN1_NAME(ASN1_SEQUENCE): 158 | tag = ASN_Tags_MMS.NAME 159 | 160 | 161 | class ASN1_DATA_TYPE_BOOLEAN_(ASN1_BOOLEAN): 162 | tag = ASN_Tags_MMS.DATA_TYPE_BOOLEAN_ 163 | 164 | 165 | class ASN1_DATA_TYPE_BIT_STRING(ASN1_BIT_STRING): 166 | tag = ASN_Tags_MMS.DATA_TYPE_BIT_STRING 167 | 168 | 169 | class ASN1_DATA_TYPE_INTEGER(ASN1_INTEGER): 170 | tag = ASN_Tags_MMS.DATA_TYPE_INTEGER 171 | 172 | 173 | class ASN1_DATA_TYPE_UNSIGNED(ASN1_INTEGER): 174 | tag = ASN_Tags_MMS.DATA_TYPE_UNSIGNED 175 | 176 | 177 | class ASN1_DATA_TYPE_FLOATING_POINT(ASN1_STRING): 178 | tag = ASN_Tags_MMS.DATA_TYPE_FLOATING_POINT 179 | 180 | 181 | class ASN1_DATA_TYPE_OCTET_STRING(ASN1_STRING): 182 | tag = ASN_Tags_MMS.DATA_TYPE_OCTET_STRING 183 | 184 | 185 | class ASN1_DATA_TYPE_VISIBLE_STRING(ASN1_ISO646_STRING): 186 | tag = ASN_Tags_MMS.DATA_TYPE_VISIBLE_STRING 187 | 188 | 189 | class ASN1_DATA_TYPE_BINARY_TIME(ASN1_STRING): 190 | tag = ASN_Tags_MMS.DATA_TYPE_BINARY_TIME 191 | 192 | 193 | class ASN1_DATA_TYPE_MMS_STRING(ASN1_UTF8_STRING): 194 | tag = ASN_Tags_MMS.DATA_TYPE_MMS_STRING 195 | 196 | 197 | class ASN1_DATA_TYPE_UTC_TIME(ASN1_STRING): 198 | tag = ASN_Tags_MMS.DATA_TYPE_UTC_TIME 199 | 200 | 201 | class ASN1_LIST_OF_VARIABLES(ASN1_SEQUENCE): 202 | tag = ASN_Tags_MMS.VARIABLE_ACCESS_SPECIFICATION_LIST_OF_VARIABLE 203 | 204 | 205 | class ASN1_VARIABLES_LIST_NAMES(ASN1_SEQUENCE): 206 | tag = ASN_Tags_MMS.VARIABLE_ACCESS_SPECIFICATION_VARIABLE_LIST_NAME 207 | 208 | 209 | class ASN1_FAILURE(ASN1_INTEGER): 210 | tag = ASN_Tags_MMS.FAILURE 211 | 212 | 213 | class ASN1_INFORMATION_REPORT_LIST_OF_ACCESS_RESULT(ASN1_SEQUENCE): 214 | tag = ASN_Tags_MMS.INFORMATION_REPORT_LIST_OF_ACCESS_RESULT 215 | 216 | 217 | class ASN1_INFORMATION_REPORT(ASN1_SEQUENCE): 218 | tag = ASN_Tags_MMS.INFORMATION_REPORT 219 | -------------------------------------------------------------------------------- /iec61850_mms/tpkt.py: -------------------------------------------------------------------------------- 1 | """ 2 | Basic Scapy Definitions for TPKT (RFC 1006 - ISO Transport Service on top of the TCP Version: 3" 3 | 4 | Source documents for these definitions: 5 | - https://tools.ietf.org/html/rfc1006 6 | """ 7 | 8 | from scapy.packet import Packet 9 | from scapy.fields import ByteField, LenField 10 | 11 | 12 | TPKT_ISO_TSAP_PORT = 102 13 | TPKT_VERSION = 0x03 14 | 15 | 16 | class TPKT(Packet): 17 | name = "TPKT" 18 | fields_desc = [ByteField("version", TPKT_VERSION), 19 | ByteField("reserved", 0x00), 20 | LenField("length", None, fmt="!H", adjust=lambda x: x + 4)] 21 | 22 | 23 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | scapy~=2.4.3 --------------------------------------------------------------------------------