tls 1.2 example

enjolras1205

前言

这篇blog类似Example Handshake Traces for TLS 1.3. 人肉trace/verify一个典型的TLS 1.2握手.
因为hash值无法反推, 理解错误时很难debug. 读rfc文档的效率不如直接阅读代码. Finished消息之后的内容尚未验证完毕.

准备工作

nginx

    # HTTPS server
    server {
        listen       443 ssl;
        server_name  localhost;

        ssl_certificate      /etc/nginx/ssl/server.crt;
        ssl_certificate_key  /etc/nginx/ssl/server.key;
        ssl_protocols TLSv1.2;

        location / {
            root   html;
            index  index.html index.htm;
        }
    }

openssl 生成证书

生成私钥和签名请求

openssl提示, private key至少是512 bits.

ubuntu# openssl req -new -newkey rsa:512 -nodes -keyout server.key -out server.csr

私钥内容

私钥内容会用于下面的计算.

ubuntu# openssl rsa -text -in server.key
Private-Key: (512 bit)
modulus:
    00:bf:ec:7d:37:cf:10:f1:94:8a:e1:ca:bf:9b:9c:
    94:13:35:30:75:5e:d0:27:6a:9f:e6:d5:2a:06:0d:
    34:80:17:18:9a:4e:87:0b:60:7f:38:9e:d4:04:49:
    13:b9:b8:45:c0:ad:83:53:70:34:4d:0b:3e:17:4e:
    a8:d6:3f:36:79
publicExponent: 65537 (0x10001)
privateExponent:
    30:f9:14:7e:b0:2c:bf:a8:4a:c4:10:eb:51:b6:e3:
    a5:ff:15:8d:6d:93:29:eb:b0:3f:c3:b7:04:72:4c:
    2a:3e:c9:5d:a3:ae:fb:27:b0:7b:74:b4:08:26:27:
    c6:f0:34:24:d8:21:32:9f:fe:c1:90:45:8b:0a:80:
    67:b4:77:6d
prime1:
    00:de:d1:50:42:ba:8a:8b:64:47:7a:e9:83:02:a7:
    e0:8d:3b:84:56:61:ce:1a:7d:48:6e:ad:97:4d:85:
    c7:be:1b
prime2:
    00:dc:81:61:64:c5:90:f6:b4:87:1e:1f:c6:d1:62:
    cb:03:7f:d0:66:ff:1d:e8:7e:bf:ce:e3:3f:70:b6:
    4c:96:fb
exponent1:
    34:4f:7b:c2:4e:bd:1c:00:8c:ef:84:46:e7:a6:b6:
    07:32:43:dd:6b:d4:d1:4f:3c:64:0f:89:08:00:32:
    66:a5
exponent2:
    00:c4:ed:23:2e:dd:26:7e:bd:71:22:5d:1c:b1:68:
    fa:87:d0:81:2d:4a:cf:ca:10:50:7a:93:06:d8:41:
    66:9b:3b
coefficient:
    47:a4:10:03:d0:b3:83:62:33:95:be:5c:eb:2b:4c:
    5b:87:d4:89:4f:5d:f8:15:a2:4c:7d:5a:58:3b:00:
    9f:41
writing RSA key
-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBAL/sfTfPEPGUiuHKv5uclBM1MHVe0Cdqn+bVKgYNNIAXGJpOhwtg
fzie1ARJE7m4RcCtg1NwNE0LPhdOqNY/NnkCAwEAAQJAMPkUfrAsv6hKxBDrUbbj
pf8VjW2TKeuwP8O3BHJMKj7JXaOu+yewe3S0CCYnxvA0JNghMp/+wZBFiwqAZ7R3
bQIhAN7RUEK6iotkR3rpgwKn4I07hFZhzhp9SG6tl02Fx74bAiEA3IFhZMWQ9rSH
Hh/G0WLLA3/QZv8d6H6/zuM/cLZMlvsCIDRPe8JOvRwAjO+ERuemtgcyQ91r1NFP
PGQPiQgAMmalAiEAxO0jLt0mfr1xIl0csWj6h9CBLUrPyhBQepMG2EFmmzsCIEek
EAPQs4NiM5W+XOsrTFuH1IlPXfgVokx9Wlg7AJ9B
-----END RSA PRIVATE KEY-----

生成证书

ubuntu# openssl x509 -req -in server.csr -signkey server.key -out server.crt
Signature ok
subject=/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd
Getting Private key

ssl key log

只有用RSA作为密钥加密算法时, 才能仅依据RSA私钥解密整个通信内容. 所以要记录ssl握手日志.
握手日志格式:Key_Log_Format
在bashrc里export的方式对我无效. 于是直接在启动命令行上export.
image.png
image.png

key log

CLIENT_RANDOM 40d527ab4688ac43d40aad7ddb955053c6fc3abaf16511a74ef0894214b404c7 84d061c5ef4bf433f4f897cb2fcf8a53896e8d0ae7d5adc378b0e5c42cfc9abe43513bfe2408b0ab30217fabd6474c7b

过程

tls v1.2 见https://tools.ietf.org/html/rfc5246

  Client                                               Server

  ClientHello                  -------->
                                                  ServerHello
                                                 Certificate\*
                                           ServerKeyExchange\*
                                          CertificateRequest\*
                               <--------      ServerHelloDone
  Certificate\*
  ClientKeyExchange
  CertificateVerify\*
  \[ChangeCipherSpec\]
  Finished                     -------->
                                           \[ChangeCipherSpec\]
                               <--------             Finished
  Application Data             <------->     Application Data

         Figure 1.  Message flow for a full handshake

ClientHello

该步骤完全是明文.

      struct {
          ProtocolVersion client\_version;
          Random random;
          SessionID session\_id;
          CipherSuite cipher\_suites<2..2^16-2>;
          CompressionMethod compression\_methods<1..2^8-1>;
          select (extensions\_present) {
              case false:
                  struct {};
              case true:
                  Extension extensions<0..2^16-1>;
          };
      } ClientHello;

image.png

ServerHello

该步骤完全是明文

      struct {
          ProtocolVersion server\_version;
          Random random;
          SessionID session\_id;
          CipherSuite cipher\_suite;
          CompressionMethod compression\_method;
          select (extensions\_present) {
              case false:
                  struct {};
              case true:
                  Extension extensions<0..2^16-1>;
          };
      } ServerHello;

image.png

Certificate

      opaque ASN.1Cert<1..2^24-1>;

      struct {
          ASN.1Cert certificate\_list<0..2^24-1>;
      } Certificate;

image.png

证书内容效验

可以看到,发给客户端挑选的证书,只有前面生成的部分.

抓包内容

copy as a Hex Stream

3082017c30820126020900f222ec913dca89ff300d06092a864886f70d01010b05003045310b30090603550406130241553113301106035504080c0a536f6d652d53746174653121301f060355040a0c18496e7465726e6574205769646769747320507479204c7464301e170d3139313231363133313431305a170d3230303131353133313431305a3045310b30090603550406130241553113301106035504080c0a536f6d652d53746174653121301f060355040a0c18496e7465726e6574205769646769747320507479204c7464305c300d06092a864886f70d0101010500034b003048024100bfec7d37cf10f1948ae1cabf9b9c94133530755ed0276a9fe6d52a060d348017189a4e870b607f389ed4044913b9b845c0ad835370344d0b3e174ea8d63f36790203010001300d06092a864886f70d01010b0500034100781581578ce8a601dedb1a0469771843aa47f7a493c4e5e459b978507399faa9b043cbda16c832bc522ea035a47280e991048bfa425b499a58a9057c3ef54740

证书内容

~/tls_test » cat server.crt | grep -v "CERTIFICATE" | base64 -d | xxd
00000000: 3082 017c 3082 0126 0209 00f2 22ec 913d  0..|0..&...."..=
00000010: ca89 ff30 0d06 092a 8648 86f7 0d01 010b  ...0...*.H......
00000020: 0500 3045 310b 3009 0603 5504 0613 0241  ..0E1.0...U....A
00000030: 5531 1330 1106 0355 0408 0c0a 536f 6d65  U1.0...U....Some
00000040: 2d53 7461 7465 3121 301f 0603 5504 0a0c  -State1!0...U...
00000050: 1849 6e74 6572 6e65 7420 5769 6467 6974  .Internet Widgit
00000060: 7320 5074 7920 4c74 6430 1e17 0d31 3931  s Pty Ltd0...191
00000070: 3231 3631 3331 3431 305a 170d 3230 3031  216131410Z..2001
00000080: 3135 3133 3134 3130 5a30 4531 0b30 0906  15131410Z0E1.0..
00000090: 0355 0406 1302 4155 3113 3011 0603 5504  .U....AU1.0...U.
000000a0: 080c 0a53 6f6d 652d 5374 6174 6531 2130  ...Some-State1!0
000000b0: 1f06 0355 040a 0c18 496e 7465 726e 6574  ...U....Internet
000000c0: 2057 6964 6769 7473 2050 7479 204c 7464   Widgits Pty Ltd
000000d0: 305c 300d 0609 2a86 4886 f70d 0101 0105  0\0...*.H.......
000000e0: 0003 4b00 3048 0241 00bf ec7d 37cf 10f1  ..K.0H.A...}7...
000000f0: 948a e1ca bf9b 9c94 1335 3075 5ed0 276a  .........50u^.'j
00000100: 9fe6 d52a 060d 3480 1718 9a4e 870b 607f  ...*..4....N..`.
00000110: 389e d404 4913 b9b8 45c0 ad83 5370 344d  8...I...E...Sp4M
00000120: 0b3e 174e a8d6 3f36 7902 0301 0001 300d  .>.N..?6y.....0.
00000130: 0609 2a86 4886 f70d 0101 0b05 0003 4100  ..*.H.........A.
00000140: 7815 8157 8ce8 a601 dedb 1a04 6977 1843  x..W........iw.C
00000150: aa47 f7a4 93c4 e5e4 59b9 7850 7399 faa9  .G......Y.xPs...
00000160: b043 cbda 16c8 32bc 522e a035 a472 80e9  .C....2.R..5.r..
00000170: 9104 8bfa 425b 499a 58a9 057c 3ef5 4740  ....B[I.X..|>.G@

Server Key Exchange Message

实际使用的算法是dhe_rsa, 参照ServerHello中的Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256.

      struct {
          opaque dh_p<1..2^16-1>;
          opaque dh_g<1..2^16-1>;
          opaque dh_Ys<1..2^16-1>;
      } ServerDHParams;     /* Ephemeral DH parameters */

      dh_p
         The prime modulus used for the Diffie-Hellman operation.

      dh_g
         The generator used for the Diffie-Hellman operation.

      dh_Ys
         The server's Diffie-Hellman public value (g^X mod p).
         
      struct {
          select (KeyExchangeAlgorithm) {
              case dh_anon:
                  ServerDHParams params;
              case dhe_dss:
              case dhe_rsa:
                  ServerDHParams params;
                  digitally-signed struct {
                      opaque client_random[32];
                      opaque server_random[32];
                      ServerDHParams params;
                  } signed_params;
              case rsa:
              case dh_dss:
              case dh_rsa:
                  struct {} ;
                 /* message is omitted for rsa, dh_dss, and dh_rsa */
              /* may be extended, e.g., for ECDH -- see [TLSECC] */
          };
      } ServerKeyExchange;

      params
         The server's key exchange parameters.

      signed_params
         For non-anonymous key exchanges, a signature over the server's
         key exchange parameters.

image.png

验证

签名验证

签名数据

client_random:
40d527ab4688ac43d40aad7ddb955053c6fc3abaf16511a74ef0894214b404c7
server_random:
830fe44c4f3d85e3d95f6b0043de6f87e2e6613625d39fd5fa42d85a34fd5580
server dh params:
030017410433bad3063e435c706c39a994d83f1d69bb30cfd12150d5bb4e16584d1751ce5cdeefaefa57b2f9cced0f9f86b2ced66f0e00ee2c9d21b7a4a77351299c984063
all data for sign:
这里注意, 签名的内容和rfc文档中完全一致, 提取ServerDHParams时建议整个copy出来, 再剔除掉Signature Algorithm Signature Length, Signature等bytes.

~/tls_test » echo -n ~/tls_test » echo -n "40d527ab4688ac43d40aad7ddb955053c6fc3abaf16511a74ef0894214b404c7830fe44c4f3d85e3d95f6b0043de6f87e2e6613625d39fd5fa42d85a34fd5580030017410433bad3063e435c706c39a994d83f1d69bb30cfd12150d5bb4e16584d1751ce5cdeefaefa57b2f9cced0f9f86b2ced66f0e00ee2c9d21b7a4a77351299c984063" | xxd -r -p > all_random
~/tls_test » cat all_random | xxd
00000000: 40d5 27ab 4688 ac43 d40a ad7d db95 5053  @.'.F..C...}..PS
00000010: c6fc 3aba f165 11a7 4ef0 8942 14b4 04c7  ..:..e..N..B....
00000020: 830f e44c 4f3d 85e3 d95f 6b00 43de 6f87  ...LO=..._k.C.o.
00000030: e2e6 6136 25d3 9fd5 fa42 d85a 34fd 5580  ..a6%....B.Z4.U.
00000040: 0300 1741 0433 bad3 063e 435c 706c 39a9  ...A.3...>C\pl9.
00000050: 94d8 3f1d 69bb 30cf d121 50d5 bb4e 1658  ..?.i.0..!P..N.X
00000060: 4d17 51ce 5cde efae fa57 b2f9 cced 0f9f  M.Q.\....W......
00000070: 86b2 ced6 6f0e 00ee 2c9d 21b7 a4a7 7351  ....o...,.!...sQ
00000080: 299c 9840 63                             )..@c
签名结果

7703282574ba1e59284b3853ab108f06d2cf072cc9cabf89787fe8a7fad450301fe3c6091126ab4a967f1dcf8d96857ebd7bca27bce1ca5fe08c1316531b58f3

签名验证

在wireshark中将EC Diffie-Hellman Server Params的Signature使用Export Packet Bytes导出到文件.
之后用openssl验证签名. 可以看到验证是成功的.

~/tls_test » cat server_exchange_signature| xxd                                                             
00000000: 7703 2825 74ba 1e59 284b 3853 ab10 8f06  w.(%t..Y(K8S....
00000010: d2cf 072c c9ca bf89 787f e8a7 fad4 5030  ...,....x.....P0
00000020: 1fe3 c609 1126 ab4a 967f 1dcf 8d96 857e  .....&.J.......~
00000030: bd7b ca27 bce1 ca5f e08c 1316 531b 58f3  .{.'..._....S.X.
~/tls_test » openssl rsautl -verify -inkey server.pem -in server_exchange_signature -pubin | xxd
00000000: 3031 300d 0609 6086 4801 6503 0402 0105  010...`.H.e.....
00000010: 0004 2029 35e7 0121 926d 2e13 d655 9943  .. )5..!.m...U.C
00000020: 8598 6c0c ac36 beb6 17ab f268 86d7 8c90  ..l..6.....h....
00000030: 6058 b4                                  `X.

正向计算哈希值, 和verify的结果刚好吻合. 前面还有一些疑似的magic number. 因为每次sign verify, 都有类似的字节. 这里不追究这些magic number的细节.

~/tls_test » sha256sum all_random                                                                           
2935e70121926d2e13d655994385986c0cac36beb617abf26886d78c906058b4  all_random
~/tls_test » echo "abcd" >> tt
~/tls_test » openssl dgst -sha256 -sign server.key -out all_random_signature tt
~/tls_test » openssl dgst -sha256 -sign server.key -out tt_signature tt
~/tls_test » openssl rsautl -verify -inkey server.pem -in tt_signature -pubin | xxd
00000000: 3031 300d 0609 6086 4801 6503 0402 0105  010...`.H.e.....
00000010: 0004 20fc 4b5f d681 6f75 a7c8 1fc8 eaa9  .. .K_..ou......
00000020: 499d 6a29 9bd8 0339 7166 e8c4 cf92 80b8  I.j)...9qf......
00000030: 01d6 2c                                  ..,
------------------------------------------------------------
~/tls_test » sha256sum tt
fc4b5fd6816f75a7c81fc8eaa9499d6a299bd803397166e8c4cf9280b801d62c  tt

Server Hello Done

告诉client可以做key exchange了.

   Meaning of this message:

      This message means that the server is done sending messages to
      support the key exchange, and the client can proceed with its
      phase of the key exchange.

      Upon receipt of the ServerHelloDone message, the client SHOULD
      verify that the server provided a valid certificate, if required,
      and check that the server hello parameters are acceptable.

image.png

Client Key Exchange

      struct {
          select (KeyExchangeAlgorithm) {
              case rsa:
                  EncryptedPreMasterSecret;
              case dhe_dss:
              case dhe_rsa:
              case dh_dss:
              case dh_rsa:
              case dh_anon:
                  ClientDiffieHellmanPublic;
          } exchange_keys;
      } ClientKeyExchange;

发送的是ClientDiffieHellmanPublic, 如果是rsa, 则有一个可用前面私钥直接解密的pre master secret.
image.png

Change Cipher Spec

The ChangeCipherSpec message is sent by both the client and the
server to notify the receiving party that subsequent records will be
protected under the newly negotiated CipherSpec and keys.

Finished

Finished用于验证加密/压缩是正确的.

   Meaning of this message:

      The Finished message is the first one protected with the just
      negotiated algorithms, keys, and secrets.  Recipients of Finished
      messages MUST verify that the contents are correct.  Once a side
      has sent its Finished message and received and validated the
      Finished message from its peer, it may begin to send and receive
      application data over the connection.
      
   Structure of this message:

      struct {
          opaque verify_data[verify_data_length];
      } Finished;

      verify_data
         PRF(master_secret, finished_label, Hash(handshake_messages))
            [0..verify_data_length-1];

验证

这里对不上.

      struct {
          opaque verify_data[verify_data_length];
      } Finished;

      verify_data
         PRF(master_secret, finished_label, Hash(handshake_messages))
            [0..verify_data_length-1];
master_secret:

84d061c5ef4bf433f4f897cb2fcf8a53896e8d0ae7d5adc378b0e5c42cfc9abe43513bfe2408b0ab30217fabd6474c7b

finished_label:
~/tls_test/master_key » echo -n "client finished" | xxd -p
636c69656e742066696e6973686564
handshake_messages:

如下hex string包含图中的Client Hello, Server Hello, Certificate Server key Exchange, Server Hello Done, Client Key Exchange, 具体看rfc文档对handshake_messages的解释:
16030100c0010000bc030340d527ab4688ac43d40aad7ddb955053c6fc3abaf16511a74ef0894214b404c700001c4a4ac02bc02fc02cc030cca9cca8c013c014009c009d002f0035000a010000772a2a0000ff010001000000000e000c0000096c6f63616c686f73740017000000230000000d00140012040308040401050308050501080606010201000500050100000000001200000010000e000c02683208687474702f312e3175500000000b00020100000a000a0008dada001d00170018aaaa00010016030300500200004c0303830fe44c4f3d85e3d95f6b0043de6f87e2e6613625d39fd5fa42d85a34fd558000c02f00002400000000ff01000100000b000403000102002300000010000b000908687474702f312e31160303018a0b0001860001830001803082017c30820126020900f222ec913dca89ff300d06092a864886f70d01010b05003045310b30090603550406130241553113301106035504080c0a536f6d652d53746174653121301f060355040a0c18496e7465726e6574205769646769747320507479204c7464301e170d3139313231363133313431305a170d3230303131353133313431305a3045310b30090603550406130241553113301106035504080c0a536f6d652d53746174653121301f060355040a0c18496e7465726e6574205769646769747320507479204c7464305c300d06092a864886f70d0101010500034b003048024100bfec7d37cf10f1948ae1cabf9b9c94133530755ed0276a9fe6d52a060d348017189a4e870b607f389ed4044913b9b845c0ad835370344d0b3e174ea8d63f36790203010001300d06092a864886f70d01010b0500034100781581578ce8a601dedb1a0469771843aa47f7a493c4e5e459b978507399faa9b043cbda16c832bc522ea035a47280e991048bfa425b499a58a9057c3ef54740160303008d0c000089030017410433bad3063e435c706c39a994d83f1d69bb30cfd12150d5bb4e16584d1751ce5cdeefaefa57b2f9cced0f9f86b2ced66f0e00ee2c9d21b7a4a77351299c984063040100407703282574ba1e59284b3853ab108f06d2cf072cc9cabf89787fe8a7fad450301fe3c6091126ab4a967f1dcf8d96857ebd7bca27bce1ca5fe08c1316531b58f316030300040e0000001603030046100000424104d2fd09c930874f11669ec3984cdd2efb58723923b9f09dba2542cebe78bcbf5fbdebf9c4f3e09a43717e55c9c8894a44a7ea982372a6412281b078ee72ad2529

hash of handshake_messages:

14893b9f972337e124d5800a20ef17af838d0656622cb7de6e26951b0fa1cd65

verify_data

49a52d49768df624fadd438a

calc verify_data
~/tls_test/master_key » echo -n "84d061c5ef4bf433f4f897cb2fcf8a53896e8d0ae7d5adc378b0e5c42cfc9abe43513bfe2408b0ab30217fabd6474c7b636c69656e742066696e697368656414893b9f972337e124d5800a20ef17af838d0656622cb7de6e26951b0fa1cd65" | xxd -r -p | sha256sum
4a752a714db4ce8708f018f85f88f6759f3cfd14b9f1e6d1eaea8147f295e39a  -

decrypt

AES-GCM Authenticated Encryption

阅读 1.6k

51 声望
3 粉丝
0 条评论
51 声望
3 粉丝
文章目录
宣传栏