| { |
| "cells": [ |
| { |
| "cell_type": "markdown", |
| "metadata": {}, |
| "source": [ |
| "# TLS handshake overview\n", |
| "This is the standard, modern TLS 1.2 handshake:\n", |
| "\n", |
| "<img src=\"images/handshake_tls12.png\" alt=\"Handshake TLS 1.2\" width=\"400\"/>" |
| ] |
| }, |
| { |
| "cell_type": "code", |
| "execution_count": null, |
| "metadata": { |
| "collapsed": true |
| }, |
| "outputs": [], |
| "source": [ |
| "# We're going to parse several successive records from the passive listening of a standard TLS handshake\n", |
| "from scapy.all import *" |
| ] |
| }, |
| { |
| "cell_type": "markdown", |
| "metadata": {}, |
| "source": [ |
| "## (C) ---> (S) ClientHello" |
| ] |
| }, |
| { |
| "cell_type": "code", |
| "execution_count": null, |
| "metadata": { |
| "collapsed": false |
| }, |
| "outputs": [], |
| "source": [ |
| "record1 = TLS(open('raw_data/tls_session_protected/01_cli.raw').read())\n", |
| "record1.show()" |
| ] |
| }, |
| { |
| "cell_type": "code", |
| "execution_count": null, |
| "metadata": { |
| "collapsed": false |
| }, |
| "outputs": [], |
| "source": [ |
| "for extension in record1.msg[0].ext:\n", |
| " print ''\n", |
| " extension.show()" |
| ] |
| }, |
| { |
| "cell_type": "markdown", |
| "metadata": {}, |
| "source": [ |
| "## (C) <--- (S) ServerHello" |
| ] |
| }, |
| { |
| "cell_type": "code", |
| "execution_count": null, |
| "metadata": { |
| "collapsed": false |
| }, |
| "outputs": [], |
| "source": [ |
| "record2 = TLS(open('raw_data/tls_session_protected/02_srv.raw').read())\n", |
| "record2.show()" |
| ] |
| }, |
| { |
| "cell_type": "markdown", |
| "metadata": {}, |
| "source": [ |
| "## (C) <--- (S) Certificate" |
| ] |
| }, |
| { |
| "cell_type": "code", |
| "execution_count": null, |
| "metadata": { |
| "collapsed": false |
| }, |
| "outputs": [], |
| "source": [ |
| "record3 = TLS(open('raw_data/tls_session_protected/03_srv.raw').read())\n", |
| "record3.show()" |
| ] |
| }, |
| { |
| "cell_type": "code", |
| "execution_count": null, |
| "metadata": { |
| "collapsed": false |
| }, |
| "outputs": [], |
| "source": [ |
| "# The Certificate message actually contains a *chain* of certificates\n", |
| "for cert in record3.msg[0].certs:\n", |
| " print type(cert[1])\n", |
| " cert[1].show()\n", |
| " print ''" |
| ] |
| }, |
| { |
| "cell_type": "code", |
| "execution_count": null, |
| "metadata": { |
| "collapsed": false |
| }, |
| "outputs": [], |
| "source": [ |
| "# Let's recall the domain that the client wants to access\n", |
| "record1.msg[0].ext[0].show()\n", |
| "\n", |
| "# Indeed the certificate may be used with other domains than its CN 'www.github.com'\n", |
| "x509c = record3.msg[0].certs[0][1].x509Cert\n", |
| "print type(x509c)\n", |
| "x509c.tbsCertificate.extensions[2].show()" |
| ] |
| }, |
| { |
| "cell_type": "markdown", |
| "metadata": {}, |
| "source": [ |
| "## (C) <--- (S) CertificateStatus, ServerKeyExchange, ServerHelloDone" |
| ] |
| }, |
| { |
| "cell_type": "code", |
| "execution_count": null, |
| "metadata": { |
| "collapsed": false |
| }, |
| "outputs": [], |
| "source": [ |
| "# Here the server sent three TLS records in the same TCP segment\n", |
| "record4 = TLS(open('raw_data/tls_session_protected/04_srv.raw').read())\n", |
| "record4.show()" |
| ] |
| }, |
| { |
| "cell_type": "code", |
| "execution_count": null, |
| "metadata": { |
| "collapsed": false |
| }, |
| "outputs": [], |
| "source": [ |
| "# Let's verify the signature in the ServerKeyExchange\n", |
| "# First, we need to assemble the whole data being signed\n", |
| "cli_random = pkcs_i2osp(record1.msg[0].gmt_unix_time, 4) + record1.msg[0].random_bytes\n", |
| "srv_random = pkcs_i2osp(record2.msg[0].gmt_unix_time, 4) + record2.msg[0].random_bytes\n", |
| "ecdh_params = str(record4[TLSServerKeyExchange].params)\n", |
| "\n", |
| "# Then we retrieve the server's Cert and verify the signature\n", |
| "cert_srv = record3.msg[0].certs[0][1]\n", |
| "cert_srv.verify(cli_random + srv_random + ecdh_params, record4[TLSServerKeyExchange].sig.sig_val, h='sha512')" |
| ] |
| }, |
| { |
| "cell_type": "markdown", |
| "metadata": { |
| "collapsed": true |
| }, |
| "source": [ |
| "## (C) ---> (S) ClientKeyExchange, ChangeCipherSpec, Finished" |
| ] |
| }, |
| { |
| "cell_type": "code", |
| "execution_count": null, |
| "metadata": { |
| "collapsed": false |
| }, |
| "outputs": [], |
| "source": [ |
| "record5_str = open('raw_data/tls_session_protected/05_cli.raw').read()\n", |
| "record5 = TLS(record5_str)\n", |
| "record5.show()" |
| ] |
| }, |
| { |
| "cell_type": "code", |
| "execution_count": null, |
| "metadata": { |
| "collapsed": false |
| }, |
| "outputs": [], |
| "source": [ |
| "# Every record has a 'tls_session' context which may enhance the parsing of later records\n", |
| "record5 = TLS(record5_str, tls_session=record2.tls_session.mirror())\n", |
| "record5.show()" |
| ] |
| }, |
| { |
| "cell_type": "markdown", |
| "metadata": {}, |
| "source": [ |
| "## (C) <--- (S) NewSessionTicket, ChangeCipherSpec, Finished" |
| ] |
| }, |
| { |
| "cell_type": "code", |
| "execution_count": null, |
| "metadata": { |
| "collapsed": false |
| }, |
| "outputs": [], |
| "source": [ |
| "record6_str = open('raw_data/tls_session_protected/06_srv.raw').read()\n", |
| "record6 = TLS(record6_str, tls_session=record5.tls_session.mirror())\n", |
| "record6.show()" |
| ] |
| }, |
| { |
| "cell_type": "markdown", |
| "metadata": {}, |
| "source": [ |
| "## (C) ---> (S) ApplicationData" |
| ] |
| }, |
| { |
| "cell_type": "code", |
| "execution_count": null, |
| "metadata": { |
| "collapsed": false |
| }, |
| "outputs": [], |
| "source": [ |
| "record7_str = open('raw_data/tls_session_protected/07_cli.raw').read()\n", |
| "record7 = TLS(record7_str, tls_session=record6.tls_session.mirror())\n", |
| "record7.show()" |
| ] |
| } |
| ], |
| "metadata": { |
| "kernelspec": { |
| "display_name": "Python 2", |
| "language": "python", |
| "name": "python2" |
| }, |
| "language_info": { |
| "codemirror_mode": { |
| "name": "ipython", |
| "version": 2 |
| }, |
| "file_extension": ".py", |
| "mimetype": "text/x-python", |
| "name": "python", |
| "nbconvert_exporter": "python", |
| "pygments_lexer": "ipython2", |
| "version": "2.7.13" |
| } |
| }, |
| "nbformat": 4, |
| "nbformat_minor": 2 |
| } |