diff --git a/scapy/asn1/asn1.py b/scapy/asn1/asn1.py index 0783a3b3a77..bd58715e26d 100644 --- a/scapy/asn1/asn1.py +++ b/scapy/asn1/asn1.py @@ -93,7 +93,7 @@ def _fix(self, n=0): return o(GeneralizedTime()._fix()) elif issubclass(o, ASN1_STRING): z1 = int(random.expovariate(0.05) + 1) - return o("".join(random.choice(self.chars) for _ in range(z1))) + return o("".join(random.choice(self.chars) for _ in range(z1)).encode()) elif issubclass(o, ASN1_SEQUENCE) and (n < 10): z2 = int(random.expovariate(0.08) + 1) return o([self.__class__(objlist=self.objlist)._fix(n + 1) @@ -520,7 +520,7 @@ def __repr__(self): ) -class ASN1_STRING(ASN1_Object[str]): +class ASN1_STRING(ASN1_Object[bytes]): tag = ASN1_Class_UNIVERSAL.STRING @@ -555,11 +555,11 @@ class ASN1_UTF8_STRING(ASN1_STRING): tag = ASN1_Class_UNIVERSAL.UTF8_STRING -class ASN1_NUMERIC_STRING(ASN1_STRING): +class ASN1_NUMERIC_STRING(ASN1_Object[str]): tag = ASN1_Class_UNIVERSAL.NUMERIC_STRING -class ASN1_PRINTABLE_STRING(ASN1_STRING): +class ASN1_PRINTABLE_STRING(ASN1_Object[str]): tag = ASN1_Class_UNIVERSAL.PRINTABLE_STRING @@ -579,7 +579,7 @@ class ASN1_GENERAL_STRING(ASN1_STRING): tag = ASN1_Class_UNIVERSAL.GENERAL_STRING -class ASN1_GENERALIZED_TIME(ASN1_STRING): +class ASN1_GENERALIZED_TIME(ASN1_Object[str]): """ Improved version of ASN1_GENERALIZED_TIME, properly handling time zones and all string representation formats defined by ASN.1. These are: @@ -723,7 +723,7 @@ def __repr__(self): # type: () -> str return "<%s[%r]>" % ( self.__dict__.get("name", self.__class__.__name__), - self.val.decode("utf-16be"), # type: ignore + self.val.decode("utf-16be"), ) @@ -742,7 +742,7 @@ class ASN1_SET(ASN1_SEQUENCE): tag = ASN1_Class_UNIVERSAL.SET -class ASN1_IPADDRESS(ASN1_STRING): +class ASN1_IPADDRESS(ASN1_Object[str]): tag = ASN1_Class_UNIVERSAL.IPADDRESS diff --git a/scapy/asn1/mib.py b/scapy/asn1/mib.py index 16820fb30dd..029f8281225 100644 --- a/scapy/asn1/mib.py +++ b/scapy/asn1/mib.py @@ -260,6 +260,23 @@ def load_mib(filenames): "1.3.14.3.2.29": "sha1RSASign", } +# nist # + +nist_oids = { + "2.16.840.1.101.3.4.2.1": "sha256", + "2.16.840.1.101.3.4.2.2": "sha384", + "2.16.840.1.101.3.4.2.3": "sha512", + "2.16.840.1.101.3.4.2.4": "sha224", + "2.16.840.1.101.3.4.2.5": "sha512-224", + "2.16.840.1.101.3.4.2.6": "sba512-256", + "2.16.840.1.101.3.4.2.7": "sha3-224", + "2.16.840.1.101.3.4.2.8": "sha3-256", + "2.16.840.1.101.3.4.2.9": "sha3-384", + "2.16.840.1.101.3.4.2.10": "sha3-512", + "2.16.840.1.101.3.4.2.11": "shake128", + "2.16.840.1.101.3.4.2.12": "shake256", +} + # thawte # thawte_oids = { @@ -267,6 +284,12 @@ def load_mib(filenames): "1.3.101.113": "Ed448", } +# pkcs7 # + +pkcs7_oids = { + "1.2.840.113549.1.7.2": "id-signedData", +} + # pkcs9 # pkcs9_oids = { @@ -471,6 +494,7 @@ def load_mib(filenames): "2.5.29.69": "id-ce-holderNameConstraints", # [MS-WCCE] "1.3.6.1.4.1.311.2.1.14": "CERT_EXTENSIONS", + "1.3.6.1.4.1.311.10.3.4": "szOID_EFS_CRYPTO", "1.3.6.1.4.1.311.20.2": "ENROLL_CERTTYPE", "1.3.6.1.4.1.311.25.1": "NTDS_REPLICATION", "1.3.6.1.4.1.311.25.2": "NTDS_CA_SECURITY_EXT", @@ -560,6 +584,12 @@ def load_mib(filenames): "1.2.840.10045.4.3.4": "ecdsa-with-SHA512" } +# ansi-x942 # + +x942KeyType_oids = { + "1.2.840.10046.2.1": "dhpublicnumber", # RFC3770 sect 4.1.1 +} + # elliptic curves # ansiX962Curve_oids = { @@ -672,11 +702,29 @@ def load_mib(filenames): '1.3.6.1.4.1.311.2.2.30': 'NEGOEX - SPNEGO Extended Negotiation Security Mechanism', } +# kerberos # + +kerberos_oids = { + "1.3.6.1.5.2.3.1": "id-pkinit-authData", + "1.3.6.1.5.2.3.2": "id-pkinit-DHKeyData", + "1.3.6.1.5.2.3.3": "id-pkinit-rkeyData", + "1.3.6.1.5.2.3.4": "id-pkinit-KPClientAuth", + "1.3.6.1.5.2.3.5": "id-pkinit-KPKdc", + # RFC8363 + "1.3.6.1.5.2.3.6": "id-pkinit-kdf", + "1.3.6.1.5.2.3.6.1": "id-pkinit-kdf-sha1", + "1.3.6.1.5.2.3.6.2": "id-pkinit-kdf-sha256", + "1.3.6.1.5.2.3.6.3": "id-pkinit-kdf-sha512", + "1.3.6.1.5.2.3.6.4": "id-pkinit-kdf-sha384", +} + x509_oids_sets = [ pkcs1_oids, secsig_oids, + nist_oids, thawte_oids, + pkcs7_oids, pkcs9_oids, attributeType_oids, certificateExtension_oids, @@ -690,9 +738,11 @@ def load_mib(filenames): evPolicy_oids, x962KeyType_oids, x962Signature_oids, + x942KeyType_oids, ansiX962Curve_oids, certicomCurve_oids, gssapi_oids, + kerberos_oids, ] x509_oids = {} diff --git a/scapy/asn1fields.py b/scapy/asn1fields.py index 9603526c29a..f2d8613af37 100644 --- a/scapy/asn1fields.py +++ b/scapy/asn1fields.py @@ -606,6 +606,8 @@ def i2repr(self, pkt, x): # type: (ASN1_Packet, _I) -> str if self.holds_packets: return super(ASN1F_SEQUENCE_OF, self).i2repr(pkt, x) # type: ignore + elif x is None: + return "[]" else: return "[%s]" % ", ".join( self.fld.i2repr(pkt, x) for x in x # type: ignore @@ -979,7 +981,7 @@ class ASN1F_STRING_PacketField(ASN1F_STRING): def i2m(self, pkt, val): # type: (ASN1_Packet, Any) -> bytes if hasattr(val, "ASN1_root"): - val = ASN1_STRING(bytes(val)) # type: ignore + val = ASN1_STRING(bytes(val)) return super(ASN1F_STRING_PacketField, self).i2m(pkt, val) def any2i(self, pkt, x): @@ -987,3 +989,32 @@ def any2i(self, pkt, x): if hasattr(x, "add_underlayer"): x.add_underlayer(pkt) return super(ASN1F_STRING_PacketField, self).any2i(pkt, x) + + +class ASN1F_STRING_ENCAPS(ASN1F_STRING_PacketField): + """ + ASN1F_STRING that encapsulates a single ASN1 packet. + """ + + def __init__(self, + name, # type: str + default, # type: Optional[ASN1_Packet] + cls, # type: Type[ASN1_Packet] + context=None, # type: Optional[Any] + implicit_tag=None, # type: Optional[int] + explicit_tag=None, # type: Optional[int] + ): + # type: (...) -> None + self.cls = cls + super(ASN1F_STRING_ENCAPS, self).__init__( + name, + default and bytes(default), # type: ignore + context=context, + implicit_tag=implicit_tag, + explicit_tag=explicit_tag + ) + + def m2i(self, pkt, s): # type: ignore + # type: (ASN1_Packet, bytes) -> Tuple[ASN1_Packet, bytes] + val = super(ASN1F_STRING_ENCAPS, self).m2i(pkt, s) + return self.cls(val[0].val, _underlayer=pkt), val[1] diff --git a/scapy/layers/kerberos.py b/scapy/layers/kerberos.py index 39e734fe724..05b65057581 100644 --- a/scapy/layers/kerberos.py +++ b/scapy/layers/kerberos.py @@ -13,6 +13,7 @@ - Kerberos Pre-Authentication: RFC6113 (FAST) - Kerberos Principal Name Canonicalization and Cross-Realm Referrals: RFC6806 - Microsoft Windows 2000 Kerberos Change Password and Set Password Protocols: RFC3244 +- PKINIT and its extensions: RFC4556, RFC8070, RFC8636 and [MS-PKCA] - User to User Kerberos Authentication: draft-ietf-cat-user2user-03 - Public Key Cryptography Based User-to-User Authentication (PKU2U): draft-zhu-pku2u-09 - Initial and Pass Through Authentication Using Kerberos V5 (IAKERB): @@ -69,20 +70,22 @@ ASN1_Codecs, ) from scapy.asn1fields import ( + ASN1F_BIT_STRING_ENCAPS, ASN1F_BOOLEAN, ASN1F_CHOICE, + ASN1F_enum_INTEGER, ASN1F_FLAGS, ASN1F_GENERAL_STRING, ASN1F_GENERALIZED_TIME, ASN1F_INTEGER, ASN1F_OID, + ASN1F_optional, ASN1F_PACKET, - ASN1F_SEQUENCE, ASN1F_SEQUENCE_OF, - ASN1F_STRING, + ASN1F_SEQUENCE, + ASN1F_STRING_ENCAPS, ASN1F_STRING_PacketField, - ASN1F_enum_INTEGER, - ASN1F_optional, + ASN1F_STRING, ) from scapy.asn1packet import ASN1_Packet from scapy.automaton import Automaton, ATMT @@ -141,7 +144,16 @@ from scapy.layers.inet import TCP, UDP from scapy.layers.smb import _NV_VERSION from scapy.layers.smb2 import STATUS_ERREF -from scapy.layers.x509 import X509_AlgorithmIdentifier +from scapy.layers.tls.cert import Cert, PrivKey +from scapy.layers.x509 import ( + _CMS_ENCAPSULATED, + CMS_ContentInfo, + CMS_IssuerAndSerialNumber, + DHPublicKey, + X509_AlgorithmIdentifier, + X509_DirectoryName, + X509_SubjectPublicKeyInfo, +) # Redirect exports from RFC3961 try: @@ -1192,7 +1204,8 @@ class KrbFastResponse(ASN1_Packet): _PADATA_CLASSES[136] = (PA_FX_FAST_REQUEST, PA_FX_FAST_REPLY) -# RFC 4556 + +# RFC 4556 - PKINIT # sect 3.2.1 @@ -1202,13 +1215,20 @@ class ExternalPrincipalIdentifier(ASN1_Packet): ASN1_codec = ASN1_Codecs.BER ASN1_root = ASN1F_SEQUENCE( ASN1F_optional( - ASN1F_STRING("subjectName", "", implicit_tag=0xA0), + ASN1F_STRING_ENCAPS( + "subjectName", None, X509_DirectoryName, implicit_tag=0x80 + ), ), ASN1F_optional( - ASN1F_STRING("issuerAndSerialNumber", "", implicit_tag=0xA1), + ASN1F_STRING_ENCAPS( + "issuerAndSerialNumber", + None, + CMS_IssuerAndSerialNumber, + implicit_tag=0x81, + ), ), ASN1F_optional( - ASN1F_STRING("subjectKeyIdentifier", "", implicit_tag=0xA2), + ASN1F_STRING("subjectKeyIdentifier", "", implicit_tag=0x82), ), ) @@ -1216,7 +1236,12 @@ class ExternalPrincipalIdentifier(ASN1_Packet): class PA_PK_AS_REQ(ASN1_Packet): ASN1_codec = ASN1_Codecs.BER ASN1_root = ASN1F_SEQUENCE( - ASN1F_STRING("signedAuthpack", "", implicit_tag=0xA0), + ASN1F_STRING_ENCAPS( + "signedAuthpack", + CMS_ContentInfo(), + CMS_ContentInfo, + implicit_tag=0x80, + ), ASN1F_optional( ASN1F_SEQUENCE_OF( "trustedCertifiers", @@ -1233,16 +1258,115 @@ class PA_PK_AS_REQ(ASN1_Packet): _PADATA_CLASSES[16] = PA_PK_AS_REQ + +# [MS-PKCA] sect 2.2.3 + + +class PAChecksum2(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_STRING("checksum", "", explicit_tag=0xA0), + ASN1F_PACKET( + "algorithmIdentifier", + X509_AlgorithmIdentifier(), + X509_AlgorithmIdentifier, + explicit_tag=0xA1, + ), + ) + + +# still RFC 4556 sect 3.2.1 + + +class PKAuthenticator(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + Microseconds("cusec", 0, explicit_tag=0xA0), + KerberosTime("ctime", GeneralizedTime(), explicit_tag=0xA1), + UInt32("nonce", 0, explicit_tag=0xA2), + ASN1F_optional( + ASN1F_STRING("paChecksum", "", explicit_tag=0xA3), + ), + # RFC8070 extension + ASN1F_optional( + ASN1F_STRING("freshnessToken", "", explicit_tag=0xA4), + ), + # [MS-PKCA] sect 2.2.3 + ASN1F_optional( + ASN1F_PACKET("paChecksum2", None, PAChecksum2, explicit_tag=0xA5), + ), + ) + + +# RFC8636 sect 6 + + +class KDFAlgorithmId(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_OID("kdfId", "", explicit_tag=0xA0), + ) + + +# still RFC 4556 sect 3.2.1 + + +class AuthPack(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_PACKET( + "pkAuthenticator", + PKAuthenticator(), + PKAuthenticator, + explicit_tag=0xA0, + ), + ASN1F_optional( + ASN1F_PACKET( + "clientPublicValue", + X509_SubjectPublicKeyInfo(), + X509_SubjectPublicKeyInfo, + explicit_tag=0xA1, + ), + ), + ASN1F_optional( + ASN1F_SEQUENCE_OF( + "supportedCMSTypes", + [], + X509_AlgorithmIdentifier, + explicit_tag=0xA2, + ), + ), + ASN1F_optional( + ASN1F_STRING("clientDCNonce", None, explicit_tag=0xA3), + ), + # RFC8636 extension + ASN1F_optional( + ASN1F_SEQUENCE_OF("supportedKDFs", None, KDFAlgorithmId, explicit_tag=0xA4), + ), + ) + + +_CMS_ENCAPSULATED["1.3.6.1.5.2.3.1"] = AuthPack + # sect 3.2.3 class DHRepInfo(ASN1_Packet): ASN1_codec = ASN1_Codecs.BER ASN1_root = ASN1F_SEQUENCE( - ASN1F_STRING("dhSignedData", "", implicit_tag=0xA0), + ASN1F_STRING_ENCAPS( + "dhSignedData", + CMS_ContentInfo(), + CMS_ContentInfo, + implicit_tag=0x80, + ), ASN1F_optional( ASN1F_STRING("serverDHNonce", "", explicit_tag=0xA1), ), + # RFC8636 extension + ASN1F_optional( + ASN1F_PACKET("kdf", None, KDFAlgorithmId, explicit_tag=0xA2), + ), ) @@ -1263,6 +1387,22 @@ class PA_PK_AS_REP(ASN1_Packet): _PADATA_CLASSES[17] = PA_PK_AS_REP + +class KDCDHKeyInfo(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_BIT_STRING_ENCAPS( + "subjectPublicKey", DHPublicKey(), DHPublicKey, explicit_tag=0xA0 + ), + UInt32("nonce", 0, explicit_tag=0xA1), + ASN1F_optional( + KerberosTime("dhKeyExpiration", None, explicit_tag=0xA2), + ), + ) + + +_CMS_ENCAPSULATED["1.3.6.1.5.2.3.2"] = KDCDHKeyInfo + # [MS-SFU] @@ -1992,6 +2132,8 @@ class KRB_ERROR(ASN1_Packet): 91: "KDC_ERR_MORE_PREAUTH_DATA_REQUIRED", 92: "KDC_ERR_PREAUTH_BAD_AUTHENTICATION_SET", 93: "KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS", + # RFC8636 + 100: "KDC_ERR_NO_ACCEPTABLE_KDF", }, explicit_tag=0xA6, ), @@ -2714,21 +2856,25 @@ def select(sockets, remain=None): class KerberosClient(Automaton): """ + Implementation of a Kerberos client. + + Prefer to use the ``krb_as_req`` and ``krb_tgs_req`` functions which + wrap this client. + + Common parameters: + :param mode: the mode to use for the client (default: AS_REQ). :param ip: the IP of the DC (default: discovered by dclocator) :param upn: the UPN of the client. :param password: the password of the client. :param key: the Key of the client (instead of the password) :param realm: the realm of the domain. (default: from the UPN) - :param spn: the SPN to request in a TGS-REQ - :param ticket: the existing ticket to use in a TGS-REQ :param host: the name of the host doing the request - :param renew: sets the Renew flag in a TGS-REQ - :param additional_tickets: in U2U or S4U2Proxy, the additional tickets - :param u2u: sets the U2U flag - :param for_user: the UPN of another user in TGS-REQ, to do a S4U2Self - :param s4u2proxy: sets the S4U2Proxy flag - :param dmsa: sets the 'unconditional delegation' mode for DMSA TGT retrieval + :param port: the Kerberos port (default 88) + :param timeout: timeout of each request (default 5) + + Advanced common parameters: + :param kdc_proxy: specify a KDC proxy url :param kdc_proxy_no_check_certificate: do not check the KDC proxy certificate :param fast: use FAST armoring @@ -2736,8 +2882,24 @@ class KerberosClient(Automaton): :param armor_ticket_upn: the UPN of the client of the armoring ticket :param armor_ticket_skey: the session Key object of the armoring ticket :param etypes: specify the list of encryption types to support - :param port: the Kerberos port (default 88) - :param timeout: timeout of each request (default 5) + + AS-REQ only: + + :param x509: a X509 certificate to use for PKINIT AS_REQ or S4U2Proxy + :param x509key: the private key of the X509 certificate (in an AS_REQ) + :param p12: (optional) use a pfx/p12 instead of x509 and x509key. In this case, + 'password' is the password of the p12. + + TGS-REQ only: + + :param spn: the SPN to request in a TGS-REQ + :param ticket: the existing ticket to use in a TGS-REQ + :param renew: sets the Renew flag in a TGS-REQ + :param additional_tickets: in U2U or S4U2Proxy, the additional tickets + :param u2u: sets the U2U flag + :param for_user: the UPN of another user in TGS-REQ, to do a S4U2Self + :param s4u2proxy: sets the S4U2Proxy flag + :param dmsa: sets the 'unconditional delegation' mode for DMSA TGT retrieval """ RES_AS_MODE = namedtuple("AS_Result", ["asrep", "sessionkey", "kdcrep"]) @@ -2756,6 +2918,9 @@ def __init__( password=None, key=None, realm=None, + x509=None, + x509key=None, + p12=None, spn=None, ticket=None, host=None, @@ -2796,9 +2961,31 @@ def __init__( else: raise ValueError("Invalid realm") + # PKINIT checks + if p12 is not None: + from cryptography.hazmat.primitives.serialization import pkcs12 + + # password should be None or bytes + if isinstance(password, str): + password = password.encode() + + # Read p12/pfx + with open(p12, "rb") as fd: + x509key, x509, _ = pkcs12.load_key_and_certificates( + fd.read(), + password=password, + ) + x509 = Cert(cryptography_obj=x509) + x509key = PrivKey(cryptography_obj=x509key) + elif x509 and x509key: + x509 = Cert(x509) + x509key = PrivKey(x509key) + if mode in [self.MODE.AS_REQ, self.MODE.GET_SALT]: if not host: raise ValueError("Invalid host") + if (x509 is None) ^ (x509key is None): + raise ValueError("Must provide both 'x509' and 'x509key' !") elif mode == self.MODE.TGS_REQ: if not ticket: raise ValueError("Invalid ticket") @@ -2815,6 +3002,7 @@ def __init__( debug=kwargs.get("debug", 0), ).ip + # Armoring checks if fast: if mode == self.MODE.AS_REQ: # Requires an external ticket @@ -2867,6 +3055,8 @@ def __init__( self.spn = spn self.upn = upn self.realm = realm.upper() + self.x509 = x509 + self.x509key = x509key self.ticket = ticket self.fast = fast self.armor_ticket = armor_ticket @@ -2902,6 +3092,10 @@ def __init__( ) def _connect(self): + """ + Internal function to bind a socket to the DC. + This also takes care of an eventual KDC proxy. + """ if self.kdc_proxy: # If we are using a KDC Proxy, wrap the socket with the KdcProxySocket, # that takes our messages and transport them over HTTP. @@ -2918,9 +3112,15 @@ def _connect(self): return sock def send(self, pkt): + """ + Sends a wrapped Kerberos packet + """ super(KerberosClient, self).send(KerberosTCPHeader() / pkt) def _base_kdc_req(self, now_time): + """ + Return the KRB_KDC_REQ_BODY used in both AS-REQ and TGS-REQ + """ kdcreq = KRB_KDC_REQ_BODY( etype=[ASN1_INTEGER(x) for x in self.etypes], additionalTickets=None, @@ -3112,33 +3312,44 @@ def as_req(self): # Pre-auth is requested if self.pre_auth: - if self.fast: - # Special FAST factor - # RFC6113 sect 5.4.6 - from scapy.libs.rfc3961 import KRB_FX_CF2 - - # Calculate the 'challenge key' - ts_key = KRB_FX_CF2( - self.fast_armorkey, - self.key, - b"clientchallengearmor", - b"challengelongterm", - ) + if self.x509: + # Special PKINIT (RFC4556) factor pafactor = PADATA( - padataType=138, # PA-ENCRYPTED-CHALLENGE - padataValue=EncryptedData(), + padataType=16, padataValue=PA_PK_AS_REQ() # PA-PK-AS-REQ ) + raise NotImplementedError("PKINIT isn't implemented yet !") else: - # Usual 'timestamp' factor - ts_key = self.key - pafactor = PADATA( - padataType=2, # PA-ENC-TIMESTAMP - padataValue=EncryptedData(), + # Key-based factor + + if self.fast: + # Special FAST factor + # RFC6113 sect 5.4.6 + from scapy.libs.rfc3961 import KRB_FX_CF2 + + # Calculate the 'challenge key' + ts_key = KRB_FX_CF2( + self.fast_armorkey, + self.key, + b"clientchallengearmor", + b"challengelongterm", + ) + pafactor = PADATA( + padataType=138, # PA-ENCRYPTED-CHALLENGE + padataValue=EncryptedData(), + ) + else: + # Usual 'timestamp' factor + ts_key = self.key + pafactor = PADATA( + padataType=2, # PA-ENC-TIMESTAMP + padataValue=EncryptedData(), + ) + pafactor.padataValue.encrypt( + ts_key, + PA_ENC_TS_ENC(patimestamp=ASN1_GENERALIZED_TIME(now_time)), ) - pafactor.padataValue.encrypt( - ts_key, - PA_ENC_TS_ENC(patimestamp=ASN1_GENERALIZED_TIME(now_time)), - ) + + # Insert Pre-Authentication data padata.insert( 0, pafactor, @@ -3664,7 +3875,17 @@ def _spn_are_equal(spn1, spn2): def krb_as_req( - upn, spn=None, ip=None, key=None, password=None, realm=None, host="WIN10", **kwargs + upn, + spn=None, + ip=None, + key=None, + password=None, + realm=None, + host="WIN10", + p12=None, + x509=None, + x509key=None, + **kwargs, ): r""" Kerberos AS-Req @@ -3677,6 +3898,10 @@ def krb_as_req( _kerberos._tcp.dc._msdcs.domain.local). :param key: (optional) pass the Key object. :param password: (optional) otherwise, pass the user's password + :param x509: (optional) pass a x509 certificate for PKINIT. + :param x509key: (optional) pass the key of the x509 certificate for PKINIT. + :param p12: (optional) use a pfx/p12 instead of x509 and x509key. In this case, + 'password' is the password of the p12. :param realm: (optional) the realm to use. Otherwise use the one from UPN. :param host: (optional) the host performing the AS-Req. WIN10 by default. @@ -3684,19 +3909,23 @@ def krb_as_req( Example:: - >>> # The KDC is on 192.168.122.17, we ask a TGT for user1 - >>> krb_as_req("user1@DOMAIN.LOCAL", "192.168.122.17", password="Password1") + >>> # The KDC is found via DC Locator, we ask a TGT for user1 + >>> krb_as_req("user1@DOMAIN.LOCAL", password="Password1") Equivalent:: >>> from scapy.libs.rfc3961 import Key, EncryptionType >>> key = Key(EncryptionType.AES256_CTS_HMAC_SHA1_96, key=hex_bytes("6d0748c546 ...: f4e99205e78f8da7681d4ec5520ae4815543720c2a647c1ae814c9")) - >>> krb_as_req("user1@DOMAIN.LOCAL", "192.168.122.17", key=key) + >>> krb_as_req("user1@DOMAIN.LOCAL", ip="192.168.122.17", key=key) + + Example using PKINIT with a p12:: + + >>> krb_as_req("user1@DOMAIN.LOCAL", p12="./store.p12", password="password") """ if realm is None: _, realm = _parse_upn(upn) - if key is None: + if key is None and p12 is None and x509 is None: if password is None: try: from prompt_toolkit import prompt @@ -3713,6 +3942,9 @@ def krb_as_req( upn=upn, password=password, key=key, + p12=p12, + x509=x509, + x509key=x509key, **kwargs, ) cli.run() diff --git a/scapy/layers/tls/cert.py b/scapy/layers/tls/cert.py index 7a491ef61ee..b38f52ca073 100644 --- a/scapy/layers/tls/cert.py +++ b/scapy/layers/tls/cert.py @@ -451,7 +451,7 @@ class _PrivKeyFactory(_PKIObjMaker): It casts the appropriate class on the fly, then fills in the appropriate attributes with import_from_asn1pkt() submethod. """ - def __call__(cls, key_path=None): + def __call__(cls, key_path=None, cryptography_obj=None): """ key_path may be the path to either: _an RSAPrivateKey_OpenSSL (as generated by openssl); @@ -468,7 +468,19 @@ def __call__(cls, key_path=None): obj.fill_and_store() return obj - obj = _PKIObjMaker.__call__(cls, key_path, _MAX_KEY_SIZE) + # This allows to import cryptography objects directly + if cryptography_obj is not None: + # We (stupidly) need to go through the whole import process because RSA + # does more than just importing the cryptography objects... + obj = _PKIObj("DER", cryptography_obj.private_bytes( + encoding=serialization.Encoding.DER, + format=serialization.PrivateFormat.PKCS8, + encryption_algorithm=serialization.NoEncryption() + )) + else: + # Load from file + obj = _PKIObjMaker.__call__(cls, key_path, _MAX_KEY_SIZE) + try: privkey = RSAPrivateKey_OpenSSL(obj._der) privkey = privkey.privateKey @@ -725,9 +737,16 @@ class _CertMaker(_PKIObjMaker): Metaclass for Cert creation. It is not necessary as it was for the keys, but we reuse the model instead of creating redundant constructors. """ - def __call__(cls, cert_path): - obj = _PKIObjMaker.__call__(cls, cert_path, - _MAX_CERT_SIZE, "CERTIFICATE") + def __call__(cls, cert_path=None, cryptography_obj=None): + # This allows to import cryptography objects directly + if cryptography_obj is not None: + obj = _PKIObj("DER", cryptography_obj.public_bytes( + encoding=serialization.Encoding.DER, + )) + else: + # Load from file + obj = _PKIObjMaker.__call__(cls, cert_path, + _MAX_CERT_SIZE, "CERTIFICATE") obj.__class__ = Cert obj.marker = "CERTIFICATE" try: diff --git a/scapy/layers/x509.py b/scapy/layers/x509.py index 0879aab1144..1f1afe4f9c9 100644 --- a/scapy/layers/x509.py +++ b/scapy/layers/x509.py @@ -2,18 +2,24 @@ # This file is part of Scapy # See https://scapy.net/ for more information # Copyright (C) Philippe Biondi -# Acknowledgment: Maxence Tury +# Acknowledgment: Arnaud Ebalard & Maxence Tury # Cool history about this file: http://natisbad.org/scapy/index.html """ -X.509 certificates. +X.509 certificates and other crypto-related ASN.1 structures """ from scapy.asn1.mib import conf # loads conf.mib -from scapy.asn1.asn1 import ASN1_Codecs, ASN1_OID, \ - ASN1_IA5_STRING, ASN1_NULL, ASN1_PRINTABLE_STRING, \ - ASN1_UTC_TIME, ASN1_UTF8_STRING +from scapy.asn1.asn1 import ( + ASN1_Codecs, + ASN1_IA5_STRING, + ASN1_NULL, + ASN1_OID, + ASN1_PRINTABLE_STRING, + ASN1_UTC_TIME, + ASN1_UTF8_STRING, +) from scapy.asn1packet import ASN1_Packet from scapy.asn1fields import ( ASN1F_BIT_STRING_ENCAPS, @@ -111,6 +117,38 @@ class RSAPrivateKey(ASN1_Packet): ASN1F_SEQUENCE_OF("otherPrimeInfos", None, RSAOtherPrimeInfo))) +#################################### +# Diffie Hellman Packets # +#################################### +# From X9.42 (or RFC3279) + + +class ValidationParms(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_BIT_STRING("seed", ""), + ASN1F_INTEGER("pgenCounter", 0), + ) + + +class DomainParameters(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_INTEGER("p", 0), + ASN1F_INTEGER("g", 0), + ASN1F_INTEGER("q", 0), + ASN1F_optional(ASN1F_INTEGER("j", 0)), + ASN1F_optional( + ASN1F_PACKET("validationParms", None, ValidationParms), + ), + ) + + +class DHPublicKey(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_INTEGER("y", 0) + + #################################### # ECDSA packets # #################################### @@ -810,8 +848,14 @@ class X509_AlgorithmIdentifier(ASN1_Packet): ASN1_root = ASN1F_SEQUENCE( ASN1F_OID("algorithm", "1.2.840.113549.1.1.11"), ASN1F_optional( - ASN1F_CHOICE("parameters", ASN1_NULL(0), - ASN1F_NULL, ECParameters))) + ASN1F_CHOICE( + "parameters", ASN1_NULL(0), + ASN1F_NULL, + ECParameters, + DomainParameters, + ) + ) + ) class ASN1F_X509_SubjectPublicKeyInfo(ASN1F_SEQUENCE): @@ -829,6 +873,10 @@ def __init__(self, **kargs): ECDSAPublicKey(), ECDSAPublicKey), lambda pkt: "ecPublicKey" == pkt.signatureAlgorithm.algorithm.oidname), # noqa: E501 + (ASN1F_BIT_STRING_ENCAPS("subjectPublicKey", + DHPublicKey(), + DHPublicKey), + lambda pkt: "dhpublicnumber" == pkt.signatureAlgorithm.algorithm.oidname), # noqa: E501 (ASN1F_PACKET("subjectPublicKey", EdDSAPublicKey(), EdDSAPublicKey), @@ -1128,6 +1176,171 @@ class X509_CRL(ASN1_Packet): ASN1_root = ASN1F_X509_CRL() +##################### +# CMS packets # +##################### +# based on RFC 3852 + +CMSVersion = ASN1F_INTEGER + +# RFC3852 sect 5.2 + +# Other layers should store the structures that can be encapsulated +# by CMS here, referred by their OIDs. +_CMS_ENCAPSULATED = {} + + +class _EncapsulatedContent_Field(ASN1F_STRING_PacketField): + def m2i(self, pkt, s): + val = super(_EncapsulatedContent_Field, self).m2i(pkt, s) + if not val[0].val: + return val + + # Get encapsulated value from its type + if pkt.eContentType.val in _CMS_ENCAPSULATED: + return ( + _CMS_ENCAPSULATED[pkt.eContentType.val](val[0].val, _underlayer=pkt), + val[1], + ) + + return val + + +class CMS_EncapsulatedContentInfo(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_OID("eContentType", "0"), + ASN1F_optional( + _EncapsulatedContent_Field("eContent", None, + explicit_tag=0xA0), + ) + ) + + +# RFC3852 sect 10.2.1 + +class CMS_RevocationInfoChoice(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_CHOICE( + "crl", None, + ASN1F_PACKET("crl", X509_CRL(), X509_Cert), + # -- TODO: 1 + ) + + +# RFC3852 sect 10.2.2 + +class CMS_CertificateChoices(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_CHOICE( + "certificate", None, + ASN1F_PACKET("certificate", X509_Cert(), X509_Cert), + # -- TODO: 0, 1, 2 + ) + + +# RFC3852 sect 10.2.4 + +class CMS_IssuerAndSerialNumber(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_PACKET("issuer", X509_DirectoryName(), X509_DirectoryName), + ASN1F_INTEGER("serialNumber", 0) + ) + + +# RFC3852 sect 5.3 + + +class CMS_Attribute(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_OID("attrType", "0"), + ASN1F_SET_OF("attrValues", [], ASN1F_field("attr", None)) + ) + + +class CMS_SignerInfo(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + CMSVersion("version", 1), + ASN1F_PACKET("sid", CMS_IssuerAndSerialNumber(), CMS_IssuerAndSerialNumber), + ASN1F_PACKET("digestAlgorithm", X509_AlgorithmIdentifier(), + X509_AlgorithmIdentifier), + ASN1F_optional( + ASN1F_SET_OF( + "signedAttrs", + None, + CMS_Attribute, + implicit_tag=0xA0, + ) + ), + ASN1F_PACKET("signatureAlgorithm", X509_AlgorithmIdentifier(), + X509_AlgorithmIdentifier), + ASN1F_STRING("signature", ASN1_UTF8_STRING("")), + ASN1F_optional( + ASN1F_SET_OF( + "unsignedAttrs", + None, + CMS_Attribute, + implicit_tag=0xA1, + ) + ) + ) + + +# RFC3852 sect 5.1 + +class CMS_SignedData(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + CMSVersion("version", 1), + ASN1F_SET_OF("digestAlgorithms", [], X509_AlgorithmIdentifier), + ASN1F_PACKET("encapContentInfo", CMS_EncapsulatedContentInfo(), + CMS_EncapsulatedContentInfo), + ASN1F_optional( + ASN1F_SET_OF( + "certificates", + None, + CMS_CertificateChoices, + implicit_tag=0xA0, + ) + ), + ASN1F_optional( + ASN1F_SET_OF( + "crls", + None, + CMS_RevocationInfoChoice, + implicit_tag=0xA1, + ) + ), + ASN1F_SET_OF( + "signerInfos", + [], + CMS_SignerInfo, + ), + ) + +# RFC3852 sect 3 + + +class CMS_ContentInfo(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_OID("contentType", "1.2.840.113549.1.7.2"), + MultipleTypeField( + [ + ( + ASN1F_PACKET("content", None, CMS_SignedData, + explicit_tag=0xA0), + lambda pkt: pkt.contentType.oidname == "id-signedData" + ) + ], + ASN1F_BIT_STRING("content", "", explicit_tag=0xA0) + ) + ) + + ############################# # OCSP Status packets # ############################# diff --git a/test/scapy/layers/kerberos.uts b/test/scapy/layers/kerberos.uts index eb94aaef16b..7d95584c9e1 100644 --- a/test/scapy/layers/kerberos.uts +++ b/test/scapy/layers/kerberos.uts @@ -186,6 +186,58 @@ assert krbfastreq.reqBody.addresses[0].address == b'SRV ' data = bytes(pkt.root.reqBody) fastreq.armoredData.reqChecksum.verify(armorkey, data) += PKINIT - Parse AS-REQ with CMS structures (MIT Kerberos) + +pkt = Kerberos(bytes.fromhex('6a820df230820deea103020105a20302010aa3820d4b30820d4730820d2ba103020110a2820d2204820d1e30820d1a80820c4b30820c4706092a864886f70d010702a0820c3830820c34020103310f300d060960864801650304020105003082041c06072b060105020301a082040f0482040b30820407a0733071a00502030a8eb7a111180f32303235303932313130343332385aa20602045ba497a5a316041467a8b2f1aded7272d4840000331ffbbfc942a304a5353033a02204205aeb03e889e99fcd6c205ef484b9dd7b462b9e94c3fe68b115a71cd287fcd775a10d300b0609608648016503040201a182032a308203263082021906072a8648ce3e02013082020c0282010100ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aacaa68ffffffffffffffff020102028201007fffffffffffffffe487ed5110b4611a62633145c06e0e68948127044533e63a0105df531d89cd9128a5043cc71a026ef7ca8cd9e69d218d98158536f92f8a1ba7f09ab6b6a8e122f242dabb312f3f637a262174d31bf6b585ffae5b7a035bf6f71c35fdad44cfd2d74f9208be258ff324943328f6722d9ee1003e5c50b1df82cc6d241b0e2ae9cd348b1fd47e9267afc1b2ae91ee51d6cb0e3179ab1042a95dcf6a9483b84b4b36b3861aa7255e4c0278ba3604650c10be19482f23171b671df1cf3b960c074301cd93c1d17603d147dae2aef837a62964ef15e5fb4aac0b8c1ccaa4be754ab5728ae9130c4c7d02880ab9472d455655347fffffffffffffff0382010500028201007b93ec38a6d3a2e5ea4776f7c942c54f06c334ea637cf45e59c21f6638f6b5baa23420d3229c4a418579db1ce3b956d12ec1bce6883621720f2e596a65dd05881745e7524c88447a5e7a45e149e09f163093088716808e6520a471b53631262a19dc4b3b896717ddca77e15c2d8cf31aa1c03a604834e5f852dc4ac86518f53de4d16101c7f26253973987e1f8c6e8298159ff039646052afe14d634891f57abe5787cb023481aceb65c6ee92b123dfd2ddd15f7dcd733be535d063c4d42a309cb7b84163f8924f88c1b3e400b7f78556ba27d0456b739fe261286cffe7ae404379bc2157bf49fc610e4d46339e0e0a380f8e3b818b0bd4f7a038644f12c77bfa2343032300a06082a8648ce3d040304300a06082a8648ce3d040302300b06092a864886f70d01010d300b06092a864886f70d01010ba42c302a300ca00a06082b06010502030602300ca00a06082b06010502030601300ca00a06082b06010502030603a08206243082062030820508a00302010202131b000000028b4c5c90b3392fca000000000002300d06092a864886f70d01010b0500304731153013060a0992268993f22c64011916054c4f43414c31163014060a0992268993f22c6401191606444f4d41494e311630140603550403130d444f4d41494e2d4443312d4341301e170d3235303932303232313135385a170d3236303932303232313135385a305731153013060a0992268993f22c64011916054c4f43414c31163014060a0992268993f22c6401191606444f4d41494e310e300c060355040313055573657273311630140603550403130d41646d696e6973747261746f7230820122300d06092a864886f70d01010105000382010f003082010a02820101009edc4865105bdbe4843dcb43a1ed273630d4bb84e2c6096cb8ef4d111da3dfc8ad78ff7a02a6ea6da16f2ecd0a7e4a85c7b685b02286298493834f8361a318864bea2f2faa92a3236cd1e373eb2874ff8e09468762de9af0a0881ea098fbeadccb9573e53c90da8398a9992e6e6a46081e23c31527453f9540ab4bca93d7b139a97c3a0392d8c035832005cc1ae2fdbfe098381e62b37cd6b94ea638fd06d2e2dfb4c1c35896d717188fa8c472a42aaf65c04ff1f2a55dbb0b02dcec1f9e07d7dd930ddec43947cf229324bfa5189bfc5a34a59864c95fa2351b506979cf1bc3529a7933be0f2004932490d1a250735bd692af367f5ca326d392c28c99bde1210203010001a38202f3308202ef301706092b0601040182371402040a1e08005500730065007230290603551d2504223020060a2b0601040182370a030406082b0601050507030406082b06010505070302300e0603551d0f0101ff0404030205a0304406092a864886f70d01090f04373035300e06082a864886f70d030202020080300e06082a864886f70d030402020080300706052b0e030207300a06082a864886f70d0307301d0603551d0e041604140a63d8a405fe59c3f3abbef3111f6f6a6a08a973301f0603551d23041830168014ab14d5ae948281f079726970b3b8f97003aa760c3081c80603551d1f0481c03081bd3081baa081b7a081b48681b16c6461703a2f2f2f434e3d444f4d41494e2d4443312d43412c434e3d4443312c434e3d4344502c434e3d5075626c69632532304b657925323053657276696365732c434e3d53657276696365732c434e3d436f6e66696775726174696f6e2c44433d444f4d41494e2c44433d4c4f43414c3f63657274696669636174655265766f636174696f6e4c6973743f626173653f6f626a656374436c6173733d63524c446973747269627574696f6e506f696e743081c006082b060105050701010481b33081b03081ad06082b060105050730028681a06c6461703a2f2f2f434e3d444f4d41494e2d4443312d43412c434e3d4149412c434e3d5075626c69632532304b657925323053657276696365732c434e3d53657276696365732c434e3d436f6e66696775726174696f6e2c44433d444f4d41494e2c44433d4c4f43414c3f634143657274696669636174653f626173653f6f626a656374436c6173733d63657274696669636174696f6e417574686f7269747930350603551d11042e302ca02a060a2b060104018237140203a01c0c1a41646d696e6973747261746f7240444f4d41494e2e4c4f43414c304e06092b06010401823719020441303fa03d060a2b060104018237190201a02f042d532d312d352d32312d313332323235373836362d343033353133333636322d313134303736393232322d353030300d06092a864886f70d01010b050003820101005b76869c48c9e4f28043253b8552a6017dc25f9dc990da86a79210f334c1a7e50b6125ab176bc7bb194b96a02736c9838117071d533e99467bf24219228bb40b6d410c8fb23f129010b68777acb83944842a0af694673206be22c0a0078ee0543962b31bae8d809ef553dbe858cd063a7a06f1ea7d026394ace39f294ad5d8c1b077e58e7d17f86eea918aa88ac09cf55ffcf147aa14a4c64f4216211e45fd8794b2906a29b97bcbd47a0b213768f5403f9aa08fd23ea92664fb9a0246ae75e34f939102fad7c48b8c5bb650203aa48b48bed4635bff4e3386e694d57a4e7e65939c5a5a72997176b5d0e50bd369e78bbf0cda53db204fbf37839223daff3a06318201d4308201d0020101305e304731153013060a0992268993f22c64011916054c4f43414c31163014060a0992268993f22c6401191606444f4d41494e311630140603550403130d444f4d41494e2d4443312d434102131b000000028b4c5c90b3392fca000000000002300d06096086480165030402010500a049301606092a864886f70d010903310906072b060105020301302f06092a864886f70d010904312204200e44063cba7907120ced545618cd365edc5071fdc806e8fdb990a7c858d37ef9300d06092a864886f70d01010b0500048201008c8e52430905bb06e897cb5eda4a466ebc6bf980a997d662b9a6f94b88173bab6e8b76b375454c7e06f2091f1ef43165e378263290a1dae9243f58a0e234ed0a082364afe9529b8e5ffee1df77f67a448f6461fac44562ca919381146d5c73e5e643ef8936765cb45661dcf4cf8b7652eee81712037ab7f007046e62ee98ea5f9d3acf426462591e9726f8a50677d935ebaf2f1fbc046033b6cb601c67d1bfe0b4485ab99fb1862500e861a114a03f1b693dd674a28516a240698c516bf94f09dde7ef80772e5098083bf3916ced80118d8f9f0bc737ec15c3d65cfb85e0d186ab11e9c7ab9383ee8fb4a2b7681c6c97edc8fcd48b7bb2dac49c52d70fab5ec1a181c83081c53081c28049304731153013060a0992268993f22c64011916054c4f43414c31163014060a0992268993f22c6401191606444f4d41494e311630140603550403130d444f4d41494e2d4443312d4341815d305b304731153013060a0992268993f22c64011916054c4f43414c31163014060a0992268993f22c6401191606444f4d41494e311630140603550403130d444f4d41494e2d4443312d434102106b671318bb858b8e437e4229b0d32f1282160414ab14d5ae948281f079726970b3b8f97003aa760c300aa10402020096a2020400300aa10402020095a2020400a4819230818fa00703050050000010a11a3018a003020101a111300f1b0d41646d696e6973747261746f72a20e1b0c646f6d61696e2e6c6f63616ca321301fa003020102a11830161b066b72627467741b0c646f6d61696e2e6c6f63616ca511180f32303235303932323130343332325aa70602045ba497a5a81a301802011202011102011402011302011002011702011902011a')) +assert isinstance(pkt.root.padata[0].padataValue, PA_PK_AS_REQ) + +pk_preauth = pkt.root.padata[0].padataValue +assert len(pk_preauth.trustedCertifiers) == 1 +assert pk_preauth.trustedCertifiers[0].subjectName.directoryName[0].rdn[0].type.oidname == "dc" +assert pk_preauth.trustedCertifiers[0].subjectName.directoryName[0].rdn[0].value.val == b"LOCAL" +assert pk_preauth.trustedCertifiers[0].subjectName.directoryName[1].rdn[0].type.oidname == "dc" +assert pk_preauth.trustedCertifiers[0].subjectName.directoryName[1].rdn[0].value.val == b"DOMAIN" +assert pk_preauth.trustedCertifiers[0].subjectName.directoryName[2].rdn[0].type.oidname == "commonName" +assert pk_preauth.trustedCertifiers[0].subjectName.directoryName[2].rdn[0].value.val == b"DOMAIN-DC1-CA" +assert pk_preauth.trustedCertifiers[0].issuerAndSerialNumber.serialNumber.val == 142762589450708598374370602088381230866 + +authpack = pk_preauth.signedAuthpack.content.encapContentInfo.eContent +assert [x.algorithm.oidname for x in authpack.supportedCMSTypes] == [ + 'ecdsa-with-SHA512', + 'ecdsa-with-SHA256', + 'sha512WithRSAEncryption', + 'sha256WithRSAEncryption', +] +assert [x.kdfId.oidname for x in authpack.supportedKDFs] == ['id-pkinit-kdf-sha256', 'id-pkinit-kdf-sha1', 'id-pkinit-kdf-sha512'] +assert authpack.pkAuthenticator.nonce == 0x5ba497a5 +assert authpack.pkAuthenticator.freshnessToken is None +assert authpack.pkAuthenticator.paChecksum2.checksum.val.hex() == "5aeb03e889e99fcd6c205ef484b9dd7b462b9e94c3fe68b115a71cd287fcd775" +assert authpack.pkAuthenticator.paChecksum2.algorithmIdentifier.algorithm.oidname == "sha256" + += PKINIT - Parse AS-REP with CMS structures (MIT Kerberos) + +from scapy.layers.tls.cert import Cert + +pkt = Kerberos(bytes.fromhex('6b82109730821093a003020105a10302010ba2820987308209833082097fa103020111a282097604820972a082096e3082096a808209663082096206092a864886f70d010702a08209533082094f020103310f300d060960864801650304020105003082012b06072b060105020302a082011e0482011a30820116a082010a03820106000282010100ffb1e474ea4bb6c9248cec29ddf54feac8bf6a3261fd25dfc32e258e0056fb2caf4fb76f90961d706b98c0b16fedadf049aa2c3dda6e5eb42933828b932b8dd10f2e00caa1eb2901df080805fbe8d00cae67e9e35e9c197c362416d09fbfa5ef10e556b7993c7501566156dd431e5ae35eb9d00b86ec529b1af887b7671de382ddf4ec2ce87d71fe1ab3fa6d0338bb9c9d2794feba33356b149bc3d1745f4f2feca0ae97f62aaf3314fa1464c844fc016dd82e3008e2cd3cc762d0cc264981497342820f8c8f4aef29147346aea727cc24c3e64f474a5a2448325123d8d217fb65eaabbb7aab36db0e905e5df46de3686bc94581580924f0226385d2db6c599ca10602044e744899a08206303082062c30820514a00302010202131b00000003b9cb9e577efbe605000000000003300d06092a864886f70d01010b0500304731153013060a0992268993f22c64011916054c4f43414c31163014060a0992268993f22c6401191606444f4d41494e311630140603550403130d444f4d41494e2d4443312d4341301e170d3235303932303232313232395a170d3236303932303232313232395a301b31193017060355040313104443312e444f4d41494e2e4c4f43414c30820122300d06092a864886f70d01010105000382010f003082010a0282010100e6832a3e3ca595057e9f70733d34ea5153e4769dc95eb98d56d7b28e8c0390cdd7bfecf01b5f12931afe8d0a1c2e69b83466b3f8ef88c4b31f2c0a49bcee9fb7b78a7e71c6c69c260e606b96d9d2ba534430c6b5cd3be7ef98110e92a0175b66b0b501d32a39dc17f30033fd0c8fa508e5c781c2d130bc8dfd7cb3a8982bd65c16a15f175e7205337dd17b6f4358644db4e6ad3a0f83a2c605275ef0cf4ca2cf974386283d141f4fb0b1f6d72720b83e4155bd0ac39f6ca7723ca317ae6340f746b4c82195addce715e31928ee0e67cb357d3200ee0b26ee422008c8c3de5c1a5acae88e10c89edff4ccd8543f6eaa551c15ed5d8e756567e39c5d56edb948fd0203010001a382033b30820337302f06092b060104018237140204221e200044006f006d00610069006e0043006f006e00740072006f006c006c00650072301d0603551d250416301406082b0601050507030206082b06010505070301300e0603551d0f0101ff0404030205a0307806092a864886f70d01090f046b3069300e06082a864886f70d030202020080300e06082a864886f70d030402020080300b060960864801650304012a300b060960864801650304012d300b0609608648016503040102300b0609608648016503040105300706052b0e030207300a06082a864886f70d0307301d0603551d0e041604148994b7358e085091a011cd226c9305cdcb6b82a2301f0603551d23041830168014ab14d5ae948281f079726970b3b8f97003aa760c3081c80603551d1f0481c03081bd3081baa081b7a081b48681b16c6461703a2f2f2f434e3d444f4d41494e2d4443312d43412c434e3d4443312c434e3d4344502c434e3d5075626c69632532304b657925323053657276696365732c434e3d53657276696365732c434e3d436f6e66696775726174696f6e2c44433d444f4d41494e2c44433d4c4f43414c3f63657274696669636174655265766f636174696f6e4c6973743f626173653f6f626a656374436c6173733d63524c446973747269627574696f6e506f696e743081c006082b060105050701010481b33081b03081ad06082b060105050730028681a06c6461703a2f2f2f434e3d444f4d41494e2d4443312d43412c434e3d4149412c434e3d5075626c69632532304b657925323053657276696365732c434e3d53657276696365732c434e3d436f6e66696775726174696f6e2c44433d444f4d41494e2c44433d4c4f43414c3f634143657274696669636174653f626173653f6f626a656374436c6173733d63657274696669636174696f6e417574686f72697479303c0603551d1104353033a01f06092b0601040182371901a01204101d9d5575a78e1740b7be50767138da8c82104443312e444f4d41494e2e4c4f43414c304f06092b060104018237190204423040a03e060a2b060104018237190201a030042e532d312d352d32312d313332323235373836362d343033353133333636322d313134303736393232322d31303030300d06092a864886f70d01010b05000382010100205571d8ddc2bbb8cfd56b0fbb8d8b6e38ce376c76135f51f25c3f3a98094d59fee193d678b1ff310effa092985394e84ff033094c1889309e29146d239178e2171e192a7c3ae0ce6c653790f9bef3f3281a238c264c5a944e13fa3e97b7ee21e0c22a74b8ab81f4d0d7dc9a592f55efad413ab5041b123f622537e13733eeda845541e5ff8c9973dc5b482701d579f53c67a5ac3fed6c37b1501154d17661f70a252211e9e320269ab7e468bf3d1f1d65f106818122d05d4e2d4db03f1670f66fd9e711970886c7dae937184256023782771d579795d1c331ecd737d0e9d7bb1b4ca24606302bc9c7c10d8aebcfc8a4a2d6beb3fbd3abf14c2680f665f04e35318201d4308201d0020101305e304731153013060a0992268993f22c64011916054c4f43414c31163014060a0992268993f22c6401191606444f4d41494e311630140603550403130d444f4d41494e2d4443312d434102131b00000003b9cb9e577efbe605000000000003300d06096086480165030402010500a049301606092a864886f70d010903310906072b060105020302302f06092a864886f70d010904312204200916c67ea99156a2738927fc51c6ebee43cdb65d715406d1fb6d40daf49c65ca300d06092a864886f70d0101010500048201007fa8498cf70e6f0f9763eaba1f050dda9ca79d343e93312319a457f157586ea849584da69ae8a3ffe26171a9a8cbd3a4b39fb7c8959ebadf42a69c4c626abcd59aac719042b2b9c90ea81bb7593618641d2b498cd6bd65322ed3dcde8895a68b0889c804ce8526cfee27d664a3cd0cc9f1a74531d029cafe4de15bb14bb4d36659fe276f126cccf421c91db7d5be02fb8185cd0de03bee08f424fc48cb4c3f4294f3225752c09abc33ca358b43b5cf3b7df109e37051f757e08a3caaad1d77d9f310a9bd8ea263a00431b57bf4b37c3b0f998a47209a406531c8fa3ff0fd4aec04e3574b2485bc6ac01d077064b67846a71600b65ff6d417441e034c7bd080eca30e1b0c444f4d41494e2e4c4f43414ca41a3018a003020101a111300f1b0d41646d696e6973747261746f72a58205806182057c30820578a003020105a10e1b0c444f4d41494e2e4c4f43414ca221301fa003020102a11830161b066b72627467741b0c646f6d61696e2e6c6f63616ca382053c30820538a003020112a103020102a282052a04820526690c97f510509c672dac4e1436da9aeb5ac4fde72b75b5c1fcfab03aef11139b30b9d32b62f9c4de8e97bc5148563c5bc5fb031e1b1869c69c2991778190d7f27eeeac2ba5e59b54b1b10af66e526fced04f1dd7edd81da93984962183a50e39f82d6f90c9cc9441fec556432ec776a4b595c459cdcfe45489d360f6c950185af170a24897a4eb1127f9c85772fe0417733b254604cd704a15993b77ac18fb1fd8fddb9e888f8c05ffd4c7a5e519593c9e7588c92345ca6ca2e04f0c83231bcc90adccb189e98c2afd53bdb8e665f91d5c3aafde51c60e9b42e88de76261060090483a8dc2d129b66cc3890524004295b5ba440c0a00b352ce91616df2c9a0153e5fd072a9a356dba5e44d79c032afc4d985a180d8fb1f9bba46be602a73ba7c4098683d6ffac4e456b0e51e9473f8ff40e50b437d370b087e1d41089d9f382a17e212d13244f95ad1fb629769c5d53b2ade80c6690fa845efb590a2c6e81851ea9ca1ba319c3a8f86bc62bbcbabf3ecc39d3f6988157a4c390ada2f42b7c577438bcfdb4136bbff92c3c32eb22213e14c51de330f4df4d493bcaa322a3eea01fe504bd03c18786ed385ca205af4396eb6c7b1cfa0e13bcf3e00452461b5c1f9761ef5edb35cfa79fdea04a5420b9762d6f2cf74d694b35c812ba62620c4e6e90ee6483768e38fa0011706d2c093a22202707c5c90cf3ea4c4f17c017f9d7e85a7cc555bf9c9bd4c1337282b5de0395d123ca25c2a9c9eca5cdc31dfd54db75f43eadadd7c7e3a3611a6c1a806c7ff5b0d0b102155978c745a9b4a022018009641ad9197492de70dee4248d159a2b2c5d6adbf253ac04dbe5713cf2878ef440aa68989b2655687a7b35f6a547a8c5a076004c58baa1b231bec7501f5f5bb9f1c66c8cc22d35641cd4442244f349d0351263bb2f1e11b4f4ec26044c87f93a1a963649f5be7a8d61306fe47a10427ac14ba6b9b09ec69950e5176e933cc1fdce258c62ccae4011e8eccab0a36b9ac1d21d36df38c32d65f438d25defa0eb5c577f5f2458304679a9934796be00d3335b7fee1f7616768f0547bd949b764ed2b4684951b35b57a7168fe79d8cd7580dfecddbc30afb8d47032f12cc5b2ee1c16a731dd977f2476989f465fdf6e08992ba566264d1e0a8f0f7274533293e2aa1c418397dc89f9f48d5d9dc3cd82548327be0ebc9b3edeb00f6cf0df8b339d10daae5bb02e9572881fbc5246d5db408fd9cf16209a4ef6b2fc6765d9d9092054b362494be360847b12927ea2fd73b89d345c22fe662f2096952edb69983f147eee5635f40c0bd7bca09b61f644a9df3ecccd0fd0d9c245b4fb224e415bfd58637d341214bc8b2e962df1e7845da642ee4b7a5343c8cee746f6da89cbe3c89f278c6d42f9a743d97ad2c767f1514458db99ca5f29175609e3a7a704b21de8c3cee0646eb60dfb5ddf6824008232dcbdf81b76b941c8af5c0788384bf61f694d80a00b9dc28ae8b0ff782d0b7fcefd60114518401534974c59b88ca89bb4f4a2a5e6e71d7f08342f830338981f534a1affc8ad28b9ec8c54b64321aaafb1d7f049719fda712def001492d6d404bf1da6043687f82378857453b0539a6cd7f452f4b789944a0ca6f238fd321687ac0685a81c9e77f113b7f5c1de3fba74b88f4e0c6cec90e230f16099f9fdb74c57879a98e4a1a85ad672021afc9199fba18c82a7e57c5655ee8d9e8e9cb6d31bc3920d7dbfe667c315b971f99ce2a3579cd1de9d7bd096dc443a1c0dc92e5f7e83657cf38020495585427720ecac4519162cced74d48c294fdb11086e97585d1a9bfaef4af44691f34341fb5e1f42113f82b597bc3e5f5e877116df8a682014a30820146a003020112a282013d048201396d08189c79793463088601b1497f77742a2980900f4c872aa340d07b36c4ff9f9b97740c6f18a15b2277c9c27f1ae7bad8a5899952ca36d3c2d0aa1e6c3137be54a8db29da9d4af03d72f7b9aea0b9f0a099a2421368e875b3cf6fc85454502e74635dd4683b061914c713cb2c551d8a46fdc47bd784c1d2925374cd0f48d4f917ca073563fe570f55f72d64f2de1776bc38e3aa79f0571ad7c64247d80d83fa3bef9f53dc3454634b78a5f207f01160fdd8a8ff4dbdfe2a2d46ccbf84eaf45299b9379b99a1eec016c143d3dc08dc3d9599e5aa62cdf5dc016fab8deba39d81c4d6c5eea684532bb6697ab61ab88d8ac43c5e36bcadd380b31d19dd8475ee68369ff5d8db5cf7733aafe82d96cc2ab68112216d37c44ddb37b336483d75f0566a713cd508a0c66ab7f13d70541e79e8d2038b42a415416d7d')) +assert isinstance(pkt.root.padata[0].padataValue, PA_PK_AS_REP) + +pk_preauth_resp = pkt.root.padata[0].padataValue +assert isinstance(pk_preauth_resp.rep, DHRepInfo) + +dhrep = pk_preauth_resp.rep +assert dhrep.kdf is None +assert dhrep.serverDHNonce is None + +dhkeyinfo = dhrep.dhSignedData.content.encapContentInfo.eContent +assert dhkeyinfo.subjectPublicKey.y.val == 32278489782659599666680674691617740192025480882925125716566496945858046289374524666228146919540757354337943084659625408278197912527087491522001624804516413386428300641892927787473470630419131055568103619174060490124485923206334065346522123445748745649691028061114330596909397680493778434408463632147264526545631660227144914565541288496092534758943967886391259750733078319727386349536272439561387290863606045665780539098807180454586714490639623651326318384483940150461818440884045020628878002871357420738487965588236164888287449564150835059541717449563619851058161535035543798732468578054040817729345202791857657764252 +assert dhkeyinfo.nonce == 0x4e744899 + +certificates = dhrep.dhSignedData.content.certificates +assert len(certificates) == 1 +cert = Cert(certificates[0].certificate) +assert cert.issuer_str == '/CN=DOMAIN-DC1-CA/dc=DOMAIN' +assert cert.subject_str == '/CN=DC1.DOMAIN.LOCAL' + + Advanced Kerberos tests = Test Kerberos InnerToken wrapping (ancient RFC1964)