Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TLS module for packetbeat #5476

Merged
merged 13 commits into from
Nov 14, 2017
Merged

TLS module for packetbeat #5476

merged 13 commits into from
Nov 14, 2017

Conversation

adriansr
Copy link
Contributor

@adriansr adriansr commented Oct 30, 2017

This patch adds TLS protocol support to Packetbeat.

It will parse the initial handshake and send an event to Elasticsearch for every TLS connection.

Events contain:

  • ciphers supported by client
  • cipher selected by server
  • extensions
  • client and server certificate chain (if any)
    • key algorithm
    • signing algorithm
    • subject alternative name (SAN)
    • validity dates
  • whether the session is resumed using session IDs or tickets
  • alert (if any)

There is support for Application Layer Protocol Negotiation (ALPN) extension to TLS. It parses extension data found in hello messages. This involves a list of protocols in the client hello:

"application_layer_protocol_negotiation": "h2,http/1.1"

And the selected protocol in the server hello.

"application_layer_protocol_negotiation": "h2"

References

ALPN: https://en.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation

@adriansr adriansr added in progress Pull request is currently in progress. Packetbeat labels Oct 30, 2017
@adriansr
Copy link
Contributor Author

Please review when you have time. It is a work in progress (working on the tests now)

Copy link
Member

@andrewkroh andrewkroh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are making good progress. Things look good so far to me. I'll take another look when you get closer to done.

- name: tls
type: group
fields:
- name: negotiated cypher
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This field name has a space in it. Probably you want an underscore here. But it looks like this file is progress because I don't see this field in the code so I'm sure you be updating all of this.

return m
}

func (parser *parser) parse(buf *streambuf.Buffer, conn *tlsConnectionData, plugin *tlsPlugin) (bool, bool) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try not to introduce circular dependencies in any way. At optimium the parser must be testable without requiring an instance of tlsPlugin. This simplifies potential unit and/or fuzzy testing of the parser only.

The TCP code generate creates different types with different responsibilities on purpose. One type per task like: manage connections, parse, correlate messages, create events, publish events


func (parser *parser) parse(buf *streambuf.Buffer, conn *tlsConnectionData, plugin *tlsPlugin) (bool, bool) {

if conn.handshakeCompleted {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Abstraction leak. The parser should be about parsing messages from receive buffer only. The parser should not have to care about the connection state if possible.

  2. if connection is 'completed' and there is nothing new to learn during the lifetime of the connect, clear the buffers more early and consider not appending to the buffer again. This will make the module much more lightweight.

switch header.recordType {
case recordTypeChangeCipherSpec: // single message of size 1 (byte 1)
conn.handshakeCompleted = true
plugin.sendEvent(conn)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Abstraction leak. Parser should not directly trigger an event, depending on potential connection state. Instead parser should return/report messages only.

return true
}

func (parser *parser) processHandshake(conn *tlsConnectionData, handshakeType handshakeType, reader bufferView) bool {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a task for the message 'correlator'. Note, depending on deployment (e.g. port forwarding), packetbeat might potentially see packets out of order.

@urso
Copy link

urso commented Nov 2, 2017

Nice progress. Can't wait for finally having TLS envelope support 🎉

@adriansr
Copy link
Contributor Author

adriansr commented Nov 6, 2017

Will update with correct fields.yml

@adriansr adriansr added review and removed in progress Pull request is currently in progress. labels Nov 6, 2017
return nil
}

certs := make([]*x509.Certificate, 0)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can probably use "var certs []*x509.Certificate" instead

return nil
}

certs := make([]*x509.Certificate, 0)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can probably use "var certs []*x509.Certificate" instead

- name: timestamp
type: long
description: >
The current time and date in standard UNIX 32-bit format
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this seconds since Unix epoch? Either way I suggest converting it to a date rather than a long so that’s easier to use in ES.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. Will do

fields:
- name: server_name_indication
type: string
description: Comma-separated list of server names
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of comma separated, I think a list would be better for searching and aggregating.

- name: session_ticket
type: string
description: >
Length of the session ticket, if provided, or empty
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

“or empty” - does this mean the field is not sent when a value is not present?


- name: session_ticket
type: string
description: Empty
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please clarify here.

description: X509 format version.

- name: serial_number
type: keyword
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the some benefits to sending this as a keyword rather than a long? Will users be expecting to see hex? Maybe we should have a field formater in Kibana for hex (possibly there is one; I didn’t check).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The serial number can be up to 160 bits long so it doesn't fit on a numeric type.

I have changed the format to decimal. The most common way of representation seems to be decimal up to 64 bit in length and then hexadecimal number or hex dump of individual bytes. I will stick with decimal in a keyword field.

This patch adds TLS protocol support for packetbeat.

It will parse the initial handshake and send to Elasticsearch
an event for every TLS connection.

This event contains:
- ciphers supported by client
- cipher selected by server
- extensions
- client and server certificate chain (if any)
- whether the session is resumed using session IDs or tickets
This parses the Application Layer Protocol Negotiation extension
in hello messages. This involves a list of protocols in the
client hello:

    "application_layer_protocol_negotiation": "h2,http/1.1"

And the selected protocol in the server hello.

    "application_layer_protocol_negotiation": "h2"
Both decimal and hexadecimal are used interchangeably. Unfortunately
long datatype cannot be used for the serial number as it can have a
length of up to 160 bits.
Copy link
Member

@andrewkroh andrewkroh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@andrewkroh andrewkroh merged commit 4ca792f into elastic:master Nov 14, 2017
@tsg tsg mentioned this pull request Nov 20, 2017
5 tasks
@monicasarbu monicasarbu changed the title TLS plugin for packetbeat TLS module for packetbeat Nov 20, 2017
@adriansr adriansr deleted the tls branch November 22, 2017 09:37
@monicasarbu
Copy link
Contributor

@adriansr I just realized that this PR doesn't have a changelog. I think the easiest would be if @tsg adds it to the #5853.

@tbragin tbragin mentioned this pull request Dec 29, 2017
17 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants