grpc, http2 and wireshark
This page shows how to decrypt gRPC traffic in wireshark.
この頁は、wireshark でgRPC 通信を復号する方法を示す。
grpc クイックスタート
https://grpc.io/docs/quickstart/go.html
に従う。新し目の wireshark だと、
パケットを右クリックして、と、してデコード、現在、を HTTP2 にすると、grpc としてデコードまでしてくれる。
HyperText Transfer Protocol 2
Stream: Magic
Stream: SETTINGS, Stream ID: 0, Length 36
Stream: HEADERS, Stream ID: 1, Length 286, POST /helloworld.Greeter/SayHello
Stream: WINDOW_UPDATE, Stream ID: 1, Length 4
Stream: DATA, Stream ID: 1, Length 10
GRPC Message: /helloworld.Greeter/SayHello, Request
Compressed Flag: Not Compressed (0)
Message Length: 5
Message Data: 5 bytes
Protocol Buffers: application/grpc,/helloworld.Greeter/SayHello,request
Field[1]
.000 1... = Field Number: 1
.... .010 = Wire Type: Length-delimited (2)
Value Length: 3
Value: 796f75
Stream: WINDOW_UPDATE, Stream ID: 0, Length 4
Stream: PING, Stream ID: 0, Length 8
HyperText Transfer Protocol 2
Stream: HEADERS, Stream ID: 1, Length 119, 200 OK
Stream: DATA, Stream ID: 1, Length 18 (partial entity body)
Stream: HEADERS, Stream ID: 1, Length 30
GRPC Message: /helloworld.Greeter/SayHello, Response
Compressed Flag: Not Compressed (0)
Message Length: 13
Message Data: 13 bytes
Protocol Buffers: application/grpc,/helloworld.Greeter/SayHello,response
Field[1]
.000 1... = Field Number: 1
.... .010 = Wire Type: Length-delimited (2)
Value Length: 11
Value: 48656c6c6f2c20796f7521
wireshark で、 http2 with tls セッションを平文で見る
http://d.hatena.ne.jp/ozuma/20140413/1397397632
最新情報では、
https://wiki.wireshark.org/SSL
秘密鍵を入れる RSA keys list ダイアログで、 ip address=any , port=0 でもよくなった。
ssl debug file を指定すると、そこに、デコードがなぜ失敗したかわかるメッセージが出る。
ssl_decrypt_pre_master_secret: session uses Diffie-Hellman key exchange (cipher suite 0xC014 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) and cannot be decrypted using a RSA private key file.
なあんだ。Diffie-Hellman が使われていたからダメだったのか。
curl なら、引数で、使う暗号を指定できる。
https://unix.stackexchange.com/questions/208437/how-to-convert-ssl-ciphers-to-curl-format
見えた
サーバは、 nginx
$ curl --ciphers rsa_aes_256_sha https://localhost/
No. Time Source Destination Protocol Length Info
16 422.305987666 ::1 ::1 TLSv1.2 215 Client Hello
Secure Sockets Layer
TLSv1.2 Record Layer: Handshake Protocol: Client Hello
Content Type: Handshake (22)
Version: TLS 1.0 (0x0301)
Length: 124
Handshake Protocol: Client Hello
Handshake Type: Client Hello (1)
Length: 120
Version: TLS 1.2 (0x0303)
Random
Session ID Length: 0
Cipher Suites Length: 2
Cipher Suites (1 suite)
Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA (0x0035) <=クライアントからの暗号提案
Compression Methods Length: 1
Compression Methods (1 method)
Extensions Length: 77
Extension: server_name
Extension: renegotiation_info
Extension: Application Layer Protocol Negotiation
Type: Application Layer Protocol Negotiation (0x0010)
Length: 14
ALPN Extension Length: 12
ALPN Protocol
ALPN string length: 8
ALPN Next Protocol: http/1.1
ALPN string length: 2
ALPN Next Protocol: h2 <=これが、 http2 with tls
Extension: signature_algorithms
18 422.306592241 ::1 ::1 TLSv1.2 1217 Server Hello, Certificate, Server Hello Done
Secure Sockets Layer
TLSv1.2 Record Layer: Handshake Protocol: Server Hello
Content Type: Handshake (22)
Version: TLS 1.2 (0x0303)
Length: 90
Handshake Protocol: Server Hello
Handshake Type: Server Hello (2)
Length: 86
Version: TLS 1.2 (0x0303)
Random
Session ID Length: 32
Session ID: cf40e6321e60297814e538c24702ac193360c18c99c1096a...
Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA (0x0035)
Compression Method: null (0)
Extensions Length: 14
Extension: renegotiation_info
Extension: Application Layer Protocol Negotiation
Type: Application Layer Protocol Negotiation (0x0010)
Length: 5
ALPN Extension Length: 3
ALPN Protocol
ALPN string length: 2
ALPN Next Protocol: h2
TLSv1.2 Record Layer: Handshake Protocol: Certificate
TLSv1.2 Record Layer: Handshake Protocol: Server Hello Done
No. Time Source Destination Protocol Length Info
20 422.313666387 ::1 ::1 TLSv1.2 428 Client Key Exchange, Change Cipher Spec, Finished
No. Time Source Destination Protocol Length Info
21 422.339419788 ::1 ::1 TLSv1.2 161 Change Cipher Spec, Finished
No. Time Source Destination Protocol Length Info
22 422.340368279 ::1 ::1 HTTP2 155 Magic
Secure Sockets Layer
TLSv1.2 Record Layer: Application Data Protocol: http2
Content Type: Application Data (23)
Version: TLS 1.2 (0x0303)
Length: 64
Encrypted Application Data: 9330bdfea71aac706c8f2c8a40fc2405e9edfe5b04df079c...
HyperText Transfer Protocol 2
Stream: Magic
Magic: PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n <=http2 の最初の電文
No. Time Source Destination Protocol Length Info
23 422.340507409 ::1 ::1 HTTP2 139 SETTINGS
HyperText Transfer Protocol 2
Stream: SETTINGS, Stream ID: 0, Length 0
Length: 0
Type: SETTINGS (4)
Flags: 0x00
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0000 = Stream Identifier: 0
No. Time Source Destination Protocol Length Info
24 422.340686491 ::1 ::1 HTTP2 171 HEADERS
HyperText Transfer Protocol 2
Stream: HEADERS, Stream ID: 1, Length 26
Length: 26
Type: HEADERS (1)
Flags: 0x05
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0001 = Stream Identifier: 1
[Pad Length: 0]
Header Block Fragment: 8284874186a0e41d139d097a8825b650c3abb615c153032a...
[Header Length: 125]
[Header Count: 6]
Header: :method: GET
Header: :path: /
Header: :scheme: https
Header: :authority: localhost
Header: user-agent: curl/7.51.0
Header: accept: */*
Padding: <MISSING>
No. Time Source Destination Protocol Length Info
26 422.403586354 ::1 ::1 HTTP2 299 SETTINGS, WINDOW_UPDATE, SETTINGS, HEADERS
HyperText Transfer Protocol 2
Stream: SETTINGS, Stream ID: 0, Length 18
Length: 18
Type: SETTINGS (4)
Flags: 0x00
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0000 = Stream Identifier: 0
Settings - Max concurrent streams : 128
Settings - Initial Windows size : 65536
Settings - Max frame size : 16777215
Stream: WINDOW_UPDATE, Stream ID: 0, Length 4
Length: 4
Type: WINDOW_UPDATE (8)
Flags: 0x00
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0000 = Stream Identifier: 0
0... .... .... .... .... .... .... .... = Reserved: 0x0
.111 1111 1111 1111 0000 0000 0000 0000 = Window Size Increment: 2147418112
Stream: SETTINGS, Stream ID: 0, Length 0
Length: 0
Type: SETTINGS (4)
Flags: 0x01
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0000 = Stream Identifier: 0
Stream: HEADERS, Stream ID: 1, Length 109
Length: 109
Type: HEADERS (1)
Flags: 0x04
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0001 = Stream Identifier: 1
[Pad Length: 0]
Header Block Fragment: 887689aa6355e580ae112e1f6196df697e94034a6e2d6a08...
[Header Length: 242]
[Header Count: 8]
Header: :status: 200
Header: server: nginx/1.12.1
Header: date: Tue, 04 Sep 2018 10:34:43 GMT
Header: content-type: text/html
Header: content-length: 3700
Header: last-modified: Tue, 15 Aug 2017 08:51:37 GMT
Header: etag: "5992b619-e74"
Header: accept-ranges: bytes
Padding: <MISSING>
No. Time Source Destination Protocol Length Info
27 422.404081133 ::1 ::1 HTTP2 139 SETTINGS
HyperText Transfer Protocol 2
Stream: SETTINGS, Stream ID: 0, Length 0
Length: 0
Type: SETTINGS (4)
Flags: 0x01
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0000 = Stream Identifier: 0
No. Time Source Destination Protocol Length Info
28 422.425518693 ::1 ::1 HTTP2 3851 DATA
HyperText Transfer Protocol 2
Stream: DATA, Stream ID: 1, Length 3700
Length: 3700
Type: DATA (0)
Flags: 0x01
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0001 = Stream Identifier: 1
[Pad Length: 0]
Data: 3c21444f43545950452068746d6c205055424c494320222d... <=これが、 index.html
Padding: <MISSING>
Wireshark SSL debug log
Wireshark version: 2.2.7 (wireshark-2.2.7)
ssl_init private key file /etc/pki/nginx/private/server.key successfully loaded.
ssl_decrypt_record ciphertext len 64
Ciphertext[64]:
| 93 30 bd fe a7 1a ac 70 6c 8f 2c 8a 40 fc 24 05 |.0.....pl.,.@.$.|
| e9 ed fe 5b 04 df 07 9c 69 c8 69 2d a4 7c e9 50 |...[....i.i-.|.P|
| 92 4c 62 84 fe df 7a f2 a6 29 8e 0f 24 52 67 e2 |.Lb...z..)..$Rg.|
| f1 37 e6 5b 31 8b a9 11 fa e7 63 84 0a d8 09 c0 |.7.[1.....c.....|
Plaintext[48]:
| 50 52 49 20 2a 20 48 54 54 50 2f 32 2e 30 0d 0a |PRI * HTTP/2.0..|
| 0d 0a 53 4d 0d 0a 0d 0a c2 76 5a a0 6f 7e 88 20 |..SM.....vZ.o~. |
| ce 2f e9 5f 5b dd 3d a6 7b ee cd fc 03 03 03 03 |./._[.=.{.......|
grpc with tls 電文を、デコードして見る
https://grpc.io/docs/guides/auth.html
に従って、 tls を使った通信を、見る。
そのままやったら、Diffie-Hellman になったので、使う暗号を制限しないといけない。
https://groups.google.com/forum/#!topic/grpc-io/6L0rfhtvP48
に、credential の関数を生で使えばできる、と書いてある。
できた
サンプルソースの差分
diff --git a/examples/helloworld/greeter_client/main.go b/examples/helloworld/greeter_client/main.go
index 4b99ff5..b83bba3 100644
--- a/examples/helloworld/greeter_client/main.go
+++ b/examples/helloworld/greeter_client/main.go
@@ -22,10 +22,14 @@ import (
"log"
"os"
"time"
+ "crypto/tls"
+ "crypto/x509"
+ "io/ioutil"
"golang.org/x/net/context"
"google.golang.org/grpc"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
+ "google.golang.org/grpc/credentials"
)
const (
@@ -34,8 +38,22 @@ const (
)
func main() {
+ certFile := "./cacert.pem"
+ //creds, err := credentials.NewClientTLSFromFile(certFile, "")
+ b, err := ioutil.ReadFile(certFile)
+ if err != nil {
+ log.Fatalf("cert file: %s", err)
+ }
+ cp := x509.NewCertPool()
+ if !cp.AppendCertsFromPEM(b) {
+ log.Fatal("credentials: failed to append certificates")
+ }
+ creds := credentials.NewTLS(&tls.Config{ServerName: "", RootCAs: cp,
+ CipherSuites: []uint16{
+ tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
+ }})
// Set up a connection to the server.
- conn, err := grpc.Dial(address, grpc.WithInsecure())
+ conn, err := grpc.Dial(address, grpc.WithTransportCredentials(creds))
if err != nil {
log.Fatalf("did not connect: %v", err)
}
diff --git a/examples/helloworld/greeter_server/main.go b/examples/helloworld/greeter_server/main.go
index 702a3b6..f96b862 100644
--- a/examples/helloworld/greeter_server/main.go
+++ b/examples/helloworld/greeter_server/main.go
@@ -28,6 +28,7 @@ import (
"google.golang.org/grpc"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
"google.golang.org/grpc/reflection"
+ "google.golang.org/grpc/credentials"
)
const (
@@ -47,7 +48,13 @@ func main() {
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
- s := grpc.NewServer()
+ certFile := "./server.crt"
+ keyFile := "./server.key"
+ creds, err := credentials.NewServerTLSFromFile(certFile, keyFile)
+ if err != nil {
+ log.Fatalf("cred: %s", err)
+ }
+ s := grpc.NewServer(grpc.Creds(creds))
pb.RegisterGreeterServer(s, &server{})
// Register reflection service on gRPC server.
reflection.Register(s)
以上