func()

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
}