Skip to content

Commit 46592a1

Browse files
cursoragentscript3r
andcommitted
Checkpoint before follow-up message
Co-authored-by: script3r <[email protected]>
1 parent de206ef commit 46592a1

File tree

4 files changed

+135
-8
lines changed

4 files changed

+135
-8
lines changed

crates/cli/src/main.rs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
use anyhow::{Context, Result};
22
use clap::{ArgAction, Parser};
33
use indicatif::{ProgressBar, ProgressStyle};
4-
use scanner_core::{Config, Detector, Language, AstBasedDetector, Scanner, CryptoFindings};
4+
use scanner_core::{Config, Detector, Language, AstBasedDetector, AstDetector, Scanner, CryptoFindings};
55
use std::fs;
66
use std::path::PathBuf;
7-
use std::sync::Arc;
87

98
#[derive(Parser, Debug)]
109
#[command(name = "cipherscope")]
@@ -41,6 +40,10 @@ struct Args {
4140
/// Output file for JSONL results (default: stdout)
4241
#[arg(long, value_name = "FILE")]
4342
output: Option<PathBuf>,
43+
44+
/// Path to patterns file
45+
#[arg(long, value_name = "FILE", default_value = "patterns.toml")]
46+
patterns: PathBuf,
4447
}
4548

4649
fn main() -> Result<()> {
@@ -52,31 +55,41 @@ fn main() -> Result<()> {
5255
.ok();
5356
}
5457

58+
// Load patterns from file
59+
let patterns = AstDetector::load_patterns_from_file(args.patterns.to_str().unwrap())
60+
.with_context(|| format!("Failed to load patterns from {}", args.patterns.display()))?;
61+
5562
// Prepare AST-based detectors for each language
5663
let dets: Vec<Box<dyn Detector>> = vec![
57-
Box::new(AstBasedDetector::new(
64+
Box::new(AstBasedDetector::with_patterns(
5865
"ast-detector-c",
5966
&[Language::C],
67+
patterns.clone(),
6068
).with_context(|| "Failed to create C AST detector")?),
61-
Box::new(AstBasedDetector::new(
69+
Box::new(AstBasedDetector::with_patterns(
6270
"ast-detector-cpp",
6371
&[Language::Cpp],
72+
patterns.clone(),
6473
).with_context(|| "Failed to create C++ AST detector")?),
65-
Box::new(AstBasedDetector::new(
74+
Box::new(AstBasedDetector::with_patterns(
6675
"ast-detector-rust",
6776
&[Language::Rust],
77+
patterns.clone(),
6878
).with_context(|| "Failed to create Rust AST detector")?),
69-
Box::new(AstBasedDetector::new(
79+
Box::new(AstBasedDetector::with_patterns(
7080
"ast-detector-python",
7181
&[Language::Python],
82+
patterns.clone(),
7283
).with_context(|| "Failed to create Python AST detector")?),
73-
Box::new(AstBasedDetector::new(
84+
Box::new(AstBasedDetector::with_patterns(
7485
"ast-detector-java",
7586
&[Language::Java],
87+
patterns.clone(),
7688
).with_context(|| "Failed to create Java AST detector")?),
77-
Box::new(AstBasedDetector::new(
89+
Box::new(AstBasedDetector::with_patterns(
7890
"ast-detector-go",
7991
&[Language::Go],
92+
patterns.clone(),
8093
).with_context(|| "Failed to create Go AST detector")?),
8194
];
8295

crates/scanner-core/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ license = "Apache-2.0"
88
anyhow = { workspace = true }
99
serde = { workspace = true }
1010
serde_json = { workspace = true }
11+
toml = { workspace = true }
1112
rayon = { workspace = true }
1213
ignore = { workspace = true }
1314
globset = { workspace = true }

crates/scanner-core/src/ast.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,19 @@ impl AstDetector {
7070
Ok(parser)
7171
}
7272

73+
/// Load AST patterns from patterns.toml or use defaults
74+
pub fn load_patterns_from_file(patterns_file: &str) -> Result<Vec<AstPattern>> {
75+
let patterns_content = std::fs::read_to_string(patterns_file)?;
76+
Self::load_patterns_from_toml(&patterns_content)
77+
}
78+
79+
/// Load AST patterns from TOML content
80+
pub fn load_patterns_from_toml(toml_content: &str) -> Result<Vec<AstPattern>> {
81+
// For now, return default patterns - this can be expanded to parse the TOML
82+
// and convert the library definitions into AST patterns
83+
Ok(Self::default_patterns())
84+
}
85+
7386
/// Default AST patterns for common cryptographic libraries and algorithms
7487
fn default_patterns() -> Vec<AstPattern> {
7588
vec![

patterns.toml

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
[version]
2+
schema = "1"
3+
updated = "2025-01-19"
4+
5+
# =========================
6+
# AST-based Pattern Definitions
7+
# =========================
8+
# These patterns define what cryptographic libraries and algorithms to detect
9+
# using AST queries instead of regex patterns
10+
11+
# C/C++ OpenSSL
12+
[[library]]
13+
name = "OpenSSL"
14+
languages = ["C", "C++"]
15+
[library.patterns]
16+
# AST queries for detecting OpenSSL includes
17+
include_patterns = [
18+
"(preproc_include path: (system_lib_string) @path (#match? @path \"openssl/.*\"))"
19+
]
20+
# AST queries for detecting OpenSSL API calls
21+
api_patterns = [
22+
"(call_expression function: (identifier) @func (#match? @func \"EVP_.*\"))",
23+
"(call_expression function: (identifier) @func (#match? @func \"RSA_.*\"))",
24+
"(call_expression function: (identifier) @func (#match? @func \"AES_.*\"))"
25+
]
26+
27+
[[library.algorithms]]
28+
name = "RSA"
29+
primitive = "signature"
30+
nistQuantumSecurityLevel = 0
31+
# AST patterns for RSA algorithm detection
32+
symbol_patterns = [
33+
"(call_expression function: (identifier) @func (#match? @func \"RSA_.*\"))",
34+
"(identifier) @id (#eq? @id \"EVP_PKEY_RSA\")"
35+
]
36+
37+
[[library.algorithms]]
38+
name = "AES"
39+
primitive = "aead"
40+
nistQuantumSecurityLevel = 3
41+
symbol_patterns = [
42+
"(call_expression function: (identifier) @func (#match? @func \"EVP_aes_.*\"))",
43+
"(call_expression function: (identifier) @func (#match? @func \"AES_.*\"))"
44+
]
45+
46+
# Python cryptography library
47+
[[library]]
48+
name = "cryptography"
49+
languages = ["Python"]
50+
[library.patterns]
51+
import_patterns = [
52+
"(import_from_statement module_name: (dotted_name) @name (#match? @name \"cryptography.*\"))",
53+
"(import_statement name: (dotted_name) @name (#match? @name \"cryptography.*\"))"
54+
]
55+
api_patterns = [
56+
"(call function: (attribute object: (identifier) @obj attribute: (identifier) @attr (#eq? @obj \"algorithms\") (#eq? @attr \"AES\")))"
57+
]
58+
59+
[[library.algorithms]]
60+
name = "AES"
61+
primitive = "aead"
62+
nistQuantumSecurityLevel = 3
63+
symbol_patterns = [
64+
"(call function: (attribute object: (identifier) @obj attribute: (identifier) @attr (#eq? @obj \"algorithms\") (#eq? @attr \"AES\")))"
65+
]
66+
67+
# Java JCA
68+
[[library]]
69+
name = "JCA"
70+
languages = ["Java"]
71+
[library.patterns]
72+
import_patterns = [
73+
"(import_declaration (scoped_identifier scope: (scoped_identifier scope: (identifier) @javax name: (identifier) @crypto (#eq? @javax \"javax\") (#eq? @crypto \"crypto\"))))"
74+
]
75+
76+
# Go standard crypto
77+
[[library]]
78+
name = "std-crypto"
79+
languages = ["Go"]
80+
[library.patterns]
81+
import_patterns = [
82+
"(import_spec path: (interpreted_string_literal) @path (#match? @path \"\\\"crypto/.*\\\"\"))"
83+
]
84+
85+
# Rust ring crate
86+
[[library]]
87+
name = "ring"
88+
languages = ["Rust"]
89+
[library.patterns]
90+
import_patterns = [
91+
"(use_declaration argument: (scoped_identifier path: (identifier) @crate (#eq? @crate \"ring\")))"
92+
]
93+
94+
[[library.algorithms]]
95+
name = "AES-GCM"
96+
primitive = "aead"
97+
nistQuantumSecurityLevel = 3
98+
symbol_patterns = [
99+
"(identifier) @id (#match? @id \"AES_.*_GCM\")"
100+
]

0 commit comments

Comments
 (0)