crypto: initial support for EAP and IKEv2 formats

This commit is contained in:
p1-bmu 2020-10-20 18:16:41 +02:00
parent 6b8691bfec
commit 5bb36ffa9b
2 changed files with 1042 additions and 0 deletions

147
pycrate_crypto/EAP.py Normal file
View File

@ -0,0 +1,147 @@
# * coding: UTF8 *
#/**
# * Software Name : pycrate
# * Version : 0.4
# *
# * Copyright 2020. Benoit Michau. P1Sec.
# *
# * This library is free software; you can redistribute it and/or
# * modify it under the terms of the GNU Lesser General Public
# * License as published by the Free Software Foundation; either
# * version 2.1 of the License, or (at your option) any later version.
# *
# * This library is distributed in the hope that it will be usefu,
# * but WITHOUT ANY WARRANTY; without even the implied warranty of
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# * Lesser General Public License for more details.
# *
# * You should have received a copy of the GNU Lesser General Public
# * License along with this library; if not, write to the Free Software
# * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# * MA 02110-1301 USA
# *
# *--------------------------------------------------------
# * File Name : pycrate_crypto/EAP.py
# * Created : 2020-10-20
# * Authors : Benoit Michau
# *--------------------------------------------------------
#*/
from enum import Enum
from pycrate_core.utils import *
from pycrate_core.elt import *
from pycrate_core.base import *
from pycrate_core.repr import *
#------------------------------------------------------------------------------#
# Extensible Authentication Protocol
# IETF RFC 3748: https://tools.ietf.org/html/rfc3748
# IANA EAP Parameters: https://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml
#------------------------------------------------------------------------------#
#------------------------------------------------------------------------------#
# EAP complete packet
# section 4 - EAP Packet Format
#------------------------------------------------------------------------------#
class EAPPacketCode(Enum):
Request = 1
Response = 2
Success = 3
Failure = 4
Initiate = 5
Finish = 6
EAPPacketCode_dict = {e.value: e.name for e in EAPPacketCode}
class EAPPacketType(Enum):
Identity = 1
Notification = 2
Legacy_Nak = 3
MD5_Challenge = 4
One_Time_Password = 5
Generic_Token_Card = 6
RSA_Public_Key_Authentication = 9
DSS_Unilateral = 10
KEA = 11
KEA_VALIDATE = 12
EAP_TLS = 13
Defender_Token = 14
RSA_Security_SecurID_EAP = 15
Arcot_Systems_EAP = 16
EAP_Cisco_Wireless = 17
EAP_SIM = 18
SRP_SHA1 = 19
EAP_TTLS = 21
Remote_Access_Service = 22
EAP_AKA = 23
EAP_3Com_Wireless = 24
PEAP = 25
MS_EAP_Authentication = 26
MAKE = 27
CRYPTOCard = 28
MSCHAPv2 = 29
DynamID = 30
Rob_EAP = 31
Protected_One_Time_Password = 32
MS_Authentication_TLV = 33
SentriNET = 34
EAP_Actiontec_Wireless = 35
Cogent_Systems_Biometrics_Authentication_EAP = 36
AirFortress_EAP = 37
HTTP_Digest = 38
SecureSuite_EAP = 39
DeviceConnect_EAP = 40
EAP_SPEKE = 41
EAP_MOBAC = 42
EAP_FAST = 43
ZoneLabs_EAP = 44
EAP_Link = 45
EAP_PAX = 46
EAP_PSK = 47
EAP_SAKE = 48
EAP_IKEv2 = 49
EAP_AKA_prime = 50
EAP_GPSK = 51
EAP_pwd = 52
EAP_EKE_V1 = 53
EAP_for_PT_EAP = 54
TEAP = 55
EAPPacketType_dict = {e.value: e.name for e in EAPPacketType}
class EAPDial(Envelope):
_GEN = (
Uint8('Type', val=EAPPacketType.Identity.value, dic=EAPPacketType_dict),
Buf('Data', val=b'', rep=REPR_HEX)
)
class EAP(Envelope):
_GEN = (
Uint8('Code', val=EAPPacketCode.Request.value, dic=EAPPacketCode_dict),
Uint8('Ident', val=1),
Uint16('Len'),
Alt('Data', GEN={
EAPPacketCode.Request.value : EAPDial('Req'),
EAPPacketCode.Response.value : EAPDial('Resp'),
EAPPacketCode.Success.value : Buf('none', bl=0, rep=REPR_HEX),
EAPPacketCode.Failure.value : Buf('none', bl=0, rep=REPR_HEX),
EAPPacketCode.Initiate.value : EAPDial('Init'),
EAPPacketCode.Finish.value : EAPDial('Fin')},
DEFAULT=Buf('unk', val=b'', rep=REPR_HEX),
sel=lambda self: self.get_env()['Code'].get_val())
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self['Len'].set_valauto(lambda: 4+self['Data'].get_len())
self['Data'].set_blauto(lambda: (self['Len'].get_val()-4)<<3)

895
pycrate_crypto/IKEv2.py Normal file
View File

@ -0,0 +1,895 @@
# * coding: UTF8 *
#/**
# * Software Name : pycrate
# * Version : 0.4
# *
# * Copyright 2020. Benoit Michau. P1Sec.
# *
# * This library is free software; you can redistribute it and/or
# * modify it under the terms of the GNU Lesser General Public
# * License as published by the Free Software Foundation; either
# * version 2.1 of the License, or (at your option) any later version.
# *
# * This library is distributed in the hope that it will be usefu,
# * but WITHOUT ANY WARRANTY; without even the implied warranty of
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# * Lesser General Public License for more details.
# *
# * You should have received a copy of the GNU Lesser General Public
# * License along with this library; if not, write to the Free Software
# * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# * MA 02110-1301 USA
# *
# *--------------------------------------------------------
# * File Name : pycrate_crypto/IKEv2.py
# * Created : 2020-10-14
# * Authors : Benoit Michau
# *--------------------------------------------------------
#*/
from enum import Enum
from pycrate_core.utils import *
from pycrate_core.elt import *
from pycrate_core.base import *
from pycrate_core.repr import *
#
from pycrate_ether.IP import IPProt_dict
from pycrate_crypto.EAP import EAP
#------------------------------------------------------------------------------#
# Internet Key Exchange v2
# IETF RFC 7296: https://tools.ietf.org/html/rfc7296
# IANA IKEv2 Parameters: https://www.iana.org/assignments/ikev2-parameters/ikev2-parameters.xhtml
#------------------------------------------------------------------------------#
#------------------------------------------------------------------------------#
# Security Association Payload
# section 3.3
#------------------------------------------------------------------------------#
class _AttributeLV(Envelope):
_GEN = (
Uint16('L'),
Buf('V', val=b'', rep=REPR_HEX)
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: self[1].get_len())
self[1].set_blauto(lambda: self[0].get_val()<<3)
class Attribute(Envelope):
_GEN = (
Uint('AF', bl=1),
Uint('Type', bl=15),
Alt('Attr', GEN={
0: _AttributeLV('LV'),
1: Buf('V', bl=16, rep=REPR_HEX)},
sel=lambda self: self.get_env()['AF'].get_val()
)
)
class IKEv2TransType(Enum):
ENCR = 1
PRF = 2
INTEG = 3
DH = 4
ESN = 5
IKEv2TransType_dict = {e.value: e.name for e in IKEv2TransType}
class IKEv2TransENCR(Enum):
ENCR_DES_IV64 = 1
ENCR_DES = 2
ENCR_3DES = 3
ENCR_RC5 = 4
ENCR_IDEA = 5
ENCR_CAST = 6
ENCR_BLOWFISH = 7
ENCR_3IDEA = 8
ENCR_DES_IV32 = 9
ENCR_NULL = 11
ENCR_AES_CBC = 12
ENCR_AES_CTR = 13
ENCR_AES_CCM_8 = 14
ENCR_AES_CCM_12 = 15
ENCR_AES_CCM_16 = 16
ENCR_AES_GCM_8 = 18
ENCR_AES_GCM_12 = 19
ENCR_AES_GCM_16 = 20
ENCR_NULL_AUTH_AES_GMAC = 21
ENCR_IEEE_P1619_XT_AES = 22
ENCR_CAMELLIA_CBC = 23
ENCR_CAMELLIA_CTR = 24
ENCR_CAMELLIA_CCM_8 = 25
ENCR_CAMELLIA_CCM_12 = 26
ENCR_CAMELLIA_CCM_16 = 27
ENCR_CHACHA20_POLY1305 = 28
ENCR_AES_CCM_8_IIV = 29
ENCR_AES_GCM_16_IIV = 30
ENCR_CHACHA20_POLY1305_IIV = 31
ENCR_KUZNYECHIK_MGM_KTREE = 32
ENCR_MAGMA_MGM_KTREE = 33
ENCR_KUZNYECHIK_MGM_MAC_KTREE = 34
ENCR_MAGMA_MGM_MAC_KTREE = 35
IKEv2TransENCR_dict = {e.value: e.name for e in IKEv2TransENCR}
class IKEv2TransPRF(Enum):
PRF_HMAC_MD5 = 1
PRF_HMAC_SHA1 = 2
PRF_HMAC_TIGER = 3
PRF_AES128_XCBC = 4
PRF_HMAC_SHA2_256 = 5
PRF_HMAC_SHA2_384 = 6
PRF_HMAC_SHA2_512 = 7
PRF_AES128_CMAC = 8
PRF_HMAC_STRIBOG_512 = 9
IKEv2TransPRF_dict = {e.value: e.name for e in IKEv2TransPRF}
class IKEv2TransAUTH(Enum):
NONE = 0
AUTH_HMAC_MD5_96 = 1
AUTH_HMAC_SHA1_96 = 2
AUTH_DES_MAC = 3
AUTH_KPDK_MD5 = 4
AUTH_AES_XCBC_96 = 5
AUTH_HMAC_MD5_128 = 6
AUTH_HMAC_SHA1_160 = 7
AUTH_AES_CMAC_96 = 8
AUTH_AES_128_GMAC = 9
AUTH_AES_192_GMAC = 10
AUTH_AES_256_GMAC = 11
AUTH_HMAC_SHA2_256_128 = 12
AUTH_HMAC_SHA2_384_192 = 13
AUTH_HMAC_SHA2_512_256 = 14
IKEv2TransAUTH_dict = {e.value: e.name for e in IKEv2TransAUTH}
class IKEv2TransDH(Enum):
NONE = 0
MODP_Group_768 = 1
MODP_Group_1024 = 2
MODP_Group_1536 = 5
MODP_Group_2048 = 14
MODP_Group_3072 = 15
MODP_Group_4096 = 16
MODP_Group_6144 = 17
MODP_Group_8192 = 18
Random_ECP_Group_256 = 19
Random_ECP_Group_384 = 20
Random_ECP_Group_521 = 21
MODP_Group_1024_Prime_Order_Subgroup_160 = 22
MODP_Group_2048_Prime_Order_Subgroup_224 = 23
MODP_Group_2048_Prime_Order_Subgroup_256 = 24
Random_ECP_Group_192 = 25
Random_ECP_Group_224 = 26
BrainpoolP224r1 = 27
BrainpoolP256r1 = 28
BrainpoolP384r1 = 29
BrainpoolP512r1 = 30
Curve25519 = 31
Curve448 = 32
GOST3410_2012_256 = 33
GOST3410_2012_512 = 34
IKEv2TransDH_dict = {e.value: e.name for e in IKEv2TransDH}
class IKEv2TransESN(Enum):
NO_ESN = 0
ESN = 1
IKEv2TransESN_dict = {e.value: e.name for e in IKEv2TransESN}
IKEv2TransID_dict = {
1 : IKEv2TransENCR_dict,
2 : IKEv2TransPRF_dict,
3 : IKEv2TransAUTH_dict,
4 : IKEv2TransDH_dict,
5 : IKEv2TransESN_dict
}
class Transform(Envelope):
_GEN = (
Uint8('Last'),
Uint8('res'),
Uint16('Len'),
Uint8('Type', val=IKEv2TransType.ENCR.value, dic=IKEv2TransType_dict),
Uint8('res'),
Uint16('ID', val=1),
Sequence('Attributes', GEN=Attribute())
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self['Last'].set_valauto(lambda: 0 if self.get_next() is None else 3)
self['Len'].set_valauto(lambda: 8 + self['Attributes'].get_len())
self['ID'].set_dicauto(lambda: IKEv2TransID_dict.get(self['Type'].get_val(), {}))
self['Attributes'].set_blauto(lambda: (self['Len'].get_val() - 8)<<3)
class IKEv2ProtID(Enum):
IKE = 1
AH = 2
ESP = 3
IKEv2ProtID_dict = {e.value: e.name for e in IKEv2ProtID}
class Proposal(Envelope):
_GEN = (
Uint8('Last'),
Uint8('res'),
Uint16('Len'),
Uint8('Num'),
Uint8('ProtID', val=IKEv2ProtID.IKE.value, dic=IKEv2ProtID_dict),
Uint8('SPISize'), # 0 for initial IKE SA nego, then 4 (AH, ESP) or 8 (IKE)
Uint8('NumTrans'),
Buf('SPI', val=b'', rep=REPR_HEX),
Sequence('Transforms', GEN=Transform())
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self['Last'].set_valauto(lambda: 0 if self.get_next() is None else 2)
self['Len'].set_valauto(lambda: 8 + self['SPI'].get_len() + self['Transforms'].get_len())
self['Num'].set_valauto(lambda: self.get_env().index(self))
self['SPISize'].set_valauto(lambda: self['SPI'].get_len())
self['NumTrans'].set_valauto(lambda: self['Transforms'].get_num())
self['SPI'].set_blauto(lambda: self['SPISize'].get_val()<<3)
self['Transforms'].set_numauto(lambda: self['NumTrans'].get_val())
self['Transforms'].set_blauto(lambda: (self['Len'].get_val() - self['SPISize'].get_val() - 8)<<3)
class PaySA(Sequence):
_GEN = Proposal()
#------------------------------------------------------------------------------#
# Key Exchange Payload
# section 3.4
#------------------------------------------------------------------------------#
class PayKE(Envelope):
_GEN = (
Uint16('DHGroup', val=IKEv2TransDH.MODP_Group_1024.value, dic=IKEv2TransDH_dict),
Uint16('res', rep=REPR_HEX),
Buf('Data', val=b'', rep=REPR_HEX)
)
#------------------------------------------------------------------------------#
# Identification Payloads
# section 3.5
#------------------------------------------------------------------------------#
class IKEv2IDType(Enum):
ID_IPV4_ADDR = 1
ID_FQDN = 2
ID_RFC822_ADDR = 3
ID_IPV6_ADDR = 5
ID_DER_ASN1_DN = 9
ID_DER_ASN1_GN = 10
ID_KEY_ID = 11
ID_FC_NAME = 12
ID_NULL = 13
IKEv2IDType_dict = {e.value: e.name for e in IKEv2IDType}
class PayID(Envelope):
_GEN = (
Uint8('Type', val=IKEv2IDType.ID_IPV4_ADDR.value, dic=IKEv2IDType_dict),
Uint24('res', rep=REPR_HEX),
Buf('Data', val=b'', rep=REPR_HEX)
)
#------------------------------------------------------------------------------#
# Certificate Payload
# section 3.6
# Certificate Request Payload
# section 3.7
#------------------------------------------------------------------------------#
class IKEv2CertEncoding(Enum):
PKCS7_wrapped_X509_Cert = 1
PGP_Cert = 2
DNS_Signed_Key = 3
X509_Cert_Signature = 4
Kerberos_Token = 6
Certificate_Revocation_List = 7
Authority_Revocation_List = 8
SPKI_Cert = 9
X509_Cert_Attribute = 10
Raw_RSA_Key = 11
Hash_URL_X509_Cert = 12
Hash_URL_X509_Bundle = 13
OCSP_Content = 14
Raw_Public_Key = 15
IKEv2CertEncoding_dict = {e.value: e.name for e in IKEv2CertEncoding}
class PayCert(Envelope):
_GEN = (
Uint8('Encoding', val=1, dic=IKEv2CertEncoding_dict),
Buf('Data', val=b'', rep=REPR_HEX)
)
#------------------------------------------------------------------------------#
# Authentication Payload
# section 3.8
#------------------------------------------------------------------------------#
class IKEv2AuthMethod(Enum):
RSA_Digital_Signature = 1
Shared_Key_Message_Integrity_Code = 2
DSS_Digital_Signature = 3
ECDSA_SHA256_P256 = 9
ECDSA_SHA384_P384 = 10
ECDSA_SHA512_P521 = 11
Generic_Secure_Password = 12
NULL = 13
Digital_Signature = 14
IKEv2AuthMethod_dict = {e.value: e.name for e in IKEv2AuthMethod}
class PayAuth(Envelope):
_GEN = (
Uint8('Method', val=1, dic=IKEv2AuthMethod_dict),
Uint24('res', rep=REPR_HEX),
Buf('Data', val=b'', rep=REPR_HEX)
)
#------------------------------------------------------------------------------#
# Nonce Payload
# section 3.9
#------------------------------------------------------------------------------#
class PayNonce(Envelope):
_GEN = (
Buf('Data', val=b'', rep=REPR_HEX),
)
#------------------------------------------------------------------------------#
# Notify Payload
# section 3.10
#------------------------------------------------------------------------------#
# error notifications
class IKEv2NotifTypeErr(Enum):
UNSUPPORTED_CRITICAL_PAYLOAD = 1
INVALID_IKE_SPI = 4
INVALID_MAJOR_VERSION = 5
INVALID_SYNTAX = 7
INVALID_MESSAGE_ID = 9
INVALID_SPI = 11
NO_PROPOSAL_CHOSEN = 14
INVALID_KE_PAYLOAD = 17
AUTHENTICATION_FAILED = 24
SINGLE_PAIR_REQUIRED = 34
NO_ADDITIONAL_SAS = 35
INTERNAL_ADDRESS_FAILURE = 36
FAILED_CP_REQUIRED = 37
TS_UNACCEPTABLE = 38
INVALID_SELECTORS = 39
UNACCEPTABLE_ADDRESSES = 40
UNEXPECTED_NAT_DETECTED = 41
USE_ASSIGNED_HoA = 42
TEMPORARY_FAILURE = 43
CHILD_SA_NOT_FOUND = 44
INVALID_GROUP_ID = 45
AUTHORIZATION_FAILED = 46
IKEv2NotifTypeErr_dict = {e.value: e.name for e in IKEv2NotifTypeErr}
# status notifications
class IKEv2NotifTypeStat(Enum):
INITIAL_CONTACT = 16384
SET_WINDOW_SIZE = 16385
ADDITIONAL_TS_POSSIBLE = 16386
IPCOMP_SUPPORTED = 16387
NAT_DETECTION_SOURCE_IP = 16388
NAT_DETECTION_DESTINATION_IP = 16389
COOKIE = 16390
USE_TRANSPORT_MODE = 16391
HTTP_CERT_LOOKUP_SUPPORTED = 16392
REKEY_SA = 16393
ESP_TFC_PADDING_NOT_SUPPORTED = 16394
NON_FIRST_FRAGMENTS_ALSO = 16395
MOBIKE_SUPPORTED = 16396
ADDITIONAL_IP4_ADDRESS = 16397
ADDITIONAL_IP6_ADDRESS = 16398
NO_ADDITIONAL_ADDRESSES = 16399
UPDATE_SA_ADDRESSES = 16400
COOKIE2 = 16401
NO_NATS_ALLOWED = 16402
AUTH_LIFETIME = 16403
MULTIPLE_AUTH_SUPPORTED = 16404
ANOTHER_AUTH_FOLLOWS = 16405
REDIRECT_SUPPORTED = 16406
REDIRECT = 16407
REDIRECTED_FROM = 16408
TICKET_LT_OPAQUE = 16409
TICKET_REQUEST = 16410
TICKET_ACK = 16411
TICKET_NACK = 16412
TICKET_OPAQUE = 16413
LINK_ID = 16414
USE_WESP_MODE = 16415
ROHC_SUPPORTED = 16416
EAP_ONLY_AUTHENTICATION = 16417
CHILDLESS_IKEV2_SUPPORTED = 16418
QUICK_CRASH_DETECTION = 16419
IKEV2_MESSAGE_ID_SYNC_SUPPORTED = 16420
IPSEC_REPLAY_COUNTER_SYNC_SUPPORTED = 16421
IKEV2_MESSAGE_ID_SYNC = 16422
IPSEC_REPLAY_COUNTER_SYNC = 16423
SECURE_PASSWORD_METHODS = 16424
PSK_PERSIST = 16425
PSK_CONFIRM = 16426
ERX_SUPPORTED = 16427
IFOM_CAPABILITY = 16428
SENDER_REQUEST_ID = 16429
IKEV2_FRAGMENTATION_SUPPORTED = 16430
SIGNATURE_HASH_ALGORITHMS = 16431
CLONE_IKE_SA_SUPPORTED = 16432
CLONE_IKE_SA = 16433
PUZZLE = 16434
USE_PPK = 16435
PPK_IDENTITY = 16436
NO_PPK_AUTH = 16437
INTERMEDIATE_EXCHANGE_SUPPORTED = 16438
IKEv2NotifTypeStat_dict = {e.value: e.name for e in IKEv2NotifTypeStat}
# all notifications
IKEv2NotifType_dict = dict(IKEv2NotifTypeErr_dict)
IKEv2NotifType_dict.update(IKEv2NotifTypeStat_dict)
class PayNotif(Envelope):
_GEN = (
Uint8('ProtID', val=IKEv2ProtID.IKE.value, dic=IKEv2ProtID_dict),
Uint8('SPISize'), # 0 for initial IKE SA nego, then 4 (AH, ESP) or 8 (IKE)
Uint16('Type', val=IKEv2NotifTypeErr.TEMPORARY_FAILURE.value, dic=IKEv2NotifType_dict),
Buf('SPI', val=b'', rep=REPR_HEX),
Buf('Data', val=b'', rep=REPR_HEX)
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self['SPISize'].set_valauto(lambda: self['SPI'].get_len())
self['SPI'].set_blauto(lambda: self['SPISize'].get_val()<<3)
#------------------------------------------------------------------------------#
# Delete Payload
# section 3.11
#------------------------------------------------------------------------------#
class PayDelete(Envelope):
_GEN = (
Uint8('ProtID', val=IKEv2ProtID.IKE.value, dic=IKEv2ProtID_dict),
Uint8('SPISize'), # 0 for initial IKE SA nego, then 4 (AH, ESP) or 8 (IKE)
Uint8('NumSPIs'),
Sequence('SPIs', GEN=Buf('SPI', rep=REPR_HEX))
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self['SPISize'].set_valauto(lambda: self['SPIs'][0].get_len() if self['SPIs'].get_num() else 0)
self['NumSPIs'].set_valauto(lambda: self['SPIs'].get_num())
self['SPIs'].set_numauto(lambda: self['NumSPIs'].get_val())
def _from_char(self, char):
self[0]._from_char(char)
self[1]._from_char(char)
self[2]._from_char(char)
self[3]._tmpl._bl = self[1].get_val()<<3
self[3]._from_char(char)
self[3]._tmpl._bl = None
#------------------------------------------------------------------------------#
# VendorID Payload
# section 3.12
#------------------------------------------------------------------------------#
class PayVID(Envelope):
_GEN = (
Buf('Data', val=b'', rep=REPR_HEX),
)
#------------------------------------------------------------------------------#
# Traffic Selector Payload
# section 3.13
#------------------------------------------------------------------------------#
class IKEv2TSType(Enum):
IPV4_ADDR_RANGE = 7
IPV6_ADDR_RANGE = 8
IKEv2TSType_dict = {e.value: e.name for e in IKEv2TSType}
class IKEv2TS(Envelope):
_GEN = (
Uint8('Type', val=IKEv2TSType.IPV4_ADDR_RANGE.value, dic=IKEv2TSType_dict),
Uint8('IPProt', val=0, dic=IPProt_dict),
Uint16('Len'),
Uint16('PortStart', val=0),
Uint16('PortEnd', val=0),
Buf('AddrStart', val=b'', rep=REPR_HEX),
Buf('AddrEnd', val=b'', rep=REPR_HEX)
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self['Len'].set_valauto(lambda: 8 + self['AddrStart'].get_len() + self['AddrEnd'].get_len())
self['AddrStart'].set_blauto(lambda: (self['Len'].get_val()-8)<<2)
self['AddrEnd'].set_blauto(lambda: (self['Len'].get_val()-8)<<2)
class PayTS(Envelope):
_GEN = (
Uint8('NumTSs'),
Uint24('res', rep=REPR_HEX),
Sequence('TSs', GEN=IKEv2TS('TS'))
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self['NumTSs'].set_valauto(lambda: self['TSs'].get_num())
self['TSs'].set_numauto(lambda: self['NumTSs'].get_val())
#------------------------------------------------------------------------------#
# Encrypted Payload
# section 3.14
#------------------------------------------------------------------------------#
# length of IV
# Warning: some of those values are not confirmed / tested / verified
IKEv2EncrIVLen_dict = {
IKEv2TransENCR.ENCR_DES_IV64 : 8,
IKEv2TransENCR.ENCR_DES : 8,
IKEv2TransENCR.ENCR_3DES : 8,
IKEv2TransENCR.ENCR_RC5 : 8,
IKEv2TransENCR.ENCR_IDEA : 8,
IKEv2TransENCR.ENCR_CAST : 8,
IKEv2TransENCR.ENCR_BLOWFISH : 8,
IKEv2TransENCR.ENCR_3IDEA : 8,
IKEv2TransENCR.ENCR_DES_IV32 : 8,
IKEv2TransENCR.ENCR_NULL : 0,
IKEv2TransENCR.ENCR_AES_CBC : 16,
IKEv2TransENCR.ENCR_AES_CTR : 16,
IKEv2TransENCR.ENCR_AES_CCM_8 : 16,
IKEv2TransENCR.ENCR_AES_CCM_12 : 16,
IKEv2TransENCR.ENCR_AES_CCM_16 : 16,
IKEv2TransENCR.ENCR_AES_GCM_8 : 16,
IKEv2TransENCR.ENCR_AES_GCM_12 : 16,
IKEv2TransENCR.ENCR_AES_GCM_16 : 16,
IKEv2TransENCR.ENCR_NULL_AUTH_AES_GMAC : 16,
IKEv2TransENCR.ENCR_IEEE_P1619_XT_AES : 16,
IKEv2TransENCR.ENCR_CAMELLIA_CBC : 16,
IKEv2TransENCR.ENCR_CAMELLIA_CTR : 16,
IKEv2TransENCR.ENCR_CAMELLIA_CCM_8 : 16,
IKEv2TransENCR.ENCR_CAMELLIA_CCM_12 : 16,
IKEv2TransENCR.ENCR_CAMELLIA_CCM_16 : 16,
IKEv2TransENCR.ENCR_CHACHA20_POLY1305 : 16,
IKEv2TransENCR.ENCR_AES_CCM_8_IIV : 16,
IKEv2TransENCR.ENCR_AES_GCM_16_IIV : 16,
IKEv2TransENCR.ENCR_CHACHA20_POLY1305_IIV : 16,
IKEv2TransENCR.ENCR_KUZNYECHIK_MGM_KTREE : 8,
IKEv2TransENCR.ENCR_MAGMA_MGM_KTREE : 8,
IKEv2TransENCR.ENCR_KUZNYECHIK_MGM_MAC_KTREE : 8,
IKEv2TransENCR.ENCR_MAGMA_MGM_MAC_KTREE : 8,
}
# length of ICS
IKEv2AuthICSLen_dict = {
IKEv2TransAUTH.NONE : 0,
IKEv2TransAUTH.AUTH_HMAC_MD5_96 : 12,
IKEv2TransAUTH.AUTH_HMAC_SHA1_96 : 12,
IKEv2TransAUTH.AUTH_DES_MAC : 8,
IKEv2TransAUTH.AUTH_KPDK_MD5 : 16,
IKEv2TransAUTH.AUTH_AES_XCBC_96 : 12,
IKEv2TransAUTH.AUTH_HMAC_MD5_128 : 16,
IKEv2TransAUTH.AUTH_HMAC_SHA1_160 : 20,
IKEv2TransAUTH.AUTH_AES_CMAC_96 : 12,
IKEv2TransAUTH.AUTH_AES_128_GMAC : 16,
IKEv2TransAUTH.AUTH_AES_192_GMAC : 24,
IKEv2TransAUTH.AUTH_AES_256_GMAC : 32,
IKEv2TransAUTH.AUTH_HMAC_SHA2_256_128 : 16,
IKEv2TransAUTH.AUTH_HMAC_SHA2_384_192 : 24,
IKEv2TransAUTH.AUTH_HMAC_SHA2_512_256 : 32,
}
class PayEncr(Envelope):
# the configuration of the encryption and integrity checksum algorithms
# is contextual
ALG_ENCR = IKEv2TransENCR.ENCR_NULL
ALG_AUTH = IKEv2TransAUTH.NONE
_GEN = (
Buf('IV', rep=REPR_HEX),
Buf('Data', val=b'', rep=REPR_HEX),
Buf('Pad', val=b'', rep=REPR_HEX),
Uint8('PadLen'),
Buf('ICS', rep=REPR_HEX)
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self['IV'].set_blauto(lambda: IKEv2EncrIVLen_dict.get(self.ALG_ENCR, 0))
self['PadLen'].set_valauto(lambda: self['Pad'].get_len())
self['ICS'].set_blauto(lambda: IKEv2AuthICSLen_dict.get(self.ALG_AUTH, 0))
# TODO
def encrypt(self, data, key):
pass
def decrypt(self, key):
pass
def ics_compute(self, key):
pass
def ics_verify(self, key):
pass
#------------------------------------------------------------------------------#
# Configuration Payload
# section 3.15
#------------------------------------------------------------------------------#
class IKEv2AttrType(Enum):
INTERNAL_IP4_ADDRESS = 1
INTERNAL_IP4_NETMASK = 2
INTERNAL_IP4_DNS = 3
INTERNAL_IP4_NBNS = 4
INTERNAL_IP4_DHCP = 6
APPLICATION_VERSION = 7
INTERNAL_IP6_ADDRESS = 8
INTERNAL_IP6_DNS = 10
INTERNAL_IP6_DHCP = 12
INTERNAL_IP4_SUBNET = 13
SUPPORTED_ATTRIBUTES = 14
INTERNAL_IP6_SUBNET = 15
MIP6_HOME_PREFIX = 16
INTERNAL_IP6_LINK = 17
INTERNAL_IP6_PREFIX = 18
HOME_AGENT_ADDRESS = 19
P_CSCF_IP4_ADDRESS = 20
P_CSCF_IP6_ADDRESS = 21
FTT_KAT = 22
EXTERNAL_SOURCE_IP4_NAT_INFO = 23
TIMEOUT_PERIOD_FOR_LIVENESS_CHECK = 24
INTERNAL_DNS_DOMAIN = 25
INTERNAL_DNSSEC_TA = 26
IKEv2AttrType_dict = {e.value: e.name for e in IKEv2AttrType}
class IKEv2Attr(Envelope):
_GEN = (
Uint('R', bl=1),
Uint('Type', val=IKEv2AttrType.SUPPORTED_ATTRIBUTES.value, bl=15, dic=IKEv2AttrType_dict),
Uint8('Len'),
Buf('Value', val=b'', rep=REPR_HEX),
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self['Len'].set_valauto(lambda: self['Value'].get_len())
self['Value'].set_blauto(lambda: self['Len'].get_val()<<3)
class IKEv2ConfigType(Enum):
CFG_REQUEST = 1
CFG_REPLY = 2
CFG_SET = 3
CFG_ACK = 4
IKEv2ConfigType_dict = {e.value: e.name for e in IKEv2ConfigType}
class PayConfig(Envelope):
_GEN = (
Uint8('Type', val=IKEv2ConfigType.CFG_REQUEST.value, dic=IKEv2ConfigType_dict),
Uint24('res', rep=REPR_HEX),
Sequence('Attrs', GEN=IKEv2Attr('Attr'))
)
#------------------------------------------------------------------------------#
# Extensible Authentication Protocol (EAP) Payload
# section 3.16
#------------------------------------------------------------------------------#
class PayEAP(Envelope):
_GEN = (
EAP(),
)
#------------------------------------------------------------------------------#
# IKEv2 payload header
# section 3.2
#------------------------------------------------------------------------------#
class IKEv2PayType(Enum):
NoNextPayload = 0
SecurityAssociation = 33
KeyExchange = 34
IdentInitiator = 35
IdentResponder = 36
Certifiate = 37
CertificateRequest = 38
Authentication = 39
Nonce = 40
Notify = 41
Delete = 42
VendorID = 43
TrafficSelectorInitiator = 44
TrafficSelectorResponder = 45
EncryptedAuthenticated = 46
Configuration = 47
EAP = 48
GenericSecurePwdMethod = 49
GroupIdentification = 50
GroupSecurityAssociation = 51
KeyDownload = 52
EncryptedAuthenticatedFrag = 53
PuzzleSolution = 54
IKEv2PayType_dict = {e.value: e.name for e in IKEv2PayType}
class IKEv2Pay(Envelope):
# LUT for payload
LUTPay = {
33 : PaySA('SA'),
34 : PayKE('KE'),
35 : PayID('IDi'),
36 : PayID('IDr'),
37 : PayCert('CERT'),
38 : PayCert('CERTREQ'),
39 : PayAuth('AUTH'),
40 : PayNonce('NONCE'),
41 : PayNotif('N'),
42 : PayDelete('D'),
43 : PayVID('V'),
44 : PayTS('TSi'),
45 : PayTS('TSr'),
46 : PayEncr('SK'),
47 : PayConfig('CP'),
48 : PayEAP('EAP'),
}
_GEN = (
Uint8('Next'),
Uint('C', bl=1),
Uint('res', bl=7, rep=REPR_HEX),
Uint16('Len'),
Buf('Pay', val=b'', rep=REPR_HEX)
)
def __init__(self, *args, **kwargs):
self.Type = 1
Envelope.__init__(self, *args, **kwargs)
self['Next'].set_valauto(lambda: getattr(self.get_next(), 'Type', 0))
self['Len'].set_valauto(lambda: 4 + self[4].get_len())
self['Pay'].set_blauto(lambda: (self[3].get_val() - 4)<<3)
def set_val(self, val):
if isinstance(val, dict) and 'Type' in val and val['Type'] in self.LUTPay:
self.Type = val['Type']
del val['Type']
pay = self.LUTPay[val['Type']].clone()
pay.set_blauto(lambda: (self[3].get_val() - 4)<<3)
self.replace(self[4], pay)
Envelope.set_val(self, val)
def _from_char(self, char):
e, n = self.get_env(), None
if e is not None:
if e.get_num():
# get the last IKEv2Pay within the Payloads Sequence
n = e[-1]
else:
e = e.get_env()
if e is not None:
# get the IKEv2 header
n = e[0]
if n is not None:
next = n['Next'].get_val()
if next in self.LUTPay:
self.Type = next
pay = self.LUTPay[next].clone()
pay.set_blauto(lambda: (self[3].get_val() - 4)<<3)
self.replace(self[4], pay)
Envelope._from_char(self, char)
#------------------------------------------------------------------------------#
# IKEv2 header
# section 3.1
#------------------------------------------------------------------------------#
class IKEv2ExchType(Enum):
IKE_SA_INIT = 34
IKE_AUTH = 35
CREATE_CHILD_SA = 36
INFORMATIONAL = 37
IKE_SESSION_RESUME = 38
GSA_AUTH = 39
GSA_REGISTRATION = 40
GSA_REKEY = 41
IKE_INTERMEDIATE = 43
IKEv2ExchType_dict = {e.value: e.name for e in IKEv2ExchType}
class IKEv2HdrFlags(Envelope):
_GEN = (
Uint('undef', bl=2, rep=REPR_HEX),
Uint('R', bl=1),
Uint('V', bl=1),
Uint('I', bl=1),
Uint('undef', bl=3, rep=REPR_HEX)
)
class IKEv2Hdr(Envelope):
_GEN = (
Buf('SPIInitiator', bl=64, rep=REPR_HEX),
Buf('SPIResponder', bl=64, rep=REPR_HEX),
Uint8('Next'),
Uint('VersMaj', val=2, bl=4),
Uint('VersMin', val=0, bl=4),
Uint8('ExchType', val=IKEv2ExchType.IKE_SA_INIT.value, dic=IKEv2ExchType_dict),
IKEv2HdrFlags('Flags'),
Uint32('MID', rep=REPR_HEX),
Uint32('Len', val=28)
)
#------------------------------------------------------------------------------#
# IKEv2 complete packet
#------------------------------------------------------------------------------#
class IKEv2(Envelope):
_GEN = (
IKEv2Hdr('Header'),
Sequence('Payloads', GEN=IKEv2Pay(), hier=1)
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0]['Next'].set_valauto(lambda: self[1][0].Type if self[1].get_num() else 0)
self[0]['Len'].set_valauto(lambda: 28 + self[1].get_len())
self[1].set_blauto(lambda: (self[0]['Len'].get_val()-28)<<3)