Disclamer: I am NOT a professional cryptographer nor an expert on the subject, only a security enthusiast. Therefor, I strongly encourage anybody more qualified to improve this post.
Before we start, I assume you mean "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" (0xC0,0x2F).
So based on the article you published, here what would change compared to TLS1.0.
First things first: the protocol version should be 1.2 (0x0303) and the client specifies the following parameters:
See below a capture of a ClientHello packet (Firefox 51 Nightly).
⚠ Some extension parameters aren't unfolded because empty/irrelevant.
The server picks its preferred cipher suite (TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) and point format (uncompressed (0) since it's listed as first choice) and send it back to the client.
The server returns its RSA certificate, nothing changes here.
The server authentication process is identical to the one detailed in your article.
The server send the curve type (named_curve), the selected named curve (secp384r1), its ephemeral public key (04:31:b9:9d:bc:66...) and the selected algorithms for hashing and signature.
The signature is defined as:
SHA-256(ClientHello.random + ServerHello.random + ServerKeyExchange.params);
and is signed by the server's private key.
The curve secp384r1 (also known as P-384 under NIST classification) is standard and defined by the following equation:
E: y2=x3+ax+b (mod p)
with the following domain parameters over the prime field Fp-384:
- p = 2384 − 2128 − 296 +
232 − 1 = 39402006196394479212279040100143613805079739270465446667948293404245721771496870329047266088258938001861606973112319
- a = -3
- b = 27580193559959705877849011840389048093056905856361568521428707301988689241309860865136260764883745107765439761230575
- g(X,Y) = 26247035095799689268623156744566981891852923491109213387815615900925518854738050089022388053975719786650872476732087,
- n = 39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942643
- h = 1
All these parameters are public.
Side note: Both the client and server have agreed on using a named curve, resulting in a much smaller Server Key Exchange packet since the domain parameters are standardized and thus known by both parties.
The server public key is calculated as:
Kpub = Kpriv × G
The server private key is just a random number, defined as:
1 ≤ Kpriv ≤ n-1
No difference with TLS1.0.
[Client] ClientKeyExchange / ChangeCipherSpec
This packet contains the client's ephemeral ECDH public key. It's calculated the same way as the server's public key (again, the generator G is common between the client and the server).
From that point, the client advise the server the next message(s) from it will be encrypted.
The server acknowledges client's last message by returning the same ChangeCipherSpec message.
Beyond that point, all communications are encrypted using AES-GCM 128bit.
The symmetric key is calculated on both parties by multiplying its own private key by the other's public key i.e.:
- Client : Symmetric Key = Client Kpriv * Server Kpub
- Server : Symmetric key = Server Kpriv * Client Kpub
TLS 1.3 (bonus)
As of today (august 2016), TLS1.3 is still a draft so it would be premature to deep dive in it. Still, writing similar article based on packet sniffing would be tricky on TLS1.3 because the handshake is vastly different as illustrated below:
As you can see, sniffing the handshake sequence (using cloudflare server) won't tell you much since the relevant data are encrypted in the ServerHello packet (see "EncryptedExtension" field).
I couldn't illustrate the sequence using Wireshark since TLS 1.3 is not supported yet.