diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 92fbccf8ae1..a1a7e03532f 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -194,6 +194,8 @@ https://github.com/elastic/beats/compare/v6.4.0...6.x[Check the HEAD diff] *Packetbeat* +- Support new TLS version negotiation introduced in TLS 1.3. {issue}8647[8647]. + *Winlogbeat* *Functionbeat* diff --git a/packetbeat/_meta/kibana/6/dashboard/Packetbeat-tls.json b/packetbeat/_meta/kibana/6/dashboard/Packetbeat-tls.json index 4e9d447bb2f..9b08834f475 100644 --- a/packetbeat/_meta/kibana/6/dashboard/Packetbeat-tls.json +++ b/packetbeat/_meta/kibana/6/dashboard/Packetbeat-tls.json @@ -447,7 +447,7 @@ "id": "2", "params": { "customLabel": "TLS version", - "field": "tls.server_hello.version", + "field": "tls.version", "order": "desc", "orderBy": "1", "size": 5 @@ -485,7 +485,7 @@ } }, "savedSearchId": "8f0ff590-d37d-11e7-9914-4982455b3063", - "title": "TLS Client Version", + "title": "TLS Server Public Key Size", "uiStateJSON": {}, "version": 1, "visState": { @@ -501,8 +501,8 @@ "enabled": true, "id": "2", "params": { - "customLabel": "Client version", - "field": "tls.client_hello.version", + "customLabel": "Public Key Size", + "field": "tls.server_certificate.public_key_size", "order": "desc", "orderBy": "1", "size": 5 @@ -518,7 +518,7 @@ "legendPosition": "right", "type": "pie" }, - "title": "TLS Client Version", + "title": "Server Public Key Size", "type": "pie" } }, @@ -1153,13 +1153,13 @@ "store": "appState" }, "exists": { - "field": "tls.server_hello.version" + "field": "tls.version" }, "meta": { "alias": null, "disabled": false, "index": "packetbeat-*", - "key": "tls.server_hello.version", + "key": "tls.version", "negate": false, "type": "exists", "value": "exists" @@ -1207,13 +1207,13 @@ "store": "appState" }, "exists": { - "field": "tls.client_hello.version" + "field": "tls.server_certificate.public_key_size" }, "meta": { "alias": null, "disabled": false, "index": "packetbeat-*", - "key": "tls.client_hello.version", + "key": "tls.server_certificate.public_key_size", "negate": false, "type": "exists", "value": "exists" @@ -1238,7 +1238,7 @@ "@timestamp", "desc" ], - "title": "TLS Client Version", + "title": "Server Public Key Size", "version": 1 }, "id": "8f0ff590-d37d-11e7-9914-4982455b3063", @@ -1626,4 +1626,4 @@ } ], "version": "6.2.4" -} \ No newline at end of file +} diff --git a/packetbeat/docs/fields.asciidoc b/packetbeat/docs/fields.asciidoc index 9919a7bd136..afdc3121286 100644 --- a/packetbeat/docs/fields.asciidoc +++ b/packetbeat/docs/fields.asciidoc @@ -3902,6 +3902,18 @@ TLS-specific event fields. +*`tls.version`*:: ++ +-- +type: keyword + +example: TLS 1.3 + +The version of the TLS protocol used. + + +-- + *`tls.handshake_completed`*:: + -- @@ -4006,6 +4018,16 @@ type: keyword Length of the session ticket, if provided, or an empty string to advertise support for tickets. +-- + +*`tls.client_hello.extensions.supported_versions`*:: ++ +-- +type: keyword + +List of TLS versions that the client is willing to use. + + -- @@ -4062,6 +4084,16 @@ type: keyword Used to announce that a session ticket will be provided by the server. Always an empty string. +-- + +*`tls.server_hello.extensions.supported_versions`*:: ++ +-- +type: keyword + +Negotiated TLS version to be used. + + -- [float] diff --git a/packetbeat/include/fields.go b/packetbeat/include/fields.go index 0e159c1a0c8..a7326c6dc42 100644 --- a/packetbeat/include/fields.go +++ b/packetbeat/include/fields.go @@ -31,5 +31,5 @@ func init() { // Asset returns asset data func Asset() string { - return "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" + return "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" } diff --git a/packetbeat/protos/tls/_meta/fields.yml b/packetbeat/protos/tls/_meta/fields.yml index c0b7fd03b32..0bcfebc01ec 100644 --- a/packetbeat/protos/tls/_meta/fields.yml +++ b/packetbeat/protos/tls/_meta/fields.yml @@ -6,6 +6,12 @@ - name: tls type: group fields: + - name: version + type: keyword + description: > + The version of the TLS protocol used. + example: "TLS 1.3" + - name: handshake_completed type: boolean description: > @@ -69,6 +75,11 @@ Length of the session ticket, if provided, or an empty string to advertise support for tickets. + - name: supported_versions + type: keyword + description: > + List of TLS versions that the client is willing to use. + - name: server_hello type: group fields: @@ -105,6 +116,11 @@ Used to announce that a session ticket will be provided by the server. Always an empty string. + - name: supported_versions + type: keyword + description: > + Negotiated TLS version to be used. + - name: client_certificate type: group description: Certificate provided by the client for authentication. diff --git a/packetbeat/protos/tls/extensions.go b/packetbeat/protos/tls/extensions.go index b1531c7269f..c9240b40f88 100644 --- a/packetbeat/protos/tls/extensions.go +++ b/packetbeat/protos/tls/extensions.go @@ -66,6 +66,7 @@ var extensionMap = map[uint16]extension{ 13: {"signature_algorithms", parseSignatureSchemes, false}, 16: {"application_layer_protocol_negotiation", parseALPN, false}, 35: {"session_ticket", parseTicket, false}, + 43: {"supported_versions", parseSupportedVersions, false}, 0xff01: {"renegotiation_info", ignoreContent, false}, } @@ -272,3 +273,47 @@ func parseALPN(buffer bufferView) interface{} { } return protos } + +func parseSupportedVersions(buffer bufferView) interface{} { + // Parsing the supported_versions extensions requires knowing whether the + // extension is included in a client_hello or server_hello, but a workaround + // can be done by looking at the extension length. + + // Server-side extension has length 2: Selected version (2 bytes) + if buffer.length() == 2 { + var ver tlsVersion + if !buffer.read8(0, &ver.major) || !buffer.read8(1, &ver.minor) { + return nil + } + return ver.String() + } + + // Client-side extension has at least 3 bytes: 1 byte length + 2 byte entry + if buffer.length() >= 3 { + var listBytes uint8 + if !buffer.read8(0, &listBytes) { + return nil + } + if 1+int(listBytes) > buffer.length() || listBytes&1 != 0 { + return nil + } + + numEntries := int(listBytes) / 2 + if numEntries == 0 { + return nil + } + list := make([]string, 0, numEntries) + for i := 0; i < numEntries; i++ { + var val uint16 + if !buffer.read16Net(1+2*i, &val) { + return nil + } + if !isGreaseValue(val) { + list = append(list, tlsVersion{major: uint8(val >> 8), minor: uint8(val & 0xff)}.String()) + } + } + return list + } + + return nil +} diff --git a/packetbeat/protos/tls/extensions_test.go b/packetbeat/protos/tls/extensions_test.go index 7b5f2e37410..9b56a0540cd 100644 --- a/packetbeat/protos/tls/extensions_test.go +++ b/packetbeat/protos/tls/extensions_test.go @@ -157,3 +157,74 @@ func TestParseSrp(t *testing.T) { r = parseSrp(*mkBuf(t, "FF726f6f74", 5)) assert.Nil(t, r) } + +func TestParseSupportedVersions(t *testing.T) { + for _, testCase := range []struct { + title string + data string + expected interface{} + }{ + { + title: "negotiation", + data: "080304030303020301", + expected: []string{"TLS 1.3", "TLS 1.2", "TLS 1.1", "TLS 1.0"}, + }, + { + title: "negotiation with GREASE", + data: "0c7a7a0304030303020301fafa", + expected: []string{"TLS 1.3", "TLS 1.2", "TLS 1.1", "TLS 1.0"}, + }, + { + title: "selected TLS 1.3", + data: "0304", + expected: "TLS 1.3", + }, + { + title: "selected future version", + data: "0305", + expected: "TLS 1.4", + }, + { + title: "empty error", + data: "00", + }, + { + title: "odd length error", + data: "0b7a7a0304030303020301FF", + }, + { + title: "out of bounds", + data: "FF", + }, + { + title: "out of bounds (2)", + data: "805a5a03040302", + }, + { + title: "valid excess data", + data: "0403030304FFFFFFFFFFFFFF", + expected: []string{"TLS 1.2", "TLS 1.3"}, + }, + } { + t.Run(testCase.title, func(t *testing.T) { + r := parseSupportedVersions(*mkBuf(t, testCase.data, len(testCase.data)/2)) + if testCase.expected == nil { + assert.Nil(t, r, testCase.data) + return + } + switch v := testCase.expected.(type) { + case string: + version, ok := r.(string) + assert.True(t, ok) + assert.Equal(t, v, version) + case []string: + list, ok := r.([]string) + assert.True(t, ok) + assert.Len(t, list, len(v)) + assert.Equal(t, v, list) + default: + assert.Fail(t, "wrong expected type", v) + } + }) + } +} diff --git a/packetbeat/protos/tls/tls.go b/packetbeat/protos/tls/tls.go index 5e0ea77452f..a06185e469d 100644 --- a/packetbeat/protos/tls/tls.go +++ b/packetbeat/protos/tls/tls.go @@ -347,6 +347,24 @@ func (plugin *tlsPlugin) createEvent(conn *tlsConnectionData) beat.Event { if len(fingerprints) > 0 { tls["fingerprints"] = fingerprints } + + // TLS version in use + if conn.handshakeCompleted > 1 { + var version string + if serverHello != nil { + var ok bool + if value, exists := serverHello.extensions.Parsed["supported_versions"]; exists { + version, ok = value.(string) + } + if !ok { + version = serverHello.version.String() + } + } else if clientHello != nil { + version = clientHello.version.String() + } + tls["version"] = version + } + fields := common.MapStr{ "type": "tls", "status": status, diff --git a/packetbeat/protos/tls/tls_test.go b/packetbeat/protos/tls/tls_test.go index 4eca6e68467..7e75b0a066f 100644 --- a/packetbeat/protos/tls/tls_test.go +++ b/packetbeat/protos/tls/tls_test.go @@ -40,6 +40,18 @@ type eventStore struct { const ( expectedClientHello = `{"dst":{"IP":"192.168.0.2","Port":27017,"Name":"","Cmdline":"","Proc":""},"server":"example.org","src":{"IP":"192.168.0.1","Port":6512,"Name":"","Cmdline":"","Proc":""},"status":"Error","tls":{"client_certificate_requested":false,"client_hello":{"extensions":{"_unparsed_":["renegotiation_info","23","status_request","18","30032"],"application_layer_protocol_negotiation":["h2","http/1.1"],"ec_points_formats":["uncompressed"],"server_name_indication":["example.org"],"session_ticket":"","signature_algorithms":["ecdsa_secp256r1_sha256","rsa_pss_sha256","rsa_pkcs1_sha256","ecdsa_secp384r1_sha384","rsa_pss_sha384","rsa_pkcs1_sha384","rsa_pss_sha512","rsa_pkcs1_sha512","rsa_pkcs1_sha1"],"supported_groups":["x25519","secp256r1","secp384r1"]},"supported_ciphers":["TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256","TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256","TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384","TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384","TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256","TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256","TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA","TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA","TLS_RSA_WITH_AES_128_GCM_SHA256","TLS_RSA_WITH_AES_256_GCM_SHA384","TLS_RSA_WITH_AES_128_CBC_SHA","TLS_RSA_WITH_AES_256_CBC_SHA","TLS_RSA_WITH_3DES_EDE_CBC_SHA"],"supported_compression_methods":["NULL"],"version":"3.3"},"fingerprints":{"ja3":{"hash":"94c485bca29d5392be53f2b8cf7f4304","str":"771,49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53-10,65281-0-23-35-13-5-18-16-30032-11-10,29-23-24,0"}},"handshake_completed":false,"resumed":false},"type":"tls"}` expectedServerHello = `{"extensions":{"_unparsed_":["renegotiation_info","status_request"],"application_layer_protocol_negotiation":["h2"],"ec_points_formats":["uncompressed","ansiX962_compressed_prime","ansiX962_compressed_char2"],"session_ticket":""},"selected_cipher":"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256","selected_compression_method":"NULL","version":"3.3"}` + rawClientHello = "16030100c2010000be03033367dfae0d46ec0651e49cca2ae47317e8989df710" + + "ee7570a88b9a7d5d56b3af00001c3a3ac02bc02fc02cc030cca9cca8c013c014" + + "009c009d002f0035000a01000079dada0000ff0100010000000010000e00000b" + + "6578616d706c652e6f72670017000000230000000d0014001204030804040105" + + "0308050501080606010201000500050100000000001200000010000e000c0268" + + "3208687474702f312e3175500000000b00020100000a000a00086a6a001d0017" + + "0018aaaa000100" + rawServerHello = "160303004a0200004603037806e1be0c363bcc1fe14a906d1ff1b11dc5369d91" + + "c631ed660d6c0f156f420700c02f00001eff01000100000b0004030001020023" + + "000000050000001000050003026832" + + rawChangeCipherSpec = "1403030000" ) func (e *eventStore) publish(event beat.Event) { @@ -148,14 +160,7 @@ func TestInvalidAlert(t *testing.T) { func TestClientHello(t *testing.T) { results, tls := testInit() - reqData, err := hex.DecodeString( - "16030100c2010000be03033367dfae0d46ec0651e49cca2ae47317e8989df710" + - "ee7570a88b9a7d5d56b3af00001c3a3ac02bc02fc02cc030cca9cca8c013c014" + - "009c009d002f0035000a01000079dada0000ff0100010000000010000e00000b" + - "6578616d706c652e6f72670017000000230000000d0014001204030804040105" + - "0308050501080606010201000500050100000000001200000010000e000c0268" + - "3208687474702f312e3175500000000b00020100000a000a00086a6a001d0017" + - "0018aaaa000100") + reqData, err := hex.DecodeString(rawClientHello) assert.Nil(t, err) tcpTuple := testTCPTuple() @@ -178,10 +183,7 @@ func TestClientHello(t *testing.T) { func TestServerHello(t *testing.T) { results, tls := testInit() - reqData, err := hex.DecodeString( - "160303004a0200004603037806e1be0c363bcc1fe14a906d1ff1b11dc5369d91" + - "c631ed660d6c0f156f420700c02f00001eff01000100000b0004030001020023" + - "000000050000001000050003026832") + reqData, err := hex.DecodeString(rawServerHello) assert.Nil(t, err) tcpTuple := testTCPTuple() @@ -319,7 +321,7 @@ func TestCompletedHandshake(t *testing.T) { assert.Empty(t, results.events) // Then a change cypher spec message - reqData, err = hex.DecodeString("1403030000") + reqData, err = hex.DecodeString(rawChangeCipherSpec) req = protos.Packet{Payload: reqData} private = tls.Parse(&req, tcpTuple, 0, private) assert.NotNil(t, private) @@ -331,3 +333,98 @@ func TestCompletedHandshake(t *testing.T) { assert.NotEmpty(t, results.events) } + +func TestTLS13VersionNegotiation(t *testing.T) { + results, tls := testInit() + + // First, a client hello + reqData, err := hex.DecodeString( + "16030102310100022d03039b9e3d533312e698bdc35c8d86902204c0f2505682" + + "2e0ae66b5f7bff999a7c6220944f9b7806d887e27500dc6a05cfed8becf3d65a" + + "9a75ab618828f1b9e418d16800222a2a130113021303c02bc02fc02cc030cca9" + + "cca8c013c014009c009d002f0035000a010001c2baba0000ff01000100000000" + + "1d001b000018746c7331332e63727970746f2e6d6f7a696c6c612e6f72670017" + + "000000230000000d001400120403080404010503080505010806060102010005" + + "00050100000000001200000010000e000c02683208687474702f312e31755000" + + "00000b000201000033002b00292a2a000100001d00208c80626064298b32ef53" + + "5d9305355e992b98baaa5db28e22a718741eab108d48002d00020101002b000b" + + "0a9a9a0304030303020301000a000a00082a2a001d00170018001b0003020002" + + "6a6a000100002900ed00c800c21f81d2ec6041f6cecd60949000000000784b0a" + + "740ce3334a066d552e3d94af270080b67e1a29ea0e6dbccdbe6ea8699cda3e28" + + "94f98dbea2fa3b1040acdf8dd3f7edefed8f768a6076a034b63c9464e9a22301" + + "1d6ef9ff0f8ce74e7a5701da7f957116b5a3c0600541f86fb00ca54dc9f4eaec" + + "6a657331881c1fcd23c59cca16d27af51a71301c38870de721382175d3de8423" + + "d809edfcd417861a3ca83e40cf631616e0791efbcc79a0fdfe0d57c6ede4dd4f" + + "8dc54cdb7904a8924f10c55f97e5fcc1f813e6002120720c822a09c99a10b09e" + + "de25dded2e4c62eff486bf7827f89613f3038d5a200a") + assert.Nil(t, err) + tcpTuple := testTCPTuple() + req := protos.Packet{Payload: reqData} + var private protos.ProtocolData + + private = tls.Parse(&req, tcpTuple, 0, private) + assert.NotNil(t, private) + assert.Empty(t, results.events) + + // Then a server hello + change cypher spec + reqData, err = hex.DecodeString( + "160303007a020000760303225084578024a693566bc71ba223826eeffc875b20" + + "27eec7337bf5fdf0eb1de720944f9b7806d887e27500dc6a05cfed8becf3d65a" + + "9a75ab618828f1b9e418d168130100002e00330024001d002070b27700b360aa" + + "3941a22da86901c00e174dc3d83e13cf4159b34b3de6809372002b0002030414" + + "0303000101") + req = protos.Packet{Payload: reqData} + private = tls.Parse(&req, tcpTuple, 1, private) + assert.NotNil(t, private) + assert.Empty(t, results.events) + + // Then a change cypher spec from the client + reqData, err = hex.DecodeString(rawChangeCipherSpec) + req = protos.Packet{Payload: reqData} + private = tls.Parse(&req, tcpTuple, 0, private) + assert.NotNil(t, private) + assert.NotEmpty(t, results.events) + + iVersion, err := results.events[0].Fields.GetValue("tls.version") + assert.Nil(t, err) + + version, ok := iVersion.(string) + assert.True(t, ok) + assert.Equal(t, "TLS 1.3", version) +} + +func TestLegacyVersionNegotiation(t *testing.T) { + results, tls := testInit() + + // First, a client hello + reqData, err := hex.DecodeString(rawClientHello) + assert.Nil(t, err) + tcpTuple := testTCPTuple() + req := protos.Packet{Payload: reqData} + var private protos.ProtocolData + + private = tls.Parse(&req, tcpTuple, 0, private) + assert.NotNil(t, private) + assert.Empty(t, results.events) + + // Then a server hello + change cypher spec + reqData, err = hex.DecodeString(rawServerHello + rawChangeCipherSpec) + req = protos.Packet{Payload: reqData} + private = tls.Parse(&req, tcpTuple, 1, private) + assert.NotNil(t, private) + assert.Empty(t, results.events) + + // Then a change cypher spec from the client + reqData, err = hex.DecodeString(rawChangeCipherSpec) + req = protos.Packet{Payload: reqData} + private = tls.Parse(&req, tcpTuple, 0, private) + assert.NotNil(t, private) + assert.NotEmpty(t, results.events) + + iVersion, err := results.events[0].Fields.GetValue("tls.version") + assert.Nil(t, err) + + version, ok := iVersion.(string) + assert.True(t, ok) + assert.Equal(t, "TLS 1.2", version) +}