IPv6 (Scapy6) [merged upstream]
In 2006, Guillaume Valadon and I started working on IPv6 support for Scapy. This resulted on a parallel IPv6-enabled version of Scapy named Scapy6.
Support for most of the protocols associated with IPv6 (ICMPv6, Neighbor Discovery, MLD, MRD, DHCPv6, MIPv6 ...) was progressively added to the extension.
In August 2008, Phil started merging our work in version 2.0 of Scapy and quickly completed that merge.
As a conclusion, Scapy6 is now deprecated and you can benefit from IPv6 protocol suite support directly in Scapy.
$ hg clone http://hg.secdev.org/scapy destination directory: scapy requesting all changes adding changesets adding manifests adding file changes added 1195 changesets with 1641 changes to 145 files updating working directory 129 files updated, 0 files merged, 0 files removed, 0 files unresolved $ cd scapy/ $ sudo ./run_scapy Welcome to Scapy (2.1.0-dev) >>> traceroute6("www.google.com", maxttl=15) Begin emission: .....*..*..*..*..*....*******.*.***Finished to send 30 packets. **......*.***...*..**....................................................... Received 158 packets, got 10 answers, remaining 5 packets 2a00:1450:8002:0000:0000:0000:0000:0068 :tcpwww 1 2001:7a8:8:8::8 3 2 2001:7a8:0:c951::1 3 3 2001:7a8:1:131::1 3 4 2001:7a8:1:30::2 3 5 2001:860:0:6:0:1:5169:1 3 6 2001:4860:0:1::25 3 7 2a00:1450:8002::68 SA 8 2a00:1450:8002::68 SA 9 2a00:1450:8002::68 SA 10 2a00:1450:8002::68 SA (<Traceroute: TCP:4 UDP:0 ICMP:0 Other:6>, <Unanswered: TCP:5 UDP:0 ICMP:0 Other:0>)
X.509 Cert, CRL and Key [merged upstream]
A while ago (I was still using CVS at that time), I was working on extensions which required support for X.509 Certificates, Keys and CRL. The idea was to be able to import X.509 certificates, CRL and keys as objects in Python scripts (and Scapy obviously) and benefit from useful methods to sign, verify, encrypt, decrypt and do a lot more. I started writing a standalone pure Python module for that purpose: cert.py
You might be wondering why I did not simply reused existing frameworks to do that (python-crypto, M2crypto, pyOpenSSL, ...). They were limited on some aspects and most importantly I wanted to spend time on the protocols (PKCS#1, RFC 3447, RFC 5280 ...) and come with a pure Python implementation of the useful methods in order to be able to modify them at will.
As I did not want to deal with the ASN.1 parsing directly (ASN.1 support was not yet in Scapy and I also did not want the module to depend on Scapy at that time anyway), I decided to implement a temporary (scurvy) hack for X.509 certificates, CRL and keys import: depend on openssl binary and parse the output of its subcommands for that purpose. Import could be improved later without breaking the API provided by the module. The benefit is that you can drop cert.py on a system with OpenSSL installed and start using it directly.
Anyway, if you want to use the module:
- in Scapy: Phil has added cert.py upstream so you can simply import it like any other Scapy internal module (using something like from scapy.crypto.cert import *
- in a standalone project: clone the repository (hg clone http://hg.natisbad.org/cert) to get cert.py and then do a simple import cert in your Python code.
The 3 main classes are Cert, Key and CRL. The code is commented and IMHO easy to read. All main methods have associated docstrings so it is pretty easy to understand what can be done. If you need examples, you can clone the repository (hg clone http://hg.natisbad.org/cert) and take a look at cert.uts file. Don't hesitate to bug me by email or post a message on Scapy Mailing List if you have additional questions.
Here is a small overview of what the module can be used for:
arno@small:/tmp/$ hg clone http://hg.secdev.org/scapy # clone Scapy destination directory: scapy requesting all changes adding changesets adding manifests adding file changes added 1195 changesets with 1641 changes to 145 files updating to branch default 129 files updated, 0 files merged, 0 files removed, 0 files unresolved arno@small:/tmp/scapy$ openssl genrsa 4096 > key.pem # generate a RSA key pair Generating RSA private key, 4096 bit long modulus ....................................................................................++ ..........................................................++ unable to write 'random state' e is 65537 (0x10001) # Generate a self signed cert arno@small:/tmp/scapy$ openssl req -new -x509 -nodes -sha1 -days 365 -key key.pem > cert.pem Country Name (2 letter code) [AU]:FR State or Province Name (full name) [Some-State]:France Locality Name (eg, city) []:Paris Organization Name (eg, company) [Internet Widgits Pty Ltd]:natisbad.org Organizational Unit Name (eg, section) []:PKI Services Unit Common Name (eg, YOUR name) []:Arnaud Ebalard Email Address []:arno@natisbad.org arno@small:/tmp/scapy$ ./run_scapy # launch scapy Welcome to Scapy (2.1.0-dev) >>> from scapy.crypto.cert import * # import cert module >>> c = Cert("cert.pem") # import our self signed cert as c >>> c.show() Serial: 827EA38F7A0E025A Issuer: C=FR, ST=France, L=Paris, ... , CN=Arnaud Ebalard/emailAddress=arno@natisbad.org Subject: C=FR, ST=France, L=Paris, ... , CN=Arnaud Ebalard/emailAddress=arno@natisbad.org Validity: 01/01/10 to 01/01/11 >>> k=Key("key.pem") # import associated key pair as k >>> help(k.sign) # How does .sign() work? Help on method sign in module scapy.crypto.cert: sign(self, M, t=None, h=None, mgf=None, sLen=None) method of scapy.crypto.cert.Key instance Sign message 'M' using 't' signature scheme where 't' can be: - None: the message 'M' is directly applied the RSASP1 signature primitive, as described in PKCS#1 v2.1, i.e. RFC 3447 Sect 5.2.1. Simply put, the message undergo a modular exponentiation using the private key. Additionnal method parameters are just ignored. - 'pkcs': the message 'M' is applied RSASSA-PKCS1-v1_5-SIGN signature scheme as described in Sect. 8.2.1 of RFC 3447. In that context, the hash function name is passed using 'h'. Possible values are "md2", "md4", "md5", "sha1", "tls", "sha224", "sha256", "sha384" and "sha512". If none is provided, sha1 is used. Other additionnal parameters are ignored. - 'pss' : the message 'M' is applied RSASSA-PSS-SIGN signature scheme as described in Sect. 8.1.1. of RFC 3447. In that context, o 'h' parameter provides the name of the hash method to use. Possible values are "md2", "md4", "md5", "sha1", "tls", "sha224", "sha256", "sha384" and "sha512". if none is provided, sha1 is used. o 'mgf' is the mask generation function. By default, mgf is derived from the provided hash function using the generic MGF1 (see pkcs_mgf1() for details). o 'sLen' is the length in octet of the salt. You can overload the default value (the octet length of the hash value for provided algorithm) by providing another one with that parameter. >>> M = "message to be signed" >>> k.sign(M, t="pss") # sign M (pss w/ SHA1) "\xb6[\x820\xff\xf4V\xc1\x130\xd8\x80 ... \xf4rYaq\xb1\xbd\xdc'\xcaZoo\xf4" >>> S=_ >>> c.verify(M, S, t="pss") # verify signature True >>> M = "message to be encrypted" >>> c.encrypt(M, t='oaep') # (public) encrypt M 'r\x08~\x9b\xeb\xcd\x80\xc2\xbb\x0e_V ... \xff\xbf\xa4H%\xffr(\x83\xa5\x80' >>> C=_ >>> k.decrypt(C, t='oaep') # (private) decrypt C 'message to be encrypted' # Overview of Cert methods >>> c. # TAB TAB (i.e. hit tabulation twice for completion) c.__doc__ c.dercert c.output c.__init__ c.encrypt c.pemcert c.__module__ c.exponent c.possible_fields c.__repr__ c.export c.possible_fields_count c.__str__ c.extKeyUsage c.pubKeyAlg c._apply_ossl_cmd c.format c.rawcert c._rsaep c.isIssuerCert c.remainingDays c._rsaes_oaep_encrypt c.isSelfSigned c.serial c._rsaes_pkcs1_v1_5_encrypt c.is_revoked c.show c._rsassa_pkcs1_v1_5_verify c.issuer c.sig c._rsassa_pss_verify c.key c.sigAlg c._rsavp1 c.keyHash c.sigLen c.asn1parsecert c.keyUsage c.subject c.authorityInfoAccess c.modulus c.subjectKeyID c.authorityKeyID c.modulusLen c.tbsCertificate c.authorityKeyID_dirname c.modulus_hexdump c.textcert c.authorityKeyID_keyid c.notAfter c.verify c.authorityKeyID_serial c.notAfter_str c.verifychain c.basicConstraints c.notAfter_str_simple c.verifychain_from_cafile c.basicConstraintsCritical c.notBefore c.verifychain_from_capath c.cRLDistributionPoints c.notBefore_str c.version c.certpath c.notBefore_str_simple c.chain c.osslcmdbase >>> c.isSelfSigned() True >>> c.notAfter (2011, 1, 1, 17, 40, 59, 5, 1, 0) >>> c.notAfter_str 'Jan 1 17:40:59 2011 GMT' >>> c.remainingDays() 364.91947916666669 >>> c.version 3 # Overview of Key methods >>> k. # TAB TAB (i.e. hit tabulation twice for completion) k.__doc__ k._rsassa_pss_sign k.modulusLen k.__init__ k._rsassa_pss_verify k.osslcmdbase k.__module__ k._rsavp1 k.pemkey k.__str__ k.asn1parsekey k.possible_fields k._apply_ossl_cmd k.coefficient k.possible_fields_count k._rsadp k.decrypt k.prime1 k._rsaep k.derkey k.prime2 k._rsaes_oaep_decrypt k.encrypt k.privExp k._rsaes_oaep_encrypt k.exponent1 k.pubExp k._rsaes_pkcs1_v1_5_decrypt k.exponent2 k.rawkey k._rsaes_pkcs1_v1_5_encrypt k.format k.sign k._rsasp1 k.key k.textkey k._rsassa_pkcs1_v1_5_sign k.keypath k.verify k._rsassa_pkcs1_v1_5_verify k.modulus # CRL is left as exercise # for curious reader
One (IMHO) interesting direction that I have currently no time to follow would be to progressively remove the dependency of cert.py on openssl binary in Scapy in order to replace it by the now available internal ASN.1 support. This would allow modifying (e.g. fuzzing) certificates and CRL structure for instance: if you have the time, I bet this is almost guaranteed to allow you to find bugs in various crypto frameworks.
Disclaimer: the module has been developed as a convenience for testing purposes only. Do not rely on it for real security needs (e.g. production apps). You have been warned.
PF_KEY
While performing MIPv6 and IPsec related work under Linux, I often had the need to monitor what was going on at PF_KEY level. Even if ip xfrm monitor or setkey -x are of some help on that aspect, they are also very limited when you are used to tcpdump, wireshark or Scapy. They also do not allow injecting PF_KEY messages.
So, I started adding support for PF_KEY to Scapy (more precisely to Scapy6 because IPv6 support had not been merged upstream at that time). I used RFC 2367, KAME extensions for policy management and Linux kernel code as a basis for that work.
One of the direct advantage of having PF_KEY support in Scapy is that you not only have the ability to monitor but also the ability to interact (i.e. inject PF_KEY traffic).
So, if you have a need, my old mercurial repo is here. If you find the extension useful and you think it would be interesting to have it available upstream in Scapy, then drop me an email and I'll see what I can do to update it for current version of Scapy. At the moment, it fits my needs.
Short example of how you can start playing with it:
arno@small:/tmp$ hg clone http://hg.natisbad.org/scapy6-pfkey destination directory: scapy6-pfkey requesting all changes adding changesets adding manifests adding file changes added 918 changesets with 947 changes to 24 files updating to branch default 18 files updated, 0 files merged, 0 files removed, 0 files unresolved arno@small:/tmp/scapy6-pfkey$ sudo ./scapy6-pfkey.py Welcome to Scapy (1.2.0.2) Scapy6 - PF_KEYv2 add-on (Using PID 3467) >>> l=pfkey_sniff() # Ctrl-C to stop the capture >>> l.show() ... 0044 SADB_X_MIGRATE / SADB_EXT_X_KMADDRESS / SADB_EXT_ADDRESS_SRC / ... / SADB_EXT_X_POLICY ... 0054 SADB_ACQUIRE: ESP 2001:db8:1::1/128 0/any -> 2001:db8:2::2/128 0/any ... ... >>> l[44].show() ###[ PF_KEY SADB_X_MIGRATE message ]### version= 2 type= SADB_X_MIGRATE errno= 0 satype= SADB_SATYPE_ESP len= 40 res= 0 seq= 0 pid= 0 ###[ PF_KEY Key Manager Addresses extension ]### len= 8 type= SADB_EXT_X_KMADDRESS res= 0 \local\ |###[ sockaddr_in6 structure - Linux version ]### | sin6_family= AF_INET6 | sin6_port= 0 | sin6_flowinfo= 0 | sin6_addr= 2001:db8:3::3 | sin6_scope_id= 0 \remote\ |###[ sockaddr_in6 structure - Linux version ]### | sin6_family= AF_INET6 | sin6_port= 0 | sin6_flowinfo= 0 | sin6_addr= 2001:db8:2::1 | sin6_scope_id= 0 ###[ PF_KEY IPv4/IPv6 source address extension ]### len= 5 type= SADB_EXT_ADDRESS_SRC proto= Mobility Header plen= 128 res= 0 \addr\ |###[ sockaddr_in6 structure - Linux version ]### | sin6_family= AF_INET6 | sin6_port= 0 | sin6_flowinfo= 0 | sin6_addr= 2001:db8:2::2 | sin6_scope_id= 0 ###[ PF_KEY IPv4/IPv6 destination address extension ]### len= 5 type= SADB_EXT_ADDRESS_DST proto= Mobility Header plen= 128 res= 0 \addr\ |###[ sockaddr_in6 structure - Linux version ]### | sin6_family= AF_INET6 | sin6_port= 0 | sin6_flowinfo= 0 | sin6_addr= 2001:db8:2::1 | sin6_scope_id= 0 ###[ PF_KEY POLICY extension ]### len= 20 type= SADB_EXT_X_POLICY poltype= IPsec dir= OUT res= 0 id= 0 prio= 0 \reqs\ |###[ IPsec Request (sadb_x_ipsecrequest) ]### | len= 72 | proto= ESP | mode= Transport | level= Require | res1= 0 | id= 0 | res2= 0 | \sockaddr1\ | |###[ sockaddr_in6 structure - Linux version ]### | | sin6_family= AF_INET6 | | sin6_port= 0 | | sin6_flowinfo= 0 | | sin6_addr= :: | | sin6_scope_id= 0 | \sockaddr2\ | |###[ sockaddr_in6 structure - Linux version ]### | | sin6_family= AF_INET6 | | sin6_port= 0 | | sin6_flowinfo= 0 | | sin6_addr= :: | | sin6_scope_id= 0 |###[ IPsec Request (sadb_x_ipsecrequest) ]### | len= 72 | proto= ESP | mode= Transport | level= Require | res1= 0 | id= 0 | res2= 0 | \sockaddr1\ | |###[ sockaddr_in6 structure - Linux version ]### | | sin6_family= AF_INET6 | | sin6_port= 0 | | sin6_flowinfo= 0 | | sin6_addr= 2001:db8:3::3 | | sin6_scope_id= 0 | \sockaddr2\ | |###[ sockaddr_in6 structure - Linux version ]### | | sin6_family= AF_INET6 | | sin6_port= 0 | | sin6_flowinfo= 0 | | sin6_addr= 2001:db8:2::1 | | sin6_scope_id= 0 >>>