Skip to content

Commit

Permalink
JA4: Take sig_hash_alg values from signature_algorithms extension…
Browse files Browse the repository at this point in the history
… only

Related issue: #41
  • Loading branch information
vvv committed Jan 4, 2024
1 parent b3a81d9 commit 274cfcc
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 20 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ jobs:
# Specify `--manifest-path` as a workaround.
#
# See https://github.com/actions-rs/clippy-check/issues/28
args: --all-features --workspace --manifest-path rust/Cargo.toml
args: --all-features --workspace --manifest-path rust/Cargo.toml -- -D warnings
token: ${{ secrets.GITHUB_TOKEN }}

doc:
Expand Down
Binary file added pcap/tls12.pcap
Binary file not shown.
6 changes: 5 additions & 1 deletion rust/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.16.2] - 2024-01-04

### Fixed

- JA4: Include SNI (0000) and ALPN (0010) in the "original" outputs (#40).
- JA4H: Search for "Cookie" and "Referer" fields in a case-insensitive fashion.
- JA4: Take signature algorithm hex values from `signature_algorithms` extension only (#41).

## [0.16.1] - 2023-12-22

Expand Down Expand Up @@ -53,7 +56,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Add Rust sources of `ja4` and `ja4x` CLI tools.

[unreleased]: https://github.com/FoxIO-LLC/ja4/compare/v0.16.1...HEAD
[unreleased]: https://github.com/FoxIO-LLC/ja4/compare/v0.16.2...HEAD
[0.16.2]: https://github.com/FoxIO-LLC/ja4/compare/v0.16.1...v0.16.2
[0.16.1]: https://github.com/FoxIO-LLC/ja4/compare/v0.16.0...v0.16.1
[0.16.0]: https://github.com/FoxIO-LLC/ja4/compare/v0.15.2...v0.16.0
[0.15.2]: https://github.com/FoxIO-LLC/ja4/compare/v0.15.1...v0.15.2
Expand Down
4 changes: 2 additions & 2 deletions rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ members = ["ja4", "ja4x"]
resolver = "2"

[workspace.package]
version = "0.16.1"
version = "0.16.2"
license = "LicenseRef-FoxIO-Proprietary"
repository = "https://github.com/FoxIO-LLC/ja4"

Expand Down
5 changes: 5 additions & 0 deletions rust/ja4/src/pcap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ impl Proto<'_> {
self.inner.name()
}

/// Returns an iterator over all [`rtshark::Metadata`] for this protocol.
pub(crate) fn iter(&self) -> impl Iterator<Item = &rtshark::Metadata> {
self.inner.iter()
}

/// Returns an iterator over the sequence of [`rtshark::Metadata`] with the given [name].
///
/// [name]: rtshark::Metadata::name
Expand Down
13 changes: 13 additions & 0 deletions rust/ja4/src/snapshots/[email protected]
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
source: ja4/src/lib.rs
expression: output
---
- stream: 0
transport: tcp
src: 192.168.133.129
dst: 34.117.237.239
src_port: 36372
dst_port: 443
tls_server_name: contile.services.mozilla.com
ja4: t13d1715h2_5b57614c22b0_3d5424432f57

61 changes: 46 additions & 15 deletions rust/ja4/src/tls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use std::fmt;
use itertools::Itertools as _;
use ja4x::x509_parser::{certificate::X509Certificate, prelude::FromDer as _};
use serde::Serialize;
use tracing::{debug, warn};

use crate::{Error, FormatFlags, Packet, PacketNum, Proto, Result};

Expand Down Expand Up @@ -186,23 +187,13 @@ impl ClientStats {
let alpn = tls
.first("tls.handshake.extensions_alpn_str")
.map_or((None, None), first_last);
let sig_hash_algs = tls
.values("tls.handshake.sig_hash_alg")
.filter_map(|v| {
let s = v.strip_prefix("0x");
if s.is_none() {
tracing::debug!(sig_hash_alg = v, %pkt.num, "Invalid signature algorithm");
}
s.map(str::to_owned)
})
.collect();
let ciphers = tls
.values("tls.handshake.ciphersuite")
.filter(|v| !TLS_GREASE_VALUES_STR.contains(v))
.filter_map(|v| {
let s = v.strip_prefix("0x");
if s.is_none() {
tracing::debug!(cipher = v, %pkt.num, "Invalid cipher suite");
debug!(cipher = v, %pkt.num, "Invalid cipher suite");
}
s.map(str::to_owned)
})
Expand All @@ -215,7 +206,7 @@ impl ClientStats {
exts,
sni,
alpn,
sig_hash_algs,
sig_hash_algs: sig_hash_algs(pkt, tls),
})
}

Expand Down Expand Up @@ -254,6 +245,46 @@ impl ClientStats {
}
}

/// Returns hex values of the signature algorithms.
fn sig_hash_algs(pkt: &Packet, tls: &Proto) -> Vec<String> {
assert_eq!(tls.name(), "tls");

// `signature_algorithms` is not the only TLS extension that contains
// `tls.handshake.sig_hash_alg` fields. For example, `delegated_credentials`
// contains them too; see https://github.com/FoxIO-LLC/ja4/issues/41
//
// We are only interested in `signature_algorithms` extension, so we skip forward
// to it.
let mut iter = tls
.iter()
.skip_while(|&md| md.name() != "tls.handshake.extension.type" || md.value() != "13");
match iter.next() {
Some(md) => debug_assert_eq!(md.display(), "Type: signature_algorithms (13)"),
None => {
debug!(%pkt.num, "signature_algorithms TLS extension not found");
return Vec::new();
}
}
match iter.next() {
Some(md) => debug_assert_eq!(md.name(), "tls.handshake.extension.len"),
None => {
warn!(%pkt.num, "Unexpected end of TLS dissection");
return Vec::new();
}
}

iter.take_while(|&md| md.name().starts_with("tls.handshake.sig_hash_"))
.filter(|&md| md.name() == "tls.handshake.sig_hash_alg")
.filter_map(|md| {
let s = md.value().strip_prefix("0x");
if s.is_none() {
warn!(%pkt.num, ?md, "signature algorithm value doesn't start with \"0x\"");
}
s.map(str::to_owned)
})
.collect()
}

/// Pieces of data that is used to construct [`Ja4Fingerprint`] and [`Ja4RawFingerprint`].
#[derive(Debug)]
struct PartsOfClientFingerprint {
Expand Down Expand Up @@ -394,7 +425,7 @@ impl ServerStats {

let v = tls.first("tls.handshake.ciphersuite")?;
let Some(cipher) = v.strip_prefix("0x") else {
tracing::debug!(cipher = v, %pkt.num, "Invalid cipher suite");
debug!(cipher = v, %pkt.num, "Invalid cipher suite");
return Ok(None);
};

Expand Down Expand Up @@ -563,7 +594,7 @@ fn tls_extensions_client(tls: &Proto) -> Vec<u16> {
Ok(n) if TLS_GREASE_VALUES_INT.contains(&n) => None,
Ok(n) => Some(n),
Err(error) => {
tracing::debug!(packet = %tls.packet_num, value = md.value(), showname = md.display(), %error, "Invalid TLS extension");
debug!(packet = %tls.packet_num, value = md.value(), showname = md.display(), %error, "Invalid TLS extension");
None
}
}
Expand All @@ -579,7 +610,7 @@ fn tls_extensions_server(tls: &Proto) -> Vec<u16> {

tls.fields("tls.handshake.extension.type").filter_map(|md| {
md.value().parse::<u16>().map_err(|e| {
tracing::debug!(packet = %tls.packet_num, value = md.value(), showname = md.display(), error = %e, "Invalid TLS extension");
debug!(packet = %tls.packet_num, value = md.value(), showname = md.display(), error = %e, "Invalid TLS extension");
}).ok()
})
.collect()
Expand Down

0 comments on commit 274cfcc

Please sign in to comment.