in packetbeat/protos/tls/tls.go [256:470]
func (plugin *tlsPlugin) createEvent(conn *tlsConnectionData) beat.Event {
status := common.OK_STATUS
if conn.handshakeCompleted < 2 {
status = common.ERROR_STATUS
}
emptyStream := &stream{}
client := conn.streams[0]
server := conn.streams[1]
if client == nil {
client = emptyStream
}
if server == nil {
server = emptyStream
}
if client.parser.direction == dirServer || server.parser.direction == dirClient {
client, server = server, client
}
tls := ecs.Tls{
Established: conn.handshakeCompleted > 1,
}
detailed := mapstr.M{}
emptyHello := &helloMessage{}
var clientHello, serverHello *helloMessage
if client.parser.hello != nil {
clientHello = client.parser.hello
detailed["client_hello"] = clientHello.toMap()
tls.ClientJa3, _ = getJa3Fingerprint(clientHello)
tls.ClientSupportedCiphers = clientHello.supportedCiphers()
} else {
clientHello = emptyHello
}
if server.parser.hello != nil {
serverHello = server.parser.hello
detailed["server_hello"] = serverHello.toMap()
tls.ServerJa3s, _ = getJa3Fingerprint(serverHello)
tls.Cipher = serverHello.selected.cipherSuite.String()
} else {
serverHello = emptyHello
}
if server.parser.ocspResponseIsValid {
detailed["ocsp_response"] = server.parser.ocspResponse.String()
}
if plugin.sendCertificates {
if cert, chain := plugin.getCerts(client.parser.certificates); cert != nil {
detailed["client_certificate"] = cert
if chain != nil {
detailed["client_certificate_chain"] = chain
}
}
if cert, chain := plugin.getCerts(server.parser.certificates); cert != nil {
detailed["server_certificate"] = cert
if chain != nil {
detailed["server_certificate_chain"] = chain
}
}
}
if plugin.includeRawCertificates {
tls.ClientCertificateChain = getPEMCertChain(client.parser.certificates)
tls.ServerCertificateChain = getPEMCertChain(server.parser.certificates)
}
if list := client.parser.certificates; len(list) > 0 {
cert := list[0]
hashCert(cert, plugin.fingerprints, map[string]*string{
"md5": &tls.ClientHashMd5,
"sha1": &tls.ClientHashSha1,
"sha256": &tls.ClientHashSha256,
})
tls.ClientSubject = cert.Subject.String()
tls.ClientIssuer = cert.Issuer.String()
tls.ClientNotAfter = cert.NotAfter
tls.ClientNotBefore = cert.NotBefore
}
if list := server.parser.certificates; len(list) > 0 {
cert := list[0]
hashCert(cert, plugin.fingerprints, map[string]*string{
"md5": &tls.ServerHashMd5,
"sha1": &tls.ServerHashSha1,
"sha256": &tls.ServerHashSha256,
})
tls.ServerSubject = cert.Subject.String()
tls.ServerIssuer = cert.Issuer.String()
tls.ServerNotAfter = cert.NotAfter
tls.ServerNotBefore = cert.NotBefore
}
detailed["client_certificate_requested"] = server.parser.certRequested
// It is a bit tricky to detect the mechanism used for a resumed session. If the client offered a ticket, then
// ticket is assumed as the method used for resumption even when a session ID is also used (as RFC-5077 requires).
// It is not possible to tell whether the server accepted the ticket or the session ID.
sessionIDMatch := len(clientHello.sessionID) != 0 && clientHello.sessionID == serverHello.sessionID
ticketOffered := len(clientHello.ticket.value) != 0 && serverHello.ticket.present
resumed := !client.parser.keyExchanged && !server.parser.keyExchanged && (sessionIDMatch || ticketOffered)
tls.Resumed = resumed
if resumed {
if ticketOffered {
detailed["resumption_method"] = "ticket"
} else {
detailed["resumption_method"] = "id"
}
}
numAlerts := len(client.parser.alerts) + len(server.parser.alerts)
alerts := make([]mapstr.M, 0, numAlerts)
alertTypes := make([]string, 0, numAlerts)
for _, alert := range client.parser.alerts {
alerts = append(alerts, alert.toMap("client"))
alertTypes = append(alertTypes, alert.code.String())
}
for _, alert := range server.parser.alerts {
alerts = append(alerts, alert.toMap("server"))
alertTypes = append(alertTypes, alert.code.String())
}
if numAlerts != 0 {
detailed["alerts"] = alerts
detailed["alert_types"] = alertTypes
}
src := &common.Endpoint{}
dst := &common.Endpoint{}
tcptuple := client.tcptuple
if tcptuple == nil {
tcptuple = server.tcptuple
}
cmdlineTuple := client.cmdlineTuple
if cmdlineTuple == nil {
cmdlineTuple = server.cmdlineTuple
}
if tcptuple != nil && cmdlineTuple != nil {
source, destination := common.MakeEndpointPair(tcptuple.BaseTuple, cmdlineTuple)
src, dst = &source, &destination
}
// TLS version in use
var version tlsVersion
if !serverHello.version.IsZero() {
var ok bool
var raw []byte
const supportedVersionsExt = 43
if raw, ok = serverHello.extensions.Raw[supportedVersionsExt]; ok {
version.major = raw[0]
version.minor = raw[1]
}
if !ok {
version = serverHello.version
}
} else if !clientHello.version.IsZero() {
version = clientHello.version
}
detailed["version"] = version.String()
pVer := version.GetProtocolVersion()
tls.VersionProtocol, tls.Version = pVer.Protocol, pVer.Version
evt, pbf := pb.NewBeatEvent(conn.startTime)
pbf.SetSource(src)
pbf.SetDestination(dst)
pbf.Event.Start = conn.startTime
pbf.Event.End = conn.endTime
pbf.Network.Transport = "tcp"
pbf.Network.Protocol = "tls"
fields := evt.Fields
fields["type"] = pbf.Network.Protocol
fields["status"] = status
// set "server.domain" to SNI, if provided
if value, ok := clientHello.extensions.Parsed["server_name_indication"]; ok {
if list, ok := value.([]string); ok && len(list) > 0 {
pbf.Destination.Domain = list[0]
tls.ClientServerName = list[0]
}
}
// set next protocol from server's ALPN extension
if value, ok := serverHello.extensions.Parsed["application_layer_protocol_negotiation"]; ok {
if list, ok := value.([]string); ok && len(list) > 0 {
tls.NextProtocol = list[0]
}
}
// Serialize ECS TLS fields
pb.MarshalStruct(fields, "tls", tls)
if plugin.includeDetailedFields {
if cert, ok := detailed["client_certificate"]; ok {
fields.Put("tls.client.x509", cert)
detailed.Delete("client_certificate")
}
if cert, ok := detailed["server_certificate"]; ok {
fields.Put("tls.server.x509", cert)
detailed.Delete("server_certificate")
}
fields.Put("tls.detailed", detailed)
}
if len(tls.ServerCertificateChain) > 0 {
fields.Put("tls.server.certificate_chain", tls.ServerCertificateChain)
}
if len(tls.ClientCertificateChain) > 0 {
fields.Put("tls.client.certificate_chain", tls.ClientCertificateChain)
}
if len(tls.ClientSupportedCiphers) > 0 {
fields.Put("tls.client.supported_ciphers", tls.ClientSupportedCiphers)
}
// Enforce booleans (not serialized when false)
if !tls.Established {
fields.Put("tls.established", tls.Established)
}
if !tls.Resumed {
fields.Put("tls.resumed", tls.Resumed)
}
return evt
}