postquant 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +127 -19
- package/dist/scanner/classifier.js +1 -1
- package/dist/scanner/classifier.js.map +1 -1
- package/dist/scanner/openssl.d.ts +25 -0
- package/dist/scanner/openssl.d.ts.map +1 -0
- package/dist/scanner/openssl.js +115 -0
- package/dist/scanner/openssl.js.map +1 -0
- package/dist/scanner/tls.d.ts.map +1 -1
- package/dist/scanner/tls.js +44 -1
- package/dist/scanner/tls.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,23 +7,101 @@
|
|
|
7
7
|
|
|
8
8
|
PostQuant scans TLS connections and source code, reports which algorithms are vulnerable to quantum attacks, grades them A+ through F, and tells you what to migrate to. Supports Python, JavaScript/TypeScript, Go, and Java.
|
|
9
9
|
|
|
10
|
+
## What's New in v0.4.0
|
|
11
|
+
|
|
12
|
+
v0.4.0 detects hybrid post-quantum key exchanges (X25519MLKEM768) via OpenSSL probing. Cloudflare and Google both negotiate hybrid PQC — PostQuant now sees it.
|
|
13
|
+
|
|
14
|
+
## What Makes v0.3.0 Different
|
|
15
|
+
|
|
16
|
+
PostQuant doesn't just find algorithms — it understands context.
|
|
17
|
+
|
|
18
|
+
A naive scanner flags `uuid` for using MD5 and calls it critical. PostQuant reads the surrounding code, sees it's generating RFC 4122 checksums (not securing passwords), and adjusts the risk to low. The grade? **A**.
|
|
19
|
+
|
|
20
|
+
Django's `auth/hashers.py` also uses MD5 — but for password hashing. PostQuant sees the `password` and `authenticate` signals, keeps the risk at critical, and grades it **D+**.
|
|
21
|
+
|
|
22
|
+
Same algorithm. Different context. Different risk. That distinction matters.
|
|
23
|
+
|
|
24
|
+
## TLS Scan Results
|
|
25
|
+
|
|
26
|
+
We scanned major sites with PostQuant v0.4.0. Cloudflare and Google now negotiate hybrid PQC key exchange:
|
|
27
|
+
|
|
28
|
+
| Site | Grade | Certificate | Key Exchange | Cipher | Hash |
|
|
29
|
+
|------|-------|-------------|--------------|--------|------|
|
|
30
|
+
| google.com | **C+** | RSA-2048 | X25519MLKEM768 | AES-256 | SHA-384 |
|
|
31
|
+
| cloudflare.com | **C+** | ECDSA P-256 | X25519MLKEM768 | AES-256 | SHA-384 |
|
|
32
|
+
| stripe.com | **C+** | ECDSA P-256 | X25519 | AES-256 | SHA-384 |
|
|
33
|
+
| github.com | **C** | ECDSA P-256 | X25519 | AES-256 | SHA-256 |
|
|
34
|
+
|
|
35
|
+
> Scanned with PostQuant v0.4.0 on March 4, 2026. Hybrid PQC key exchange (X25519MLKEM768) is now detected via OpenSSL probing. Grade remains C+ because certificates still use classical algorithms (RSA/ECDSA) — no CA supports PQC certificates yet.
|
|
36
|
+
|
|
10
37
|
## Framework Scan Results
|
|
11
38
|
|
|
12
|
-
We scanned popular open-source frameworks with PostQuant v0.
|
|
39
|
+
We scanned popular open-source frameworks with PostQuant v0.3.0:
|
|
40
|
+
|
|
41
|
+
| Project | Language | Grade | Critical | What We Found |
|
|
42
|
+
|---------|----------|-------|----------|---------------|
|
|
43
|
+
| Django | Python | **D+** | 2 | MD5 in auth hashers, SHA-1 in file uploads |
|
|
44
|
+
| FastAPI | Python | **A** | 0 | No quantum-vulnerable crypto detected |
|
|
45
|
+
| Express | JS | **A** | 0 | No quantum-vulnerable crypto detected |
|
|
46
|
+
| Gin | Go | **A** | 0 | No quantum-vulnerable crypto detected |
|
|
47
|
+
|
|
48
|
+
> Scanned with PostQuant v0.3.0 on March 3, 2026. Run `npx postquant analyze <path>` to scan your own projects.
|
|
49
|
+
|
|
50
|
+
## Package Scan Results
|
|
51
|
+
|
|
52
|
+
We scanned popular npm and PyPI packages. Context-aware risk assessment separates real threats from protocol compliance:
|
|
53
|
+
|
|
54
|
+
### npm Packages
|
|
55
|
+
|
|
56
|
+
| Package | Grade | Raw Findings | Adjusted Risk | What We Found |
|
|
57
|
+
|---------|-------|-------------|---------------|---------------|
|
|
58
|
+
| uuid | **A** | 4 critical | 4 low | MD5/SHA-1 for RFC 4122 checksums — not security |
|
|
59
|
+
| express-session | **A** | 2 critical | 2 low | SHA-1 for integrity checks — not auth |
|
|
60
|
+
| node-forge | **C+** | 4 critical | 4 critical | RSA in encryption — intentional crypto library |
|
|
61
|
+
| pg | **D+** | 4 critical | 4 critical | MD5 in PostgreSQL auth protocol |
|
|
62
|
+
| mysql2 | **D+** | 2 critical | 2 high | SHA-1 in MySQL auth_41 protocol |
|
|
63
|
+
| ssh2 | **D+** | 18 critical | 12 critical | DH, ECDH, Ed25519 in SSH key exchange |
|
|
64
|
+
|
|
65
|
+
### Python Packages
|
|
66
|
+
|
|
67
|
+
| Package | Grade | Raw Findings | Adjusted Risk | What We Found |
|
|
68
|
+
|---------|-------|-------------|---------------|---------------|
|
|
69
|
+
| requests | **A** | 5 critical | 3 low | MD5/SHA-1 in HTTP digest auth checksums |
|
|
70
|
+
| boto3 | **A** | 1 critical | 1 informational | MD5 for S3 protocol compliance |
|
|
71
|
+
| werkzeug | **C+** | 1 critical | 1 high | RSA in dev server TLS certificate |
|
|
72
|
+
| aiohttp | **D+** | 3 critical | 2 critical | Crypto usage in client fingerprinting |
|
|
73
|
+
| django | **D+** | 2 critical | 2 critical | MD5 in auth hashers, SHA-1 in uploads |
|
|
74
|
+
| paramiko | **D-** | 10 critical | 10 critical | ECDSA, X25519, DH throughout SSH protocol |
|
|
75
|
+
|
|
76
|
+
> Scanned with PostQuant v0.3.0 on March 3, 2026. "Raw Findings" = pattern matching only. "Adjusted Risk" = after context analysis.
|
|
13
77
|
|
|
14
|
-
|
|
15
|
-
|---------|----------|-------|-------------------|---------------|
|
|
16
|
-
| Go stdlib | Go | F | 161 | ECDSA, RSA, DH throughout the crypto package |
|
|
17
|
-
| Spring Boot | Java | D+ | 7 | RSA in OAuth2 auth server, SHA-1 in DevTools |
|
|
18
|
-
| Django | Python | D+ | 7 | MD5 in auth hashers, SHA-1 in template caching |
|
|
19
|
-
| Next.js | JS | D+ | 4 | MD5 + SHA-1 in Turbopack runtime |
|
|
20
|
-
| Node.js | JS | D+ | 6 | DH + ECDH in crypto.js, SHA-1 in TLS |
|
|
21
|
-
| Flask | Python | D+ | 1 | SHA-1 in session management |
|
|
22
|
-
| FastAPI | Python | A | 0 | No quantum-vulnerable crypto detected |
|
|
23
|
-
| Express | JS | A | 0 | No quantum-vulnerable crypto detected |
|
|
24
|
-
| Gin | Go | A | 0 | No quantum-vulnerable crypto detected |
|
|
78
|
+
## Risk Assessment
|
|
25
79
|
|
|
26
|
-
|
|
80
|
+
PostQuant v0.3.0 introduces context-aware risk assessment. Instead of blindly flagging every MD5 or SHA-1 as critical, the scanner reads surrounding code to understand *how* the algorithm is being used.
|
|
81
|
+
|
|
82
|
+
**How it works:**
|
|
83
|
+
|
|
84
|
+
1. **Pattern matching** finds cryptographic algorithm usage (MD5, SHA-1, RSA, ECDSA, etc.)
|
|
85
|
+
2. **Context analysis** examines the surrounding code — file paths, variable names, function calls, API patterns
|
|
86
|
+
3. **Risk adjustment** raises or lowers the finding's severity based on context signals
|
|
87
|
+
|
|
88
|
+
**Context signals that decrease risk:**
|
|
89
|
+
- Nearby code references `checksum`, `digest`, `fingerprint`, `uuid`
|
|
90
|
+
- File paths suggest test fixtures or protocol compliance
|
|
91
|
+
- API patterns match known non-security uses (e.g., PostgreSQL MD5 auth marked as legacy-support)
|
|
92
|
+
|
|
93
|
+
**Context signals that increase risk:**
|
|
94
|
+
- Nearby code references `password`, `authenticate`, `encrypt`, `secret`
|
|
95
|
+
- File paths contain `auth/`, `security/`, `crypto/`
|
|
96
|
+
- Algorithm used for digital signatures, key exchange, or session management
|
|
97
|
+
|
|
98
|
+
**Result:** `uuid` using MD5 for checksums scores **A**. Django using MD5 for password hashing scores **D+**. Same algorithm, different risk.
|
|
99
|
+
|
|
100
|
+
To disable context analysis and use raw pattern matching only:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
npx postquant analyze . --no-context
|
|
104
|
+
```
|
|
27
105
|
|
|
28
106
|
## Why
|
|
29
107
|
|
|
@@ -58,20 +136,42 @@ Most sites today score C+ or C. That's expected — almost nobody has deployed p
|
|
|
58
136
|
|
|
59
137
|
### Code Scanner
|
|
60
138
|
|
|
61
|
-
Scan source code for quantum-vulnerable cryptographic patterns. 54 detection patterns across 4 languages (Python, JavaScript/TypeScript, Go, Java) with
|
|
139
|
+
Scan source code for quantum-vulnerable cryptographic patterns. 54 detection patterns across 4 languages (Python, JavaScript/TypeScript, Go, Java) with context-aware risk assessment.
|
|
62
140
|
|
|
63
141
|
```bash
|
|
64
142
|
# Scan your project
|
|
65
143
|
npx postquant analyze .
|
|
66
144
|
|
|
145
|
+
# Show all findings including low-risk ones
|
|
146
|
+
npx postquant analyze . --show-all
|
|
147
|
+
|
|
148
|
+
# Skip context analysis, raw pattern matching only
|
|
149
|
+
npx postquant analyze . --no-context
|
|
150
|
+
|
|
67
151
|
# SARIF output for GitHub Code Scanning
|
|
68
152
|
npx postquant analyze ./src --format sarif
|
|
69
153
|
|
|
70
154
|
# CycloneDX CBOM for compliance
|
|
71
155
|
npx postquant analyze . --format cbom
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Output with context labels:
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
Overall Grade: D+
|
|
72
162
|
|
|
73
|
-
|
|
74
|
-
|
|
163
|
+
Findings
|
|
164
|
+
|
|
165
|
+
django/contrib/auth/hashers.py (python)
|
|
166
|
+
L669: MD5 🔴 Critical — authentication
|
|
167
|
+
|
|
168
|
+
tests/file_uploads/tests.py (python)
|
|
169
|
+
L120: SHA-1 🔴 Critical — digital signature
|
|
170
|
+
|
|
171
|
+
Adjusted Risk (with context)
|
|
172
|
+
🔴 2 critical
|
|
173
|
+
🟢 4 low
|
|
174
|
+
🟢 2 informational
|
|
75
175
|
```
|
|
76
176
|
|
|
77
177
|
## Usage
|
|
@@ -125,7 +225,13 @@ postquant analyze . --ignore "vendor/**" --ignore "test/**"
|
|
|
125
225
|
# Set fail threshold for CI
|
|
126
226
|
postquant analyze ./src --fail-grade D
|
|
127
227
|
|
|
128
|
-
# Show all findings including
|
|
228
|
+
# Show all findings including low and informational risk
|
|
229
|
+
postquant analyze ./src --show-all
|
|
230
|
+
|
|
231
|
+
# Skip context analysis, use raw pattern matching only
|
|
232
|
+
postquant analyze ./src --no-context
|
|
233
|
+
|
|
234
|
+
# Show all findings including safe ones (legacy)
|
|
129
235
|
postquant analyze ./src --verbose
|
|
130
236
|
```
|
|
131
237
|
|
|
@@ -180,8 +286,10 @@ npm run dev -- analyze ./src # Code scan from source
|
|
|
180
286
|
|
|
181
287
|
| Phase | Target | Status |
|
|
182
288
|
|-------|--------|--------|
|
|
183
|
-
| TLS scanner CLI | March 2026 | v0.
|
|
184
|
-
| Code scanner + CBOM | March 2026 | v0.
|
|
289
|
+
| TLS scanner CLI | March 2026 | v0.3.0 |
|
|
290
|
+
| Code scanner + CBOM | March 2026 | v0.3.0 |
|
|
291
|
+
| Context-aware risk assessment | March 2026 | v0.3.0 |
|
|
292
|
+
| Hybrid PQC detection (OpenSSL probe) | March 2026 | v0.4.0 |
|
|
185
293
|
| Migration playbook engine | April 2026 | Planned |
|
|
186
294
|
| Web dashboard + Enterprise tier | May 2026 | Planned |
|
|
187
295
|
| GitHub Actions Marketplace + CI/CD | June 2026 | Planned |
|
|
@@ -85,7 +85,7 @@ function classifyCertificate(scan) {
|
|
|
85
85
|
function isPqcKeyExchange(scan) {
|
|
86
86
|
const ephName = scan.ephemeralKeyInfo?.name?.toUpperCase() ?? '';
|
|
87
87
|
const cipherName = scan.cipher?.name?.toUpperCase() ?? '';
|
|
88
|
-
const pqcPatterns = ['KYBER', 'MLKEM', 'ML-KEM'];
|
|
88
|
+
const pqcPatterns = ['KYBER', 'MLKEM', 'ML-KEM', 'X25519MLKEM'];
|
|
89
89
|
return pqcPatterns.some((p) => ephName.includes(p) || cipherName.includes(p));
|
|
90
90
|
}
|
|
91
91
|
function classifyKeyExchange(scan) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"classifier.js","sourceRoot":"","sources":["../../src/scanner/classifier.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"classifier.js","sourceRoot":"","sources":["../../src/scanner/classifier.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface OpensslProbeResult {
|
|
2
|
+
/** Negotiated TLS 1.3 group (e.g., 'X25519MLKEM768') */
|
|
3
|
+
group: string | null;
|
|
4
|
+
/** Classical key exchange info from "Peer Temp Key" / "Server Temp Key" */
|
|
5
|
+
peerTempKey: {
|
|
6
|
+
type: string;
|
|
7
|
+
name: string;
|
|
8
|
+
size: number;
|
|
9
|
+
} | null;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Find an OpenSSL 3.x binary (not LibreSSL).
|
|
13
|
+
* Returns the path or null if none found.
|
|
14
|
+
*/
|
|
15
|
+
export declare function findOpenssl3(): Promise<string | null>;
|
|
16
|
+
/**
|
|
17
|
+
* Probe a host via `openssl s_client` to detect the negotiated TLS group.
|
|
18
|
+
* Gracefully returns nulls on any failure.
|
|
19
|
+
*/
|
|
20
|
+
export declare function probeWithOpenssl(host: string, port: number): Promise<OpensslProbeResult>;
|
|
21
|
+
/**
|
|
22
|
+
* Parse openssl s_client output for TLS group and key exchange info.
|
|
23
|
+
*/
|
|
24
|
+
export declare function parseOpensslOutput(output: string): OpensslProbeResult;
|
|
25
|
+
//# sourceMappingURL=openssl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openssl.d.ts","sourceRoot":"","sources":["../../src/scanner/openssl.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,kBAAkB;IACjC,wDAAwD;IACxD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,2EAA2E;IAC3E,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAClE;AAUD;;;GAGG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiB3D;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,kBAAkB,CAAC,CA4B7B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,kBAAkB,CAyBrE"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { access, constants } from 'node:fs/promises';
|
|
3
|
+
const OPENSSL_CANDIDATES = [
|
|
4
|
+
'openssl',
|
|
5
|
+
'/opt/homebrew/opt/openssl@3/bin/openssl',
|
|
6
|
+
'/usr/local/opt/openssl@3/bin/openssl',
|
|
7
|
+
];
|
|
8
|
+
const PROBE_TIMEOUT_MS = 5000;
|
|
9
|
+
/**
|
|
10
|
+
* Find an OpenSSL 3.x binary (not LibreSSL).
|
|
11
|
+
* Returns the path or null if none found.
|
|
12
|
+
*/
|
|
13
|
+
export async function findOpenssl3() {
|
|
14
|
+
for (const candidate of OPENSSL_CANDIDATES) {
|
|
15
|
+
try {
|
|
16
|
+
// For absolute paths, check file exists first
|
|
17
|
+
if (candidate.startsWith('/')) {
|
|
18
|
+
await access(candidate, constants.X_OK);
|
|
19
|
+
}
|
|
20
|
+
const version = await runCommand(candidate, ['version']);
|
|
21
|
+
if (version.startsWith('OpenSSL 3.')) {
|
|
22
|
+
return candidate;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// Not found or not usable — try next
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Probe a host via `openssl s_client` to detect the negotiated TLS group.
|
|
33
|
+
* Gracefully returns nulls on any failure.
|
|
34
|
+
*/
|
|
35
|
+
export async function probeWithOpenssl(host, port) {
|
|
36
|
+
const nullResult = { group: null, peerTempKey: null };
|
|
37
|
+
let opensslBin;
|
|
38
|
+
try {
|
|
39
|
+
opensslBin = await findOpenssl3();
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return nullResult;
|
|
43
|
+
}
|
|
44
|
+
if (!opensslBin) {
|
|
45
|
+
return nullResult;
|
|
46
|
+
}
|
|
47
|
+
let output;
|
|
48
|
+
try {
|
|
49
|
+
output = await runCommand(opensslBin, [
|
|
50
|
+
's_client',
|
|
51
|
+
'-connect',
|
|
52
|
+
`${host}:${port}`,
|
|
53
|
+
'-servername',
|
|
54
|
+
host,
|
|
55
|
+
]);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return nullResult;
|
|
59
|
+
}
|
|
60
|
+
return parseOpensslOutput(output);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Parse openssl s_client output for TLS group and key exchange info.
|
|
64
|
+
*/
|
|
65
|
+
export function parseOpensslOutput(output) {
|
|
66
|
+
const result = { group: null, peerTempKey: null };
|
|
67
|
+
// Match: "Negotiated TLS1.3 group: X25519MLKEM768"
|
|
68
|
+
const groupMatch = output.match(/Negotiated TLS[\d.]+ group:\s*(\S+)/i);
|
|
69
|
+
if (groupMatch) {
|
|
70
|
+
result.group = groupMatch[1];
|
|
71
|
+
}
|
|
72
|
+
// Match: "Peer Temp Key: ECDH, X25519, 253 bits"
|
|
73
|
+
// or: "Server Temp Key: ECDH, prime256v1, 256 bits"
|
|
74
|
+
const tempKeyMatch = output.match(/(?:Peer|Server) Temp Key:\s*(\w+),\s*([^,]+),\s*(\d+)\s*bits/i);
|
|
75
|
+
if (tempKeyMatch) {
|
|
76
|
+
result.peerTempKey = {
|
|
77
|
+
type: tempKeyMatch[1],
|
|
78
|
+
name: tempKeyMatch[2].trim(),
|
|
79
|
+
size: parseInt(tempKeyMatch[3], 10),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
function runCommand(bin, args) {
|
|
85
|
+
return new Promise((resolve, reject) => {
|
|
86
|
+
const controller = new AbortController();
|
|
87
|
+
const timer = setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS);
|
|
88
|
+
const child = execFile(bin, args, {
|
|
89
|
+
timeout: PROBE_TIMEOUT_MS,
|
|
90
|
+
signal: controller.signal,
|
|
91
|
+
}, (error, stdout, stderr) => {
|
|
92
|
+
clearTimeout(timer);
|
|
93
|
+
// openssl s_client writes useful info to both stdout and stderr
|
|
94
|
+
// and may exit non-zero even on success (connection closed)
|
|
95
|
+
const combined = String(stdout ?? '') + '\n' + String(stderr ?? '');
|
|
96
|
+
if (combined.trim().length > 0) {
|
|
97
|
+
resolve(combined);
|
|
98
|
+
}
|
|
99
|
+
else if (error) {
|
|
100
|
+
reject(error);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
resolve('');
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
// Close stdin immediately so openssl doesn't hang waiting for input
|
|
107
|
+
try {
|
|
108
|
+
child.stdin?.end();
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
// ignore
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=openssl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openssl.js","sourceRoot":"","sources":["../../src/scanner/openssl.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tls.d.ts","sourceRoot":"","sources":["../../src/scanner/tls.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"tls.d.ts","sourceRoot":"","sources":["../../src/scanner/tls.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGvD,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,aAAa,CAAC,CA0CxB"}
|
package/dist/scanner/tls.js
CHANGED
|
@@ -1,9 +1,52 @@
|
|
|
1
1
|
import tls from 'node:tls';
|
|
2
|
-
|
|
2
|
+
import { probeWithOpenssl } from './openssl.js';
|
|
3
|
+
export async function scanHost(host, port, timeout) {
|
|
4
|
+
const result = await connectTls(host, port, timeout);
|
|
5
|
+
// Enrich with openssl probe for PQC detection
|
|
6
|
+
// Node.js returns {} for getEphemeralKeyInfo() on TLS 1.3
|
|
7
|
+
try {
|
|
8
|
+
const probe = await probeWithOpenssl(host, port);
|
|
9
|
+
if (probe.group) {
|
|
10
|
+
const groupUpper = probe.group.toUpperCase();
|
|
11
|
+
const isPqc = groupUpper.includes('KYBER') ||
|
|
12
|
+
groupUpper.includes('MLKEM') ||
|
|
13
|
+
groupUpper.includes('ML-KEM');
|
|
14
|
+
if (isPqc) {
|
|
15
|
+
result.ephemeralKeyInfo = {
|
|
16
|
+
type: 'KEM',
|
|
17
|
+
name: probe.group,
|
|
18
|
+
size: 0,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
else if (!result.ephemeralKeyInfo) {
|
|
22
|
+
// Classical group detected by openssl, Node.js had nothing
|
|
23
|
+
result.ephemeralKeyInfo = {
|
|
24
|
+
type: 'ECDH',
|
|
25
|
+
name: probe.group,
|
|
26
|
+
size: 0,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
else if (!result.ephemeralKeyInfo && probe.peerTempKey) {
|
|
31
|
+
// No negotiated group line but we got Peer Temp Key info
|
|
32
|
+
result.ephemeralKeyInfo = {
|
|
33
|
+
type: probe.peerTempKey.type,
|
|
34
|
+
name: probe.peerTempKey.name,
|
|
35
|
+
size: probe.peerTempKey.size,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// openssl probe failed — keep Node.js data as-is
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
function connectTls(host, port, timeout) {
|
|
3
45
|
return new Promise((resolve, reject) => {
|
|
4
46
|
const socket = tls.connect({
|
|
5
47
|
host,
|
|
6
48
|
port,
|
|
49
|
+
servername: host,
|
|
7
50
|
rejectUnauthorized: false,
|
|
8
51
|
timeout,
|
|
9
52
|
}, () => {
|
package/dist/scanner/tls.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tls.js","sourceRoot":"","sources":["../../src/scanner/tls.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"tls.js","sourceRoot":"","sources":["../../src/scanner/tls.ts"],"names":[],"mappings":"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"}
|