@quantakrypto/core 0.4.3 → 0.5.0
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 +76 -27
- package/dist/cbom-merge.d.ts +9 -0
- package/dist/cbom-merge.d.ts.map +1 -0
- package/dist/cbom-merge.js +121 -0
- package/dist/cbom-merge.js.map +1 -0
- package/dist/cbom.d.ts +5 -0
- package/dist/cbom.d.ts.map +1 -1
- package/dist/cbom.js +132 -37
- package/dist/cbom.js.map +1 -1
- package/dist/comments.d.ts +6 -26
- package/dist/comments.d.ts.map +1 -1
- package/dist/comments.js +77 -38
- package/dist/comments.js.map +1 -1
- package/dist/dependencies.d.ts.map +1 -1
- package/dist/dependencies.js +1 -1
- package/dist/dependencies.js.map +1 -1
- package/dist/detect-utils.d.ts +59 -21
- package/dist/detect-utils.d.ts.map +1 -1
- package/dist/detect-utils.js +143 -8
- package/dist/detect-utils.js.map +1 -1
- package/dist/detectors/age.d.ts +16 -0
- package/dist/detectors/age.d.ts.map +1 -0
- package/dist/detectors/age.js +40 -0
- package/dist/detectors/age.js.map +1 -0
- package/dist/detectors/ansible.d.ts +13 -0
- package/dist/detectors/ansible.d.ts.map +1 -0
- package/dist/detectors/ansible.js +108 -0
- package/dist/detectors/ansible.js.map +1 -0
- package/dist/detectors/bicep.d.ts +20 -0
- package/dist/detectors/bicep.d.ts.map +1 -0
- package/dist/detectors/bicep.js +74 -0
- package/dist/detectors/bicep.js.map +1 -0
- package/dist/detectors/c.d.ts +4 -2
- package/dist/detectors/c.d.ts.map +1 -1
- package/dist/detectors/c.js +222 -4
- package/dist/detectors/c.js.map +1 -1
- package/dist/detectors/cicd.d.ts +27 -0
- package/dist/detectors/cicd.d.ts.map +1 -0
- package/dist/detectors/cicd.js +129 -0
- package/dist/detectors/cicd.js.map +1 -0
- package/dist/detectors/cloud-kms.d.ts +24 -0
- package/dist/detectors/cloud-kms.d.ts.map +1 -0
- package/dist/detectors/cloud-kms.js +99 -0
- package/dist/detectors/cloud-kms.js.map +1 -0
- package/dist/detectors/cloudformation.d.ts +38 -0
- package/dist/detectors/cloudformation.d.ts.map +1 -0
- package/dist/detectors/cloudformation.js +201 -0
- package/dist/detectors/cloudformation.js.map +1 -0
- package/dist/detectors/codesign.d.ts +50 -0
- package/dist/detectors/codesign.d.ts.map +1 -0
- package/dist/detectors/codesign.js +143 -0
- package/dist/detectors/codesign.js.map +1 -0
- package/dist/detectors/csharp.d.ts.map +1 -1
- package/dist/detectors/csharp.js +13 -3
- package/dist/detectors/csharp.js.map +1 -1
- package/dist/detectors/dart.d.ts +35 -0
- package/dist/detectors/dart.d.ts.map +1 -0
- package/dist/detectors/dart.js +177 -0
- package/dist/detectors/dart.js.map +1 -0
- package/dist/detectors/database.d.ts +19 -0
- package/dist/detectors/database.d.ts.map +1 -0
- package/dist/detectors/database.js +97 -0
- package/dist/detectors/database.js.map +1 -0
- package/dist/detectors/dkim.d.ts +54 -0
- package/dist/detectors/dkim.d.ts.map +1 -0
- package/dist/detectors/dkim.js +92 -0
- package/dist/detectors/dkim.js.map +1 -0
- package/dist/detectors/dnssec.d.ts +55 -0
- package/dist/detectors/dnssec.d.ts.map +1 -0
- package/dist/detectors/dnssec.js +116 -0
- package/dist/detectors/dnssec.js.map +1 -0
- package/dist/detectors/elixir.d.ts +20 -0
- package/dist/detectors/elixir.d.ts.map +1 -0
- package/dist/detectors/elixir.js +227 -0
- package/dist/detectors/elixir.js.map +1 -0
- package/dist/detectors/java.d.ts.map +1 -1
- package/dist/detectors/java.js +34 -4
- package/dist/detectors/java.js.map +1 -1
- package/dist/detectors/jose.d.ts +20 -0
- package/dist/detectors/jose.d.ts.map +1 -0
- package/dist/detectors/jose.js +72 -0
- package/dist/detectors/jose.js.map +1 -0
- package/dist/detectors/jwk.d.ts +25 -0
- package/dist/detectors/jwk.d.ts.map +1 -0
- package/dist/detectors/jwk.js +131 -0
- package/dist/detectors/jwk.js.map +1 -0
- package/dist/detectors/k8s.d.ts +17 -0
- package/dist/detectors/k8s.d.ts.map +1 -0
- package/dist/detectors/k8s.js +88 -0
- package/dist/detectors/k8s.js.map +1 -0
- package/dist/detectors/keystore.d.ts +19 -0
- package/dist/detectors/keystore.d.ts.map +1 -0
- package/dist/detectors/keystore.js +76 -0
- package/dist/detectors/keystore.js.map +1 -0
- package/dist/detectors/mesh.d.ts +34 -0
- package/dist/detectors/mesh.d.ts.map +1 -0
- package/dist/detectors/mesh.js +91 -0
- package/dist/detectors/mesh.js.map +1 -0
- package/dist/detectors/messaging.d.ts +16 -0
- package/dist/detectors/messaging.d.ts.map +1 -0
- package/dist/detectors/messaging.js +79 -0
- package/dist/detectors/messaging.js.map +1 -0
- package/dist/detectors/objc.d.ts +41 -0
- package/dist/detectors/objc.d.ts.map +1 -0
- package/dist/detectors/objc.js +146 -0
- package/dist/detectors/objc.js.map +1 -0
- package/dist/detectors/openpgp.d.ts +20 -0
- package/dist/detectors/openpgp.d.ts.map +1 -0
- package/dist/detectors/openpgp.js +151 -0
- package/dist/detectors/openpgp.js.map +1 -0
- package/dist/detectors/pem.d.ts.map +1 -1
- package/dist/detectors/pem.js +33 -1
- package/dist/detectors/pem.js.map +1 -1
- package/dist/detectors/php.d.ts +25 -0
- package/dist/detectors/php.d.ts.map +1 -0
- package/dist/detectors/php.js +171 -0
- package/dist/detectors/php.js.map +1 -0
- package/dist/detectors/pkcs11.d.ts +17 -0
- package/dist/detectors/pkcs11.d.ts.map +1 -0
- package/dist/detectors/pkcs11.js +87 -0
- package/dist/detectors/pkcs11.js.map +1 -0
- package/dist/detectors/proxy.d.ts +52 -0
- package/dist/detectors/proxy.d.ts.map +1 -0
- package/dist/detectors/proxy.js +157 -0
- package/dist/detectors/proxy.js.map +1 -0
- package/dist/detectors/pulumi.d.ts +19 -0
- package/dist/detectors/pulumi.d.ts.map +1 -0
- package/dist/detectors/pulumi.js +80 -0
- package/dist/detectors/pulumi.js.map +1 -0
- package/dist/detectors/python.d.ts.map +1 -1
- package/dist/detectors/python.js +70 -0
- package/dist/detectors/python.js.map +1 -1
- package/dist/detectors/rust.d.ts.map +1 -1
- package/dist/detectors/rust.js +73 -0
- package/dist/detectors/rust.js.map +1 -1
- package/dist/detectors/secrets.d.ts +24 -0
- package/dist/detectors/secrets.d.ts.map +1 -0
- package/dist/detectors/secrets.js +63 -0
- package/dist/detectors/secrets.js.map +1 -0
- package/dist/detectors/solidity.d.ts +50 -0
- package/dist/detectors/solidity.d.ts.map +1 -0
- package/dist/detectors/solidity.js +108 -0
- package/dist/detectors/solidity.js.map +1 -0
- package/dist/detectors/source.d.ts.map +1 -1
- package/dist/detectors/source.js +243 -53
- package/dist/detectors/source.js.map +1 -1
- package/dist/detectors/spire.d.ts +49 -0
- package/dist/detectors/spire.d.ts.map +1 -0
- package/dist/detectors/spire.js +77 -0
- package/dist/detectors/spire.js.map +1 -0
- package/dist/detectors/ssh-ca.d.ts +72 -0
- package/dist/detectors/ssh-ca.d.ts.map +1 -0
- package/dist/detectors/ssh-ca.js +119 -0
- package/dist/detectors/ssh-ca.js.map +1 -0
- package/dist/detectors/stateful-hbs.d.ts.map +1 -1
- package/dist/detectors/stateful-hbs.js +9 -6
- package/dist/detectors/stateful-hbs.js.map +1 -1
- package/dist/detectors/supply-chain.d.ts +17 -0
- package/dist/detectors/supply-chain.d.ts.map +1 -0
- package/dist/detectors/supply-chain.js +89 -0
- package/dist/detectors/supply-chain.js.map +1 -0
- package/dist/detectors/swift.d.ts +22 -0
- package/dist/detectors/swift.d.ts.map +1 -0
- package/dist/detectors/swift.js +120 -0
- package/dist/detectors/swift.js.map +1 -0
- package/dist/detectors/terraform.d.ts +21 -0
- package/dist/detectors/terraform.d.ts.map +1 -0
- package/dist/detectors/terraform.js +150 -0
- package/dist/detectors/terraform.js.map +1 -0
- package/dist/detectors/vault.d.ts +15 -0
- package/dist/detectors/vault.d.ts.map +1 -0
- package/dist/detectors/vault.js +97 -0
- package/dist/detectors/vault.js.map +1 -0
- package/dist/detectors/vpn.d.ts +22 -0
- package/dist/detectors/vpn.d.ts.map +1 -0
- package/dist/detectors/vpn.js +73 -0
- package/dist/detectors/vpn.js.map +1 -0
- package/dist/detectors/weak-hash.d.ts +71 -0
- package/dist/detectors/weak-hash.d.ts.map +1 -0
- package/dist/detectors/weak-hash.js +116 -0
- package/dist/detectors/weak-hash.js.map +1 -0
- package/dist/detectors/webauthn.d.ts +61 -0
- package/dist/detectors/webauthn.d.ts.map +1 -0
- package/dist/detectors/webauthn.js +109 -0
- package/dist/detectors/webauthn.js.map +1 -0
- package/dist/detectors/xmldsig.d.ts +23 -0
- package/dist/detectors/xmldsig.d.ts.map +1 -0
- package/dist/detectors/xmldsig.js +84 -0
- package/dist/detectors/xmldsig.js.map +1 -0
- package/dist/evidence.d.ts +79 -4
- package/dist/evidence.d.ts.map +1 -1
- package/dist/evidence.js +76 -0
- package/dist/evidence.js.map +1 -1
- package/dist/index.d.ts +17 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -9
- package/dist/index.js.map +1 -1
- package/dist/inventory.d.ts +0 -2
- package/dist/inventory.d.ts.map +1 -1
- package/dist/inventory.js +15 -6
- package/dist/inventory.js.map +1 -1
- package/dist/policy.d.ts +67 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +115 -0
- package/dist/policy.js.map +1 -0
- package/dist/registry.d.ts +9 -4
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +81 -4
- package/dist/registry.js.map +1 -1
- package/dist/remediate-pipeline.d.ts +0 -3
- package/dist/remediate-pipeline.d.ts.map +1 -1
- package/dist/remediate-pipeline.js +23 -2
- package/dist/remediate-pipeline.js.map +1 -1
- package/dist/remediation.d.ts +10 -0
- package/dist/remediation.d.ts.map +1 -1
- package/dist/remediation.js +32 -0
- package/dist/remediation.js.map +1 -1
- package/dist/report.d.ts +9 -0
- package/dist/report.d.ts.map +1 -1
- package/dist/report.js +38 -1
- package/dist/report.js.map +1 -1
- package/dist/scan-worker.js +5 -3
- package/dist/scan-worker.js.map +1 -1
- package/dist/scan.d.ts.map +1 -1
- package/dist/scan.js +35 -6
- package/dist/scan.js.map +1 -1
- package/dist/standards-profiles.d.ts +58 -0
- package/dist/standards-profiles.d.ts.map +1 -0
- package/dist/standards-profiles.js +100 -0
- package/dist/standards-profiles.js.map +1 -0
- package/dist/standards.d.ts +96 -0
- package/dist/standards.d.ts.map +1 -0
- package/dist/standards.js +107 -0
- package/dist/standards.js.map +1 -0
- package/dist/types.d.ts +6 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/dist/vex.d.ts +39 -0
- package/dist/vex.d.ts.map +1 -0
- package/dist/vex.js +87 -0
- package/dist/vex.js.map +1 -0
- package/dist/walk.d.ts +8 -3
- package/dist/walk.d.ts.map +1 -1
- package/dist/walk.js +32 -1
- package/dist/walk.js.map +1 -1
- package/package.json +1 -1
- package/src/cbom-merge.ts +146 -0
- package/src/cbom.ts +153 -39
- package/src/comments.ts +84 -39
- package/src/dependencies.ts +2 -1
- package/src/detect-utils.ts +146 -12
- package/src/detectors/age.ts +60 -0
- package/src/detectors/ansible.ts +140 -0
- package/src/detectors/bicep.ts +107 -0
- package/src/detectors/c.ts +240 -6
- package/src/detectors/cicd.ts +171 -0
- package/src/detectors/cloud-kms.ts +141 -0
- package/src/detectors/cloudformation.ts +250 -0
- package/src/detectors/codesign.ts +214 -0
- package/src/detectors/csharp.ts +13 -3
- package/src/detectors/dart.ts +237 -0
- package/src/detectors/database.ts +141 -0
- package/src/detectors/dkim.ts +172 -0
- package/src/detectors/dnssec.ts +195 -0
- package/src/detectors/elixir.ts +268 -0
- package/src/detectors/java.ts +39 -4
- package/src/detectors/jose.ts +110 -0
- package/src/detectors/jwk.ts +170 -0
- package/src/detectors/k8s.ts +115 -0
- package/src/detectors/keystore.ts +109 -0
- package/src/detectors/mesh.ts +130 -0
- package/src/detectors/messaging.ts +106 -0
- package/src/detectors/objc.ts +209 -0
- package/src/detectors/openpgp.ts +194 -0
- package/src/detectors/pem.ts +31 -1
- package/src/detectors/php.ts +230 -0
- package/src/detectors/pkcs11.ts +113 -0
- package/src/detectors/proxy.ts +236 -0
- package/src/detectors/pulumi.ts +106 -0
- package/src/detectors/python.ts +71 -0
- package/src/detectors/rust.ts +76 -0
- package/src/detectors/secrets.ts +103 -0
- package/src/detectors/solidity.ts +176 -0
- package/src/detectors/source.ts +283 -73
- package/src/detectors/spire.ts +143 -0
- package/src/detectors/ssh-ca.ts +215 -0
- package/src/detectors/stateful-hbs.ts +9 -6
- package/src/detectors/supply-chain.ts +117 -0
- package/src/detectors/swift.ts +149 -0
- package/src/detectors/terraform.ts +188 -0
- package/src/detectors/vault.ts +120 -0
- package/src/detectors/vpn.ts +103 -0
- package/src/detectors/weak-hash.ts +217 -0
- package/src/detectors/webauthn.ts +205 -0
- package/src/detectors/xmldsig.ts +115 -0
- package/src/evidence.ts +138 -4
- package/src/index.ts +50 -12
- package/src/inventory.ts +15 -7
- package/src/policy.ts +180 -0
- package/src/registry.ts +81 -4
- package/src/remediate-pipeline.ts +26 -3
- package/src/remediation.ts +39 -0
- package/src/report.ts +43 -1
- package/src/scan-worker.ts +5 -3
- package/src/scan.ts +41 -6
- package/src/standards-profiles.ts +136 -0
- package/src/standards.ts +186 -0
- package/src/types.ts +11 -4
- package/src/version.ts +1 -1
- package/src/vex.ts +122 -0
- package/src/walk.ts +33 -2
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { ELIXIR_EXTENSIONS, eachMatch, findingFromRule, hasExtension } from "../detect-utils.js";
|
|
2
|
+
import { CWE_BROKEN_CRYPTO } from "../cwe.js";
|
|
3
|
+
const RE_EX_GEN = /:crypto\.generate_key\s*\(\s*:(\w+)/g;
|
|
4
|
+
// `:crypto.compute_key(:ecdh|:dh, PeerPub, MyKey, :curve)` is the DH/ECDH AGREEMENT
|
|
5
|
+
// operation itself — the harvest-now-decrypt-later step — which generate_key alone
|
|
6
|
+
// misses. Classified by the same type/curve logic as generate_key.
|
|
7
|
+
const RE_EX_COMPUTE = /:crypto\.compute_key\s*\(\s*:(\w+)/g;
|
|
8
|
+
const RE_EX_SIGN = /:crypto\.(?:sign|verify)\s*\(\s*:(\w+)/g;
|
|
9
|
+
const RE_EX_X509_RSA = /\bX509\.PrivateKey\.new_rsa\s*\(/g;
|
|
10
|
+
const RE_EX_X509_EC = /\bX509\.PrivateKey\.new_ec\s*\(/g;
|
|
11
|
+
const RE_EX_JOSE = /\bJOSE\.JWK\.generate_key\s*\(\s*\{\s*:(\w+)/g;
|
|
12
|
+
const SIG_REM = "ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205)";
|
|
13
|
+
const KEX_REM = "hybrid X25519MLKEM768 (ML-KEM-768)";
|
|
14
|
+
const RULE_EX_KEYGEN = {
|
|
15
|
+
id: "elixir-crypto-keygen",
|
|
16
|
+
title: "Elixir :crypto key generation",
|
|
17
|
+
description: ":crypto.generate_key (rsa/ecdh/dh/eddsa)",
|
|
18
|
+
category: "kem",
|
|
19
|
+
severity: "high",
|
|
20
|
+
confidence: "high",
|
|
21
|
+
algorithm: "RSA",
|
|
22
|
+
hndl: true,
|
|
23
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
24
|
+
message: "Generates a classical key pair via Erlang :crypto (Elixir) — not quantum-safe.",
|
|
25
|
+
};
|
|
26
|
+
const RULE_EX_SIGN = {
|
|
27
|
+
id: "elixir-crypto-sign",
|
|
28
|
+
title: "Elixir :crypto signature",
|
|
29
|
+
description: ":crypto.sign / :crypto.verify (rsa/ecdsa/eddsa)",
|
|
30
|
+
category: "signature",
|
|
31
|
+
severity: "high",
|
|
32
|
+
confidence: "high",
|
|
33
|
+
algorithm: "unknown",
|
|
34
|
+
hndl: false,
|
|
35
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
36
|
+
message: "Classical signature via Erlang :crypto (Elixir) is forgeable by a quantum attacker.",
|
|
37
|
+
remediation: SIG_REM,
|
|
38
|
+
};
|
|
39
|
+
const RULE_EX_X509 = {
|
|
40
|
+
id: "elixir-x509-keygen",
|
|
41
|
+
title: "Elixir X509 key generation",
|
|
42
|
+
description: "X509.PrivateKey.new_rsa / new_ec",
|
|
43
|
+
category: "kem",
|
|
44
|
+
severity: "high",
|
|
45
|
+
confidence: "high",
|
|
46
|
+
algorithm: "RSA",
|
|
47
|
+
hndl: true,
|
|
48
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
49
|
+
message: "Generates a classical key pair via the X509 library (Elixir) — not quantum-safe.",
|
|
50
|
+
};
|
|
51
|
+
const RULE_EX_JOSE = {
|
|
52
|
+
id: "elixir-jose-jwk",
|
|
53
|
+
title: "Elixir JOSE JWK generation",
|
|
54
|
+
description: "JOSE.JWK.generate_key ({:rsa|:ec|:okp})",
|
|
55
|
+
category: "kem",
|
|
56
|
+
severity: "high",
|
|
57
|
+
confidence: "high",
|
|
58
|
+
algorithm: "RSA",
|
|
59
|
+
hndl: true,
|
|
60
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
61
|
+
message: "Generates a classical JWK via JOSE (Elixir) — not quantum-safe.",
|
|
62
|
+
};
|
|
63
|
+
const RSA_CLS = { algo: "RSA", cat: "kem", sev: "high", hndl: true, label: "RSA" };
|
|
64
|
+
const DH_CLS = { algo: "DH", cat: "key-exchange", sev: "high", hndl: true, label: "DH" };
|
|
65
|
+
const ECDH_CLS = {
|
|
66
|
+
algo: "ECDH",
|
|
67
|
+
cat: "key-exchange",
|
|
68
|
+
sev: "high",
|
|
69
|
+
hndl: true,
|
|
70
|
+
label: "ECDH",
|
|
71
|
+
remediation: KEX_REM,
|
|
72
|
+
};
|
|
73
|
+
const X25519_CLS = {
|
|
74
|
+
algo: "X25519",
|
|
75
|
+
cat: "key-exchange",
|
|
76
|
+
sev: "medium",
|
|
77
|
+
hndl: true,
|
|
78
|
+
label: "X25519",
|
|
79
|
+
remediation: KEX_REM,
|
|
80
|
+
};
|
|
81
|
+
const X448_CLS = { ...X25519_CLS, algo: "X448", label: "X448" };
|
|
82
|
+
const EDDSA_CLS = {
|
|
83
|
+
algo: "EdDSA",
|
|
84
|
+
cat: "signature",
|
|
85
|
+
sev: "low",
|
|
86
|
+
hndl: false,
|
|
87
|
+
label: "EdDSA",
|
|
88
|
+
remediation: SIG_REM,
|
|
89
|
+
};
|
|
90
|
+
const EC_CLS = {
|
|
91
|
+
algo: "ECDH",
|
|
92
|
+
cat: "key-exchange",
|
|
93
|
+
sev: "high",
|
|
94
|
+
hndl: true,
|
|
95
|
+
label: "EC (ECDSA/ECDH)",
|
|
96
|
+
remediation: KEX_REM,
|
|
97
|
+
};
|
|
98
|
+
/** Classify a `:crypto.generate_key(:<type>, …)` by its type atom (+ the curve
|
|
99
|
+
* atom in a short window for the ecdh X25519/X448 case). */
|
|
100
|
+
function classifyGen(type, window) {
|
|
101
|
+
switch (type) {
|
|
102
|
+
case "rsa":
|
|
103
|
+
return RSA_CLS;
|
|
104
|
+
case "dh":
|
|
105
|
+
return DH_CLS;
|
|
106
|
+
case "eddsa":
|
|
107
|
+
case "ed25519":
|
|
108
|
+
return EDDSA_CLS;
|
|
109
|
+
case "ecdh":
|
|
110
|
+
if (/:x25519\b/i.test(window))
|
|
111
|
+
return X25519_CLS;
|
|
112
|
+
if (/:x448\b/i.test(window))
|
|
113
|
+
return X448_CLS;
|
|
114
|
+
return ECDH_CLS;
|
|
115
|
+
default:
|
|
116
|
+
return null; // srp / other non-broken-in-this-model types
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/** Signature algorithm classification for `:crypto.sign(:<type>, …)`. */
|
|
120
|
+
function classifySign(type) {
|
|
121
|
+
if (type === "rsa")
|
|
122
|
+
return "RSA";
|
|
123
|
+
if (type === "ecdsa")
|
|
124
|
+
return "ECDSA";
|
|
125
|
+
if (type === "eddsa" || type === "ed25519")
|
|
126
|
+
return "EdDSA";
|
|
127
|
+
if (type === "dss")
|
|
128
|
+
return "DSA"; // Erlang's algorithm atom for DSA signatures
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
/** Detects classical asymmetric crypto in Elixir (:crypto, X509, JOSE). */
|
|
132
|
+
export const elixirDetector = {
|
|
133
|
+
id: "elixir-crypto",
|
|
134
|
+
description: "Classical asymmetric crypto in Elixir (:crypto, X509, JOSE)",
|
|
135
|
+
scope: "source",
|
|
136
|
+
language: "elixir",
|
|
137
|
+
rules: [RULE_EX_KEYGEN, RULE_EX_SIGN, RULE_EX_X509, RULE_EX_JOSE],
|
|
138
|
+
appliesTo: (f) => hasExtension(f, ELIXIR_EXTENSIONS),
|
|
139
|
+
detect({ file, content }) {
|
|
140
|
+
const findings = [];
|
|
141
|
+
const at = (m) => ({
|
|
142
|
+
file,
|
|
143
|
+
content,
|
|
144
|
+
index: m.index,
|
|
145
|
+
matchLength: m[0].length,
|
|
146
|
+
});
|
|
147
|
+
// :crypto.generate_key(:type, …) — classify by the type atom (+ curve window).
|
|
148
|
+
eachMatch(RE_EX_GEN, content, (m) => {
|
|
149
|
+
const cls = classifyGen(m[1], content.slice(m.index, m.index + 80));
|
|
150
|
+
if (!cls)
|
|
151
|
+
return;
|
|
152
|
+
findings.push(findingFromRule(RULE_EX_KEYGEN, at(m), {
|
|
153
|
+
title: `Elixir :crypto ${cls.label} key generation`,
|
|
154
|
+
category: cls.cat,
|
|
155
|
+
severity: cls.sev,
|
|
156
|
+
algorithm: cls.algo,
|
|
157
|
+
hndl: cls.hndl,
|
|
158
|
+
message: `Generates a classical ${cls.label} key pair via Erlang :crypto (Elixir) — not quantum-safe.`,
|
|
159
|
+
...(cls.remediation ? { remediation: cls.remediation } : {}),
|
|
160
|
+
}));
|
|
161
|
+
});
|
|
162
|
+
// :crypto.compute_key(:type, …) — the (EC)DH agreement operation.
|
|
163
|
+
eachMatch(RE_EX_COMPUTE, content, (m) => {
|
|
164
|
+
const cls = classifyGen(m[1], content.slice(m.index, m.index + 120));
|
|
165
|
+
if (!cls)
|
|
166
|
+
return;
|
|
167
|
+
findings.push(findingFromRule(RULE_EX_KEYGEN, at(m), {
|
|
168
|
+
title: `Elixir :crypto ${cls.label} key agreement`,
|
|
169
|
+
category: cls.cat,
|
|
170
|
+
severity: cls.sev,
|
|
171
|
+
algorithm: cls.algo,
|
|
172
|
+
hndl: cls.hndl,
|
|
173
|
+
message: `Performs classical ${cls.label} key agreement via Erlang :crypto (Elixir) — harvest-now-decrypt-later exposed.`,
|
|
174
|
+
...(cls.remediation ? { remediation: cls.remediation } : {}),
|
|
175
|
+
}));
|
|
176
|
+
});
|
|
177
|
+
// :crypto.sign / :crypto.verify(:type, …).
|
|
178
|
+
eachMatch(RE_EX_SIGN, content, (m) => {
|
|
179
|
+
const algo = classifySign(m[1]);
|
|
180
|
+
if (!algo)
|
|
181
|
+
return;
|
|
182
|
+
findings.push(findingFromRule(RULE_EX_SIGN, at(m), {
|
|
183
|
+
algorithm: algo,
|
|
184
|
+
message: `Classical ${algo} signature via Erlang :crypto (Elixir) is forgeable by a quantum attacker.`,
|
|
185
|
+
}));
|
|
186
|
+
});
|
|
187
|
+
// X509.PrivateKey.new_rsa / new_ec.
|
|
188
|
+
eachMatch(RE_EX_X509_RSA, content, (m) => findings.push(findingFromRule(RULE_EX_X509, at(m), { algorithm: "RSA" })));
|
|
189
|
+
eachMatch(RE_EX_X509_EC, content, (m) => findings.push(findingFromRule(RULE_EX_X509, at(m), {
|
|
190
|
+
title: "Elixir X509 EC key generation",
|
|
191
|
+
category: EC_CLS.cat,
|
|
192
|
+
algorithm: EC_CLS.algo,
|
|
193
|
+
hndl: EC_CLS.hndl,
|
|
194
|
+
message: "Generates a classical EC key pair via the X509 library (Elixir); EC keys feed BOTH ECDSA and ECDH.",
|
|
195
|
+
remediation: KEX_REM,
|
|
196
|
+
})));
|
|
197
|
+
// JOSE.JWK.generate_key({:rsa|:ec|:okp, …}). An OKP key is EdDSA (Ed25519/Ed448,
|
|
198
|
+
// signature) OR a Montgomery key-agreement key (X25519/X448, HNDL) — inspect the
|
|
199
|
+
// curve atom in a short window so an X25519 OKP is not mislabeled as an EdDSA
|
|
200
|
+
// signature.
|
|
201
|
+
eachMatch(RE_EX_JOSE, content, (m) => {
|
|
202
|
+
const kind = m[1];
|
|
203
|
+
let okpCls = EDDSA_CLS;
|
|
204
|
+
if (kind === "okp") {
|
|
205
|
+
const window = content.slice(m.index, m.index + 80);
|
|
206
|
+
if (/:x25519\b/i.test(window))
|
|
207
|
+
okpCls = X25519_CLS;
|
|
208
|
+
else if (/:x448\b/i.test(window))
|
|
209
|
+
okpCls = X448_CLS;
|
|
210
|
+
}
|
|
211
|
+
const cls = kind === "rsa" ? RSA_CLS : kind === "ec" ? EC_CLS : kind === "okp" ? okpCls : null;
|
|
212
|
+
if (!cls)
|
|
213
|
+
return;
|
|
214
|
+
findings.push(findingFromRule(RULE_EX_JOSE, at(m), {
|
|
215
|
+
title: `Elixir JOSE ${cls.label} JWK`,
|
|
216
|
+
category: cls.cat,
|
|
217
|
+
severity: cls.sev,
|
|
218
|
+
algorithm: cls.algo,
|
|
219
|
+
hndl: cls.hndl,
|
|
220
|
+
message: `Generates a classical ${cls.label} JWK via JOSE (Elixir) — not quantum-safe.`,
|
|
221
|
+
...(cls.remediation ? { remediation: cls.remediation } : {}),
|
|
222
|
+
}));
|
|
223
|
+
});
|
|
224
|
+
return findings;
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
//# sourceMappingURL=elixir.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elixir.js","sourceRoot":"","sources":["../../src/detectors/elixir.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Source-code detector for classical asymmetric cryptography in Elixir (the BEAM\n * / Phoenix ecosystem), previously uncovered. Handles the three common surfaces:\n *\n * - **Erlang `:crypto`** — `:crypto.generate_key(:rsa|:ecdh|:dh|:eddsa, …)`\n * (the curve atom disambiguates X25519/X448 from a generic ECDH curve) and\n * `:crypto.sign/:crypto.verify(:rsa|:ecdsa|:eddsa, …)`.\n * - **`X509`** (the `x509` hex package) — `X509.PrivateKey.new_rsa` / `new_ec`.\n * - **`JOSE`** (erlang-jose) — `JOSE.JWK.generate_key({:rsa|:ec|:okp, …})`.\n *\n * Lexical, like the other packs; the `:crypto.` atom-module syntax and the\n * `X509.` / `JOSE.` module paths are distinctive, so the false-positive rate is low.\n *\n * HNDL: RSA and (EC/X)DH key agreement are harvest-now-decrypt-later exposed\n * (hndl:true); ECDSA / EdDSA signatures are hndl:false but forgeable.\n */\nimport type { AlgorithmFamily, Detector, Finding, RuleMeta } from \"../types.js\";\nimport { ELIXIR_EXTENSIONS, eachMatch, findingFromRule, hasExtension } from \"../detect-utils.js\";\nimport { CWE_BROKEN_CRYPTO } from \"../cwe.js\";\n\nconst RE_EX_GEN = /:crypto\\.generate_key\\s*\\(\\s*:(\\w+)/g;\n// `:crypto.compute_key(:ecdh|:dh, PeerPub, MyKey, :curve)` is the DH/ECDH AGREEMENT\n// operation itself — the harvest-now-decrypt-later step — which generate_key alone\n// misses. Classified by the same type/curve logic as generate_key.\nconst RE_EX_COMPUTE = /:crypto\\.compute_key\\s*\\(\\s*:(\\w+)/g;\nconst RE_EX_SIGN = /:crypto\\.(?:sign|verify)\\s*\\(\\s*:(\\w+)/g;\nconst RE_EX_X509_RSA = /\\bX509\\.PrivateKey\\.new_rsa\\s*\\(/g;\nconst RE_EX_X509_EC = /\\bX509\\.PrivateKey\\.new_ec\\s*\\(/g;\nconst RE_EX_JOSE = /\\bJOSE\\.JWK\\.generate_key\\s*\\(\\s*\\{\\s*:(\\w+)/g;\n\ninterface Cls {\n algo: AlgorithmFamily;\n cat: Finding[\"category\"];\n sev: Finding[\"severity\"];\n hndl: boolean;\n label: string;\n remediation?: string;\n}\nconst SIG_REM = \"ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205)\";\nconst KEX_REM = \"hybrid X25519MLKEM768 (ML-KEM-768)\";\n\nconst RULE_EX_KEYGEN: RuleMeta = {\n id: \"elixir-crypto-keygen\",\n title: \"Elixir :crypto key generation\",\n description: \":crypto.generate_key (rsa/ecdh/dh/eddsa)\",\n category: \"kem\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"RSA\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"Generates a classical key pair via Erlang :crypto (Elixir) — not quantum-safe.\",\n};\nconst RULE_EX_SIGN: RuleMeta = {\n id: \"elixir-crypto-sign\",\n title: \"Elixir :crypto signature\",\n description: \":crypto.sign / :crypto.verify (rsa/ecdsa/eddsa)\",\n category: \"signature\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"Classical signature via Erlang :crypto (Elixir) is forgeable by a quantum attacker.\",\n remediation: SIG_REM,\n};\nconst RULE_EX_X509: RuleMeta = {\n id: \"elixir-x509-keygen\",\n title: \"Elixir X509 key generation\",\n description: \"X509.PrivateKey.new_rsa / new_ec\",\n category: \"kem\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"RSA\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"Generates a classical key pair via the X509 library (Elixir) — not quantum-safe.\",\n};\nconst RULE_EX_JOSE: RuleMeta = {\n id: \"elixir-jose-jwk\",\n title: \"Elixir JOSE JWK generation\",\n description: \"JOSE.JWK.generate_key ({:rsa|:ec|:okp})\",\n category: \"kem\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"RSA\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"Generates a classical JWK via JOSE (Elixir) — not quantum-safe.\",\n};\n\nconst RSA_CLS: Cls = { algo: \"RSA\", cat: \"kem\", sev: \"high\", hndl: true, label: \"RSA\" };\nconst DH_CLS: Cls = { algo: \"DH\", cat: \"key-exchange\", sev: \"high\", hndl: true, label: \"DH\" };\nconst ECDH_CLS: Cls = {\n algo: \"ECDH\",\n cat: \"key-exchange\",\n sev: \"high\",\n hndl: true,\n label: \"ECDH\",\n remediation: KEX_REM,\n};\nconst X25519_CLS: Cls = {\n algo: \"X25519\",\n cat: \"key-exchange\",\n sev: \"medium\",\n hndl: true,\n label: \"X25519\",\n remediation: KEX_REM,\n};\nconst X448_CLS: Cls = { ...X25519_CLS, algo: \"X448\", label: \"X448\" };\nconst EDDSA_CLS: Cls = {\n algo: \"EdDSA\",\n cat: \"signature\",\n sev: \"low\",\n hndl: false,\n label: \"EdDSA\",\n remediation: SIG_REM,\n};\nconst EC_CLS: Cls = {\n algo: \"ECDH\",\n cat: \"key-exchange\",\n sev: \"high\",\n hndl: true,\n label: \"EC (ECDSA/ECDH)\",\n remediation: KEX_REM,\n};\n\n/** Classify a `:crypto.generate_key(:<type>, …)` by its type atom (+ the curve\n * atom in a short window for the ecdh X25519/X448 case). */\nfunction classifyGen(type: string, window: string): Cls | null {\n switch (type) {\n case \"rsa\":\n return RSA_CLS;\n case \"dh\":\n return DH_CLS;\n case \"eddsa\":\n case \"ed25519\":\n return EDDSA_CLS;\n case \"ecdh\":\n if (/:x25519\\b/i.test(window)) return X25519_CLS;\n if (/:x448\\b/i.test(window)) return X448_CLS;\n return ECDH_CLS;\n default:\n return null; // srp / other non-broken-in-this-model types\n }\n}\n\n/** Signature algorithm classification for `:crypto.sign(:<type>, …)`. */\nfunction classifySign(type: string): AlgorithmFamily | null {\n if (type === \"rsa\") return \"RSA\";\n if (type === \"ecdsa\") return \"ECDSA\";\n if (type === \"eddsa\" || type === \"ed25519\") return \"EdDSA\";\n if (type === \"dss\") return \"DSA\"; // Erlang's algorithm atom for DSA signatures\n return null;\n}\n\n/** Detects classical asymmetric crypto in Elixir (:crypto, X509, JOSE). */\nexport const elixirDetector: Detector = {\n id: \"elixir-crypto\",\n description: \"Classical asymmetric crypto in Elixir (:crypto, X509, JOSE)\",\n scope: \"source\",\n language: \"elixir\",\n rules: [RULE_EX_KEYGEN, RULE_EX_SIGN, RULE_EX_X509, RULE_EX_JOSE],\n appliesTo: (f) => hasExtension(f, ELIXIR_EXTENSIONS),\n detect({ file, content }): Finding[] {\n const findings: Finding[] = [];\n const at = (m: RegExpExecArray) => ({\n file,\n content,\n index: m.index,\n matchLength: m[0].length,\n });\n\n // :crypto.generate_key(:type, …) — classify by the type atom (+ curve window).\n eachMatch(RE_EX_GEN, content, (m) => {\n const cls = classifyGen(m[1], content.slice(m.index, m.index + 80));\n if (!cls) return;\n findings.push(\n findingFromRule(RULE_EX_KEYGEN, at(m), {\n title: `Elixir :crypto ${cls.label} key generation`,\n category: cls.cat,\n severity: cls.sev,\n algorithm: cls.algo,\n hndl: cls.hndl,\n message: `Generates a classical ${cls.label} key pair via Erlang :crypto (Elixir) — not quantum-safe.`,\n ...(cls.remediation ? { remediation: cls.remediation } : {}),\n }),\n );\n });\n\n // :crypto.compute_key(:type, …) — the (EC)DH agreement operation.\n eachMatch(RE_EX_COMPUTE, content, (m) => {\n const cls = classifyGen(m[1], content.slice(m.index, m.index + 120));\n if (!cls) return;\n findings.push(\n findingFromRule(RULE_EX_KEYGEN, at(m), {\n title: `Elixir :crypto ${cls.label} key agreement`,\n category: cls.cat,\n severity: cls.sev,\n algorithm: cls.algo,\n hndl: cls.hndl,\n message: `Performs classical ${cls.label} key agreement via Erlang :crypto (Elixir) — harvest-now-decrypt-later exposed.`,\n ...(cls.remediation ? { remediation: cls.remediation } : {}),\n }),\n );\n });\n\n // :crypto.sign / :crypto.verify(:type, …).\n eachMatch(RE_EX_SIGN, content, (m) => {\n const algo = classifySign(m[1]);\n if (!algo) return;\n findings.push(\n findingFromRule(RULE_EX_SIGN, at(m), {\n algorithm: algo,\n message: `Classical ${algo} signature via Erlang :crypto (Elixir) is forgeable by a quantum attacker.`,\n }),\n );\n });\n\n // X509.PrivateKey.new_rsa / new_ec.\n eachMatch(RE_EX_X509_RSA, content, (m) =>\n findings.push(findingFromRule(RULE_EX_X509, at(m), { algorithm: \"RSA\" })),\n );\n eachMatch(RE_EX_X509_EC, content, (m) =>\n findings.push(\n findingFromRule(RULE_EX_X509, at(m), {\n title: \"Elixir X509 EC key generation\",\n category: EC_CLS.cat,\n algorithm: EC_CLS.algo,\n hndl: EC_CLS.hndl,\n message:\n \"Generates a classical EC key pair via the X509 library (Elixir); EC keys feed BOTH ECDSA and ECDH.\",\n remediation: KEX_REM,\n }),\n ),\n );\n\n // JOSE.JWK.generate_key({:rsa|:ec|:okp, …}). An OKP key is EdDSA (Ed25519/Ed448,\n // signature) OR a Montgomery key-agreement key (X25519/X448, HNDL) — inspect the\n // curve atom in a short window so an X25519 OKP is not mislabeled as an EdDSA\n // signature.\n eachMatch(RE_EX_JOSE, content, (m) => {\n const kind = m[1];\n let okpCls: Cls = EDDSA_CLS;\n if (kind === \"okp\") {\n const window = content.slice(m.index, m.index + 80);\n if (/:x25519\\b/i.test(window)) okpCls = X25519_CLS;\n else if (/:x448\\b/i.test(window)) okpCls = X448_CLS;\n }\n const cls =\n kind === \"rsa\" ? RSA_CLS : kind === \"ec\" ? EC_CLS : kind === \"okp\" ? okpCls : null;\n if (!cls) return;\n findings.push(\n findingFromRule(RULE_EX_JOSE, at(m), {\n title: `Elixir JOSE ${cls.label} JWK`,\n category: cls.cat,\n severity: cls.sev,\n algorithm: cls.algo,\n hndl: cls.hndl,\n message: `Generates a classical ${cls.label} JWK via JOSE (Elixir) — not quantum-safe.`,\n ...(cls.remediation ? { remediation: cls.remediation } : {}),\n }),\n );\n });\n\n return findings;\n },\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"java.d.ts","sourceRoot":"","sources":["../../src/detectors/java.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAqB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"java.d.ts","sourceRoot":"","sources":["../../src/detectors/java.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAqB,MAAM,aAAa,CAAC;AA0U/D,iFAAiF;AACjF,eAAO,MAAM,YAAY,EAAE,QAuG1B,CAAC"}
|
package/dist/detectors/java.js
CHANGED
|
@@ -8,7 +8,7 @@ import { CWE_BROKEN_CRYPTO, CWE_CERT_VALIDATION, CWE_WEAK_STRENGTH } from "../cw
|
|
|
8
8
|
// are symmetric / hashing only).
|
|
9
9
|
const RE_JAVA_GETINSTANCE = /\b(KeyPairGenerator|Signature|Cipher|KeyAgreement|KeyFactory)\s*\.\s*getInstance\s*\(\s*"([^"]+)"/g;
|
|
10
10
|
// BouncyCastle lightweight-API class instantiations.
|
|
11
|
-
const RE_JAVA_BC = /\bnew\s+(RSAKeyPairGenerator|DSAKeyPairGenerator|ECKeyPairGenerator|ECDSASigner|Ed25519Signer|Ed448Signer|X25519Agreement|X448Agreement|ECDHBasicAgreement|DHBasicAgreement|X25519KeyPairGenerator|Ed25519KeyPairGenerator|RSAEngine|OAEPEncoding)\s*\(/g;
|
|
11
|
+
const RE_JAVA_BC = /\bnew\s+(RSAKeyPairGenerator|DSAKeyPairGenerator|ECKeyPairGenerator|ECDSASigner|Ed25519Signer|Ed448Signer|X25519Agreement|X448Agreement|ECDHBasicAgreement|DHBasicAgreement|X25519KeyPairGenerator|X448KeyPairGenerator|Ed25519KeyPairGenerator|Ed448KeyPairGenerator|X448PrivateKeyParameters|RSAEngine|OAEPEncoding)\s*\(/g;
|
|
12
12
|
// BouncyCastle lightweight-API curve/EdDSA classes as a BARE constructor call —
|
|
13
13
|
// the Kotlin form (`X448KeyPairGenerator()`, no `new` keyword). RE_JAVA_BC above
|
|
14
14
|
// only matches the Java `new <Class>(` form, so Kotlin sources that drive the
|
|
@@ -17,13 +17,27 @@ const RE_JAVA_BC = /\bnew\s+(RSAKeyPairGenerator|DSAKeyPairGenerator|ECKeyPairGe
|
|
|
17
17
|
// while bare `X448Agreement(` routes to the family-specific rules below. Scoped
|
|
18
18
|
// to the exact X448/X25519/Ed448/Ed25519 class names to stay precise.
|
|
19
19
|
const RE_JAVA_BC_CURVE = /(?<!\bnew\s+)\b(X448KeyPairGenerator|X448Agreement|X448PrivateKeyParameters|X25519KeyPairGenerator|X25519Agreement|Ed448KeyPairGenerator|Ed448Signer|Ed25519KeyPairGenerator|Ed25519Signer)\s*\(/g;
|
|
20
|
+
// The non-curve BouncyCastle classes (RSA/EC/DSA/DH keygen, signers, engines) as a
|
|
21
|
+
// BARE constructor call — the Kotlin form, `ECKeyPairGenerator()` with no `new`. Java
|
|
22
|
+
// and Scala instantiate Java classes with `new` (caught by RE_JAVA_BC), so bare calls
|
|
23
|
+
// to these distinctive class names are Kotlin. The `(?<!\bnew\s+)` avoids double-
|
|
24
|
+
// counting the `new` form; routed through the same BC_CLASS_RULES map.
|
|
25
|
+
const RE_JAVA_BC_BARE = /(?<!\bnew\s+)\b(RSAKeyPairGenerator|DSAKeyPairGenerator|ECKeyPairGenerator|ECDSASigner|ECDHBasicAgreement|DHBasicAgreement|RSAEngine|OAEPEncoding)\s*\(/g;
|
|
20
26
|
// Insecure JSSE / TLS configuration expressed in Java source. Mirrors the JS
|
|
21
27
|
// tlsDetector in source.ts (category "tls"): a legacy SSL/TLS protocol version
|
|
22
28
|
// requested from SSLContext, and TLS hostname verification neutered via an
|
|
23
29
|
// all-trusting verifier (Apache HttpClient's NoopHostnameVerifier /
|
|
24
30
|
// ALLOW_ALL_HOSTNAME_VERIFIER).
|
|
25
|
-
|
|
26
|
-
|
|
31
|
+
// `TLSv1(?:\.1)?` catches both TLS 1.0 and the equally-deprecated TLS 1.1 (RFC 8996),
|
|
32
|
+
// mirroring the JS tlsDetector; the closing `"` keeps `"TLSv1.2"`/`"TLSv1.3"`/`"TLS"`
|
|
33
|
+
// from matching. `SSLv2` is included alongside `SSLv3`.
|
|
34
|
+
const RE_JAVA_TLS_LEGACY = /\bSSLContext\s*\.\s*getInstance\s*\(\s*"(SSL|SSLv2|SSLv3|TLSv1(?:\.1)?)"/g;
|
|
35
|
+
// Require a USAGE position, not a bare identifier: `NoopHostnameVerifier` followed by
|
|
36
|
+
// `(` (construction) or `.` (`.INSTANCE`), and `ALLOW_ALL_HOSTNAME_VERIFIER` preceded
|
|
37
|
+
// by `.` (member access). This keeps `new NoopHostnameVerifier()` and
|
|
38
|
+
// `SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER` while dropping the common
|
|
39
|
+
// false positive of a plain `import …NoopHostnameVerifier;` line.
|
|
40
|
+
const RE_JAVA_TLS_NOVERIFY = /\bNoopHostnameVerifier\s*[.(]|\.\s*ALLOW_ALL_HOSTNAME_VERIFIER\b/g;
|
|
27
41
|
// Identifier-form JWT/JOSE signature algorithms (audit F7). The quoted-string
|
|
28
42
|
// alg token ("RS256") is caught by the language-agnostic jwt-jose detector, but
|
|
29
43
|
// the Java JWT libraries pass the alg as an IDENTIFIER, not a string literal:
|
|
@@ -233,6 +247,11 @@ function classifyGetInstance(factory, rawAlg) {
|
|
|
233
247
|
const isSignature = factory === "Signature";
|
|
234
248
|
if (alg.includes("ECDSA"))
|
|
235
249
|
return RULE_JAVA_ECDSA_SIGN;
|
|
250
|
+
// ECIES (EC Integrated Encryption Scheme, incl. `ECIESwithAES-CBC`) is classical EC
|
|
251
|
+
// public-key ENCRYPTION — harvest-now-decrypt-later exposed. Checked before the EC
|
|
252
|
+
// branches below (which would otherwise miss it) and the RSA/DSA checks.
|
|
253
|
+
if (alg.includes("ECIES"))
|
|
254
|
+
return RULE_JAVA_ECDH;
|
|
236
255
|
if (alg.includes("ECDH"))
|
|
237
256
|
return RULE_JAVA_ECDH;
|
|
238
257
|
if (alg === "EC")
|
|
@@ -268,7 +287,10 @@ const BC_CLASS_RULES = {
|
|
|
268
287
|
ECDHBasicAgreement: RULE_JAVA_ECDH,
|
|
269
288
|
DHBasicAgreement: RULE_JAVA_DH,
|
|
270
289
|
X25519KeyPairGenerator: RULE_JAVA_XDH,
|
|
290
|
+
X448KeyPairGenerator: RULE_JAVA_XDH,
|
|
291
|
+
X448PrivateKeyParameters: RULE_JAVA_XDH,
|
|
271
292
|
Ed25519KeyPairGenerator: RULE_JAVA_EDDSA,
|
|
293
|
+
Ed448KeyPairGenerator: RULE_JAVA_EDDSA,
|
|
272
294
|
RSAEngine: RULE_JAVA_RSA,
|
|
273
295
|
OAEPEncoding: RULE_JAVA_RSA,
|
|
274
296
|
};
|
|
@@ -287,7 +309,7 @@ const BC_CURVE_CLASS_RULES = {
|
|
|
287
309
|
/** Detects classical asymmetric crypto in Java / Kotlin (JCA + BouncyCastle). */
|
|
288
310
|
export const javaDetector = {
|
|
289
311
|
id: "java-crypto",
|
|
290
|
-
description: "Classical asymmetric crypto
|
|
312
|
+
description: "Classical asymmetric crypto on the JVM — Java/Kotlin/Scala (JCA getInstance + BouncyCastle)",
|
|
291
313
|
scope: "source",
|
|
292
314
|
language: "java",
|
|
293
315
|
rules: [
|
|
@@ -332,6 +354,14 @@ export const javaDetector = {
|
|
|
332
354
|
return;
|
|
333
355
|
findings.push(findingFromRule(rule, { file, content, index: m.index, matchLength: m[0].length }));
|
|
334
356
|
});
|
|
357
|
+
// Bare (Kotlin-form) constructor calls to the non-curve BC classes — same rules
|
|
358
|
+
// as the `new` form, routed via BC_CLASS_RULES.
|
|
359
|
+
eachMatch(RE_JAVA_BC_BARE, content, (m) => {
|
|
360
|
+
const rule = BC_CLASS_RULES[m[1]];
|
|
361
|
+
if (!rule)
|
|
362
|
+
return;
|
|
363
|
+
findings.push(findingFromRule(rule, { file, content, index: m.index, matchLength: m[0].length }));
|
|
364
|
+
});
|
|
335
365
|
// Legacy SSL/TLS protocol version requested from SSLContext.
|
|
336
366
|
eachMatch(RE_JAVA_TLS_LEGACY, content, (m) => {
|
|
337
367
|
findings.push(findingFromRule(RULE_JAVA_TLS_LEGACY, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"java.js","sourceRoot":"","sources":["../../src/detectors/java.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Source-code detector for classical, non-quantum-safe asymmetric cryptography\n * in Java / Kotlin (the JCA — Java Cryptography Architecture). Same lexical\n * strategy as the other language packs.\n *\n * The JCA funnels almost everything through a handful of factory methods keyed\n * by an ALGORITHM STRING: `KeyPairGenerator.getInstance(\"RSA\")`,\n * `Signature.getInstance(\"SHA256withECDSA\")`, `Cipher.getInstance(\"RSA/ECB/…\")`,\n * `KeyAgreement.getInstance(\"ECDH\")`. So detection here is two steps: match the\n * `<Factory>.getInstance(\"<alg>\")` call, then classify the (factory, alg) pair\n * into a rule. Symmetric / hashing algorithms (\"AES\", \"HmacSHA256\", …) classify\n * to nothing and are ignored. A small set of BouncyCastle lightweight-API class\n * names (`new ECDSASigner()`, `new X25519Agreement()`, …) is matched directly.\n *\n * HNDL policy mirrors the other detectors: KEM / key agreement (RSA encryption,\n * (EC)DH, X25519/X448) is harvest-now-decrypt-later exposed (hndl:true);\n * signatures (RSA/ECDSA/DSA/EdDSA) are hndl:false but forgeable by a quantum\n * attacker. `KeyPairGenerator.getInstance(\"EC\")` is ambiguous (an EC key feeds\n * both ECDSA and ECDH), so it is classified conservatively as\n * key-exchange-capable (hndl:true), exactly as the Node/Python EC keygen rules.\n */\nimport type { Detector, Finding, RuleMeta } from \"../types.js\";\nimport { JAVA_EXTENSIONS, eachMatch, findingFromRule, hasExtension } from \"../detect-utils.js\";\nimport { CWE_BROKEN_CRYPTO, CWE_CERT_VALIDATION, CWE_WEAK_STRENGTH } from \"../cwe.js\";\n\n/* -------------------------------------------------------------------------- */\n/* Regexes */\n/* -------------------------------------------------------------------------- */\n\n// <Factory>.getInstance(\"<alg>\") — the JCA entry points that carry asymmetric\n// algorithms. KeyGenerator/MessageDigest/Mac are intentionally excluded (they\n// are symmetric / hashing only).\nconst RE_JAVA_GETINSTANCE =\n /\\b(KeyPairGenerator|Signature|Cipher|KeyAgreement|KeyFactory)\\s*\\.\\s*getInstance\\s*\\(\\s*\"([^\"]+)\"/g;\n\n// BouncyCastle lightweight-API class instantiations.\nconst RE_JAVA_BC =\n /\\bnew\\s+(RSAKeyPairGenerator|DSAKeyPairGenerator|ECKeyPairGenerator|ECDSASigner|Ed25519Signer|Ed448Signer|X25519Agreement|X448Agreement|ECDHBasicAgreement|DHBasicAgreement|X25519KeyPairGenerator|Ed25519KeyPairGenerator|RSAEngine|OAEPEncoding)\\s*\\(/g;\n\n// BouncyCastle lightweight-API curve/EdDSA classes as a BARE constructor call —\n// the Kotlin form (`X448KeyPairGenerator()`, no `new` keyword). RE_JAVA_BC above\n// only matches the Java `new <Class>(` form, so Kotlin sources that drive the\n// lightweight API directly are missed. The negative lookbehind `(?<!\\bnew\\s+)`\n// keeps this additive: `new X448Agreement(` stays with RE_JAVA_BC (java-xdh),\n// while bare `X448Agreement(` routes to the family-specific rules below. Scoped\n// to the exact X448/X25519/Ed448/Ed25519 class names to stay precise.\nconst RE_JAVA_BC_CURVE =\n /(?<!\\bnew\\s+)\\b(X448KeyPairGenerator|X448Agreement|X448PrivateKeyParameters|X25519KeyPairGenerator|X25519Agreement|Ed448KeyPairGenerator|Ed448Signer|Ed25519KeyPairGenerator|Ed25519Signer)\\s*\\(/g;\n\n// Insecure JSSE / TLS configuration expressed in Java source. Mirrors the JS\n// tlsDetector in source.ts (category \"tls\"): a legacy SSL/TLS protocol version\n// requested from SSLContext, and TLS hostname verification neutered via an\n// all-trusting verifier (Apache HttpClient's NoopHostnameVerifier /\n// ALLOW_ALL_HOSTNAME_VERIFIER).\nconst RE_JAVA_TLS_LEGACY = /\\bSSLContext\\s*\\.\\s*getInstance\\s*\\(\\s*\"(SSL|SSLv3|TLSv1)\"/g;\nconst RE_JAVA_TLS_NOVERIFY = /\\b(NoopHostnameVerifier|ALLOW_ALL_HOSTNAME_VERIFIER)\\b/g;\n\n// Identifier-form JWT/JOSE signature algorithms (audit F7). The quoted-string\n// alg token (\"RS256\") is caught by the language-agnostic jwt-jose detector, but\n// the Java JWT libraries pass the alg as an IDENTIFIER, not a string literal:\n// jjwt's `SignatureAlgorithm.RS256` and auth0 java-jwt's `Algorithm.RSA256` /\n// `Algorithm.ECDSA256`. (\"SignatureAlgorithm\" has no word boundary before its\n// \"Algorithm\", so the auth0 branch cannot re-match the jjwt form.)\nconst RE_JAVA_JWT_ALG =\n /\\bSignatureAlgorithm\\.(?:RS|PS|ES)(?:256|384|512)\\b|\\bAlgorithm\\.(?:RSA|ECDSA)(?:256|384|512)\\b/g;\n\n/* -------------------------------------------------------------------------- */\n/* Rule catalog */\n/* -------------------------------------------------------------------------- */\n\nconst RULE_JAVA_RSA: RuleMeta = {\n id: \"java-rsa\",\n title: \"Java RSA key/encryption\",\n description: \"JCA RSA KeyPairGenerator / Cipher / KeyFactory\",\n category: \"kem\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"RSA\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"Classical RSA (Java/JCA) is not quantum-safe and RSA encryption is HNDL-exposed.\",\n};\nconst RULE_JAVA_RSA_SIGN: RuleMeta = {\n id: \"java-rsa-sign\",\n title: \"Java RSA signature\",\n description: 'JCA Signature.getInstance(\"…withRSA\")',\n category: \"signature\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"RSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"Classical RSA signing (Java/JCA) is forgeable by a quantum attacker.\",\n remediation: \"ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205)\",\n};\nconst RULE_JAVA_EC_KEYGEN: RuleMeta = {\n id: \"java-ec-keygen\",\n title: \"Java EC key generation\",\n description: 'JCA KeyPairGenerator.getInstance(\"EC\")',\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"ECDH\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Generates a classical EC key pair (Java/JCA). EC keys feed BOTH ECDSA signatures and ECDH key agreement; the ECDH path is harvest-now-decrypt-later exposed.\",\n remediation:\n \"For key agreement: hybrid X25519MLKEM768 (ML-KEM-768). For signatures: ML-DSA-65 (FIPS 204).\",\n};\nconst RULE_JAVA_ECDSA_SIGN: RuleMeta = {\n id: \"java-ecdsa-sign\",\n title: \"Java ECDSA signature\",\n description: 'JCA Signature.getInstance(\"…withECDSA\")',\n category: \"signature\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"ECDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"Classical ECDSA signing (Java/JCA) is forgeable by a quantum attacker.\",\n remediation: \"ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205)\",\n};\nconst RULE_JAVA_ECDH: RuleMeta = {\n id: \"java-ecdh\",\n title: \"Java ECDH key agreement\",\n description: 'JCA KeyAgreement.getInstance(\"ECDH\")',\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"ECDH\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Elliptic-curve Diffie-Hellman (Java/JCA) is broken by Shor's algorithm (harvest-now-decrypt-later).\",\n};\nconst RULE_JAVA_DSA: RuleMeta = {\n id: \"java-dsa\",\n title: \"Java DSA key/signature\",\n description: \"JCA DSA KeyPairGenerator / Signature\",\n category: \"signature\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"DSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"Classical DSA (Java/JCA) is deprecated and forgeable by a quantum attacker.\",\n remediation: \"Rotate off DSA and migrate to ML-DSA-65 (FIPS 204).\",\n};\nconst RULE_JAVA_DH: RuleMeta = {\n id: \"java-dh\",\n title: \"Java Diffie-Hellman key exchange\",\n description: \"JCA DiffieHellman KeyPairGenerator / KeyAgreement\",\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"DH\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Finite-field Diffie-Hellman (Java/JCA) is broken by Shor's algorithm (harvest-now-decrypt-later).\",\n};\nconst RULE_JAVA_XDH: RuleMeta = {\n id: \"java-xdh\",\n title: \"Java X25519/X448 key agreement\",\n description: \"JCA XDH / X25519 / X448 (KeyPairGenerator / KeyAgreement)\",\n category: \"key-exchange\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"X25519\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"X25519/X448 (Java/JCA) is modern but still classical key agreement — harvest-now-decrypt-later.\",\n};\nconst RULE_JAVA_EDDSA: RuleMeta = {\n id: \"java-eddsa\",\n title: \"Java Ed25519/Ed448 signature\",\n description: \"JCA EdDSA / Ed25519 / Ed448\",\n category: \"signature\",\n severity: \"low\",\n confidence: \"high\",\n algorithm: \"EdDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"Ed25519/Ed448 (Java/JCA) is a modern but still classical signature scheme.\",\n};\n// BouncyCastle lightweight-API rules for bare (Kotlin-form) constructor calls.\n// Split by family so X448 and X25519 report their own algorithm string (java-xdh\n// lumps both under \"X25519\"). Severity/CWE copied from the JCA siblings above.\nconst RULE_JAVA_BC_X448: RuleMeta = {\n id: \"java-bc-x448\",\n title: \"Java/Kotlin X448 key agreement (BouncyCastle lightweight API)\",\n description: \"BouncyCastle X448KeyPairGenerator / X448Agreement / X448PrivateKeyParameters\",\n category: \"key-exchange\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"X448\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"X448 (Java/Kotlin, BouncyCastle lightweight API) is modern but still classical key agreement — harvest-now-decrypt-later.\",\n};\nconst RULE_JAVA_BC_X25519: RuleMeta = {\n id: \"java-bc-x25519\",\n title: \"Java/Kotlin X25519 key agreement (BouncyCastle lightweight API)\",\n description: \"BouncyCastle X25519KeyPairGenerator / X25519Agreement\",\n category: \"key-exchange\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"X25519\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"X25519 (Java/Kotlin, BouncyCastle lightweight API) is modern but still classical key agreement — harvest-now-decrypt-later.\",\n};\nconst RULE_JAVA_BC_EDDSA: RuleMeta = {\n id: \"java-bc-eddsa\",\n title: \"Java/Kotlin Ed25519/Ed448 signature (BouncyCastle lightweight API)\",\n description:\n \"BouncyCastle Ed448KeyPairGenerator / Ed448Signer / Ed25519KeyPairGenerator / Ed25519Signer\",\n category: \"signature\",\n severity: \"low\",\n confidence: \"high\",\n algorithm: \"EdDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Ed25519/Ed448 (Java/Kotlin, BouncyCastle lightweight API) is a modern but still classical signature scheme.\",\n};\nconst RULE_JAVA_TLS_LEGACY: RuleMeta = {\n id: \"java-tls-legacy-version\",\n title: \"Legacy SSL/TLS version requested\",\n description: 'SSLContext.getInstance(\"SSL\" | \"SSLv3\" | \"TLSv1\")',\n category: \"tls\",\n severity: \"medium\",\n confidence: \"high\",\n hndl: false,\n cwe: CWE_WEAK_STRENGTH,\n message: \"SSL/SSLv3/TLS 1.0 are deprecated and insecure (Java/JSSE); require TLS 1.3.\",\n remediation: 'Use SSLContext.getInstance(\"TLSv1.3\") and prefer PQC-hybrid key exchange.',\n};\nconst RULE_JAVA_TLS_NOVERIFY: RuleMeta = {\n id: \"java-tls-hostname-verification-disabled\",\n title: \"TLS hostname verification disabled\",\n description: \"NoopHostnameVerifier / ALLOW_ALL_HOSTNAME_VERIFIER\",\n category: \"tls\",\n severity: \"high\",\n confidence: \"high\",\n hndl: false,\n cwe: CWE_CERT_VALIDATION,\n message: \"An all-trusting hostname verifier (Java) disables TLS hostname checking (MITM risk).\",\n remediation: \"Remove the all-trusting verifier; rely on the default hostname verifier.\",\n};\nconst RULE_JAVA_JWT_ALG: RuleMeta = {\n id: \"java-jwt-alg\",\n title: \"Java identifier-form JWT/JOSE algorithm\",\n description: \"jjwt SignatureAlgorithm.RS/PS/ES* / auth0 Algorithm.RSA*/ECDSA*\",\n category: \"signature\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"A classical JWT/JOSE signature algorithm (Java, identifier form) is used, forgeable by a quantum attacker.\",\n remediation: \"ML-DSA-65 (FIPS 204); track IETF PQC JOSE/COSE algorithms\",\n};\n\n/**\n * Classify a `<factory>.getInstance(\"<alg>\")` pair into a rule, or null when the\n * algorithm is not classical asymmetric crypto (AES, HMAC, PBKDF2, hashes, …).\n * `alg` is normalised to upper-case with any Cipher transformation suffix\n * (`RSA/ECB/OAEPPadding` → `RSA`) stripped.\n */\nfunction classifyGetInstance(factory: string, rawAlg: string): RuleMeta | null {\n const alg = rawAlg.split(\"/\")[0].trim().toUpperCase();\n const isSignature = factory === \"Signature\";\n\n if (alg.includes(\"ECDSA\")) return RULE_JAVA_ECDSA_SIGN;\n if (alg.includes(\"ECDH\")) return RULE_JAVA_ECDH;\n if (alg === \"EC\") return isSignature ? RULE_JAVA_ECDSA_SIGN : RULE_JAVA_EC_KEYGEN;\n if (alg.includes(\"ED25519\") || alg.includes(\"ED448\") || alg.includes(\"EDDSA\"))\n return RULE_JAVA_EDDSA;\n if (alg.includes(\"X25519\") || alg.includes(\"X448\") || alg === \"XDH\") return RULE_JAVA_XDH;\n // RSASSA-PSS is an RSA *signature* scheme, not encryption/KEM. The string\n // contains \"RSA\", so it must be caught here — BEFORE the generic RSA branch\n // below, which would otherwise (mis)classify it as HNDL-exposed RSA\n // encryption (java-rsa / hndl:true). Signatures are hndl:false. (Fixes F8.)\n if (alg.includes(\"PSS\")) return RULE_JAVA_RSA_SIGN;\n if (alg.includes(\"RSA\")) return isSignature ? RULE_JAVA_RSA_SIGN : RULE_JAVA_RSA;\n if (alg.includes(\"DSA\")) return RULE_JAVA_DSA; // ECDSA already handled above\n if (alg.includes(\"DH\") || alg.includes(\"DIFFIEHELLMAN\")) return RULE_JAVA_DH;\n return null;\n}\n\n/** BouncyCastle lightweight-API class name → rule. */\nconst BC_CLASS_RULES: Record<string, RuleMeta> = {\n RSAKeyPairGenerator: RULE_JAVA_RSA,\n DSAKeyPairGenerator: RULE_JAVA_DSA,\n ECKeyPairGenerator: RULE_JAVA_EC_KEYGEN,\n ECDSASigner: RULE_JAVA_ECDSA_SIGN,\n Ed25519Signer: RULE_JAVA_EDDSA,\n Ed448Signer: RULE_JAVA_EDDSA,\n X25519Agreement: RULE_JAVA_XDH,\n X448Agreement: RULE_JAVA_XDH,\n ECDHBasicAgreement: RULE_JAVA_ECDH,\n DHBasicAgreement: RULE_JAVA_DH,\n X25519KeyPairGenerator: RULE_JAVA_XDH,\n Ed25519KeyPairGenerator: RULE_JAVA_EDDSA,\n RSAEngine: RULE_JAVA_RSA,\n OAEPEncoding: RULE_JAVA_RSA,\n};\n\n/** BouncyCastle lightweight-API bare-constructor class name → family rule. */\nconst BC_CURVE_CLASS_RULES: Record<string, RuleMeta> = {\n X448KeyPairGenerator: RULE_JAVA_BC_X448,\n X448Agreement: RULE_JAVA_BC_X448,\n X448PrivateKeyParameters: RULE_JAVA_BC_X448,\n X25519KeyPairGenerator: RULE_JAVA_BC_X25519,\n X25519Agreement: RULE_JAVA_BC_X25519,\n Ed448KeyPairGenerator: RULE_JAVA_BC_EDDSA,\n Ed448Signer: RULE_JAVA_BC_EDDSA,\n Ed25519KeyPairGenerator: RULE_JAVA_BC_EDDSA,\n Ed25519Signer: RULE_JAVA_BC_EDDSA,\n};\n\n/** Detects classical asymmetric crypto in Java / Kotlin (JCA + BouncyCastle). */\nexport const javaDetector: Detector = {\n id: \"java-crypto\",\n description: \"Classical asymmetric crypto in Java/Kotlin (JCA getInstance + BouncyCastle)\",\n scope: \"source\",\n language: \"java\",\n rules: [\n RULE_JAVA_RSA,\n RULE_JAVA_RSA_SIGN,\n RULE_JAVA_EC_KEYGEN,\n RULE_JAVA_ECDSA_SIGN,\n RULE_JAVA_ECDH,\n RULE_JAVA_DSA,\n RULE_JAVA_DH,\n RULE_JAVA_XDH,\n RULE_JAVA_EDDSA,\n RULE_JAVA_BC_X448,\n RULE_JAVA_BC_X25519,\n RULE_JAVA_BC_EDDSA,\n RULE_JAVA_TLS_LEGACY,\n RULE_JAVA_TLS_NOVERIFY,\n RULE_JAVA_JWT_ALG,\n ],\n appliesTo: (f) => hasExtension(f, JAVA_EXTENSIONS),\n detect({ file, content }): Finding[] {\n const findings: Finding[] = [];\n\n eachMatch(RE_JAVA_GETINSTANCE, content, (m) => {\n const rule = classifyGetInstance(m[1], m[2]);\n if (!rule) return; // symmetric / hashing algorithm — not our concern.\n findings.push(\n findingFromRule(rule, { file, content, index: m.index, matchLength: m[0].length }),\n );\n });\n\n eachMatch(RE_JAVA_BC, content, (m) => {\n const rule = BC_CLASS_RULES[m[1]];\n if (!rule) return;\n findings.push(\n findingFromRule(rule, { file, content, index: m.index, matchLength: m[0].length }),\n );\n });\n\n // BouncyCastle lightweight-API classes as a bare constructor call (Kotlin\n // form, no `new`). RE_JAVA_BC_CURVE's negative lookbehind excludes the\n // `new <Class>(` form already handled above, so this only adds the missed\n // 448/25519 Kotlin-style matches — no double-counting.\n eachMatch(RE_JAVA_BC_CURVE, content, (m) => {\n const rule = BC_CURVE_CLASS_RULES[m[1]];\n if (!rule) return;\n findings.push(\n findingFromRule(rule, { file, content, index: m.index, matchLength: m[0].length }),\n );\n });\n\n // Legacy SSL/TLS protocol version requested from SSLContext.\n eachMatch(RE_JAVA_TLS_LEGACY, content, (m) => {\n findings.push(\n findingFromRule(RULE_JAVA_TLS_LEGACY, {\n file,\n content,\n index: m.index,\n matchLength: m[0].length,\n }),\n );\n });\n\n // All-trusting hostname verifier — disables TLS hostname verification.\n eachMatch(RE_JAVA_TLS_NOVERIFY, content, (m) => {\n findings.push(\n findingFromRule(RULE_JAVA_TLS_NOVERIFY, {\n file,\n content,\n index: m.index,\n matchLength: m[0].length,\n }),\n );\n });\n\n // Identifier-form JWT/JOSE signature algorithms (jjwt / auth0).\n eachMatch(RE_JAVA_JWT_ALG, content, (m) => {\n findings.push(\n findingFromRule(RULE_JAVA_JWT_ALG, {\n file,\n content,\n index: m.index,\n matchLength: m[0].length,\n }),\n );\n });\n\n return findings;\n },\n};\n"]}
|
|
1
|
+
{"version":3,"file":"java.js","sourceRoot":"","sources":["../../src/detectors/java.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Source-code detector for classical, non-quantum-safe asymmetric cryptography\n * in Java / Kotlin (the JCA — Java Cryptography Architecture). Same lexical\n * strategy as the other language packs.\n *\n * The JCA funnels almost everything through a handful of factory methods keyed\n * by an ALGORITHM STRING: `KeyPairGenerator.getInstance(\"RSA\")`,\n * `Signature.getInstance(\"SHA256withECDSA\")`, `Cipher.getInstance(\"RSA/ECB/…\")`,\n * `KeyAgreement.getInstance(\"ECDH\")`. So detection here is two steps: match the\n * `<Factory>.getInstance(\"<alg>\")` call, then classify the (factory, alg) pair\n * into a rule. Symmetric / hashing algorithms (\"AES\", \"HmacSHA256\", …) classify\n * to nothing and are ignored. A small set of BouncyCastle lightweight-API class\n * names (`new ECDSASigner()`, `new X25519Agreement()`, …) is matched directly.\n *\n * HNDL policy mirrors the other detectors: KEM / key agreement (RSA encryption,\n * (EC)DH, X25519/X448) is harvest-now-decrypt-later exposed (hndl:true);\n * signatures (RSA/ECDSA/DSA/EdDSA) are hndl:false but forgeable by a quantum\n * attacker. `KeyPairGenerator.getInstance(\"EC\")` is ambiguous (an EC key feeds\n * both ECDSA and ECDH), so it is classified conservatively as\n * key-exchange-capable (hndl:true), exactly as the Node/Python EC keygen rules.\n */\nimport type { Detector, Finding, RuleMeta } from \"../types.js\";\nimport { JAVA_EXTENSIONS, eachMatch, findingFromRule, hasExtension } from \"../detect-utils.js\";\nimport { CWE_BROKEN_CRYPTO, CWE_CERT_VALIDATION, CWE_WEAK_STRENGTH } from \"../cwe.js\";\n\n/* -------------------------------------------------------------------------- */\n/* Regexes */\n/* -------------------------------------------------------------------------- */\n\n// <Factory>.getInstance(\"<alg>\") — the JCA entry points that carry asymmetric\n// algorithms. KeyGenerator/MessageDigest/Mac are intentionally excluded (they\n// are symmetric / hashing only).\nconst RE_JAVA_GETINSTANCE =\n /\\b(KeyPairGenerator|Signature|Cipher|KeyAgreement|KeyFactory)\\s*\\.\\s*getInstance\\s*\\(\\s*\"([^\"]+)\"/g;\n\n// BouncyCastle lightweight-API class instantiations.\nconst RE_JAVA_BC =\n /\\bnew\\s+(RSAKeyPairGenerator|DSAKeyPairGenerator|ECKeyPairGenerator|ECDSASigner|Ed25519Signer|Ed448Signer|X25519Agreement|X448Agreement|ECDHBasicAgreement|DHBasicAgreement|X25519KeyPairGenerator|X448KeyPairGenerator|Ed25519KeyPairGenerator|Ed448KeyPairGenerator|X448PrivateKeyParameters|RSAEngine|OAEPEncoding)\\s*\\(/g;\n\n// BouncyCastle lightweight-API curve/EdDSA classes as a BARE constructor call —\n// the Kotlin form (`X448KeyPairGenerator()`, no `new` keyword). RE_JAVA_BC above\n// only matches the Java `new <Class>(` form, so Kotlin sources that drive the\n// lightweight API directly are missed. The negative lookbehind `(?<!\\bnew\\s+)`\n// keeps this additive: `new X448Agreement(` stays with RE_JAVA_BC (java-xdh),\n// while bare `X448Agreement(` routes to the family-specific rules below. Scoped\n// to the exact X448/X25519/Ed448/Ed25519 class names to stay precise.\nconst RE_JAVA_BC_CURVE =\n /(?<!\\bnew\\s+)\\b(X448KeyPairGenerator|X448Agreement|X448PrivateKeyParameters|X25519KeyPairGenerator|X25519Agreement|Ed448KeyPairGenerator|Ed448Signer|Ed25519KeyPairGenerator|Ed25519Signer)\\s*\\(/g;\n\n// The non-curve BouncyCastle classes (RSA/EC/DSA/DH keygen, signers, engines) as a\n// BARE constructor call — the Kotlin form, `ECKeyPairGenerator()` with no `new`. Java\n// and Scala instantiate Java classes with `new` (caught by RE_JAVA_BC), so bare calls\n// to these distinctive class names are Kotlin. The `(?<!\\bnew\\s+)` avoids double-\n// counting the `new` form; routed through the same BC_CLASS_RULES map.\nconst RE_JAVA_BC_BARE =\n /(?<!\\bnew\\s+)\\b(RSAKeyPairGenerator|DSAKeyPairGenerator|ECKeyPairGenerator|ECDSASigner|ECDHBasicAgreement|DHBasicAgreement|RSAEngine|OAEPEncoding)\\s*\\(/g;\n\n// Insecure JSSE / TLS configuration expressed in Java source. Mirrors the JS\n// tlsDetector in source.ts (category \"tls\"): a legacy SSL/TLS protocol version\n// requested from SSLContext, and TLS hostname verification neutered via an\n// all-trusting verifier (Apache HttpClient's NoopHostnameVerifier /\n// ALLOW_ALL_HOSTNAME_VERIFIER).\n// `TLSv1(?:\\.1)?` catches both TLS 1.0 and the equally-deprecated TLS 1.1 (RFC 8996),\n// mirroring the JS tlsDetector; the closing `\"` keeps `\"TLSv1.2\"`/`\"TLSv1.3\"`/`\"TLS\"`\n// from matching. `SSLv2` is included alongside `SSLv3`.\nconst RE_JAVA_TLS_LEGACY =\n /\\bSSLContext\\s*\\.\\s*getInstance\\s*\\(\\s*\"(SSL|SSLv2|SSLv3|TLSv1(?:\\.1)?)\"/g;\n// Require a USAGE position, not a bare identifier: `NoopHostnameVerifier` followed by\n// `(` (construction) or `.` (`.INSTANCE`), and `ALLOW_ALL_HOSTNAME_VERIFIER` preceded\n// by `.` (member access). This keeps `new NoopHostnameVerifier()` and\n// `SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER` while dropping the common\n// false positive of a plain `import …NoopHostnameVerifier;` line.\nconst RE_JAVA_TLS_NOVERIFY = /\\bNoopHostnameVerifier\\s*[.(]|\\.\\s*ALLOW_ALL_HOSTNAME_VERIFIER\\b/g;\n\n// Identifier-form JWT/JOSE signature algorithms (audit F7). The quoted-string\n// alg token (\"RS256\") is caught by the language-agnostic jwt-jose detector, but\n// the Java JWT libraries pass the alg as an IDENTIFIER, not a string literal:\n// jjwt's `SignatureAlgorithm.RS256` and auth0 java-jwt's `Algorithm.RSA256` /\n// `Algorithm.ECDSA256`. (\"SignatureAlgorithm\" has no word boundary before its\n// \"Algorithm\", so the auth0 branch cannot re-match the jjwt form.)\nconst RE_JAVA_JWT_ALG =\n /\\bSignatureAlgorithm\\.(?:RS|PS|ES)(?:256|384|512)\\b|\\bAlgorithm\\.(?:RSA|ECDSA)(?:256|384|512)\\b/g;\n\n/* -------------------------------------------------------------------------- */\n/* Rule catalog */\n/* -------------------------------------------------------------------------- */\n\nconst RULE_JAVA_RSA: RuleMeta = {\n id: \"java-rsa\",\n title: \"Java RSA key/encryption\",\n description: \"JCA RSA KeyPairGenerator / Cipher / KeyFactory\",\n category: \"kem\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"RSA\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"Classical RSA (Java/JCA) is not quantum-safe and RSA encryption is HNDL-exposed.\",\n};\nconst RULE_JAVA_RSA_SIGN: RuleMeta = {\n id: \"java-rsa-sign\",\n title: \"Java RSA signature\",\n description: 'JCA Signature.getInstance(\"…withRSA\")',\n category: \"signature\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"RSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"Classical RSA signing (Java/JCA) is forgeable by a quantum attacker.\",\n remediation: \"ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205)\",\n};\nconst RULE_JAVA_EC_KEYGEN: RuleMeta = {\n id: \"java-ec-keygen\",\n title: \"Java EC key generation\",\n description: 'JCA KeyPairGenerator.getInstance(\"EC\")',\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"ECDH\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Generates a classical EC key pair (Java/JCA). EC keys feed BOTH ECDSA signatures and ECDH key agreement; the ECDH path is harvest-now-decrypt-later exposed.\",\n remediation:\n \"For key agreement: hybrid X25519MLKEM768 (ML-KEM-768). For signatures: ML-DSA-65 (FIPS 204).\",\n};\nconst RULE_JAVA_ECDSA_SIGN: RuleMeta = {\n id: \"java-ecdsa-sign\",\n title: \"Java ECDSA signature\",\n description: 'JCA Signature.getInstance(\"…withECDSA\")',\n category: \"signature\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"ECDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"Classical ECDSA signing (Java/JCA) is forgeable by a quantum attacker.\",\n remediation: \"ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205)\",\n};\nconst RULE_JAVA_ECDH: RuleMeta = {\n id: \"java-ecdh\",\n title: \"Java ECDH key agreement\",\n description: 'JCA KeyAgreement.getInstance(\"ECDH\")',\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"ECDH\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Elliptic-curve Diffie-Hellman (Java/JCA) is broken by Shor's algorithm (harvest-now-decrypt-later).\",\n};\nconst RULE_JAVA_DSA: RuleMeta = {\n id: \"java-dsa\",\n title: \"Java DSA key/signature\",\n description: \"JCA DSA KeyPairGenerator / Signature\",\n category: \"signature\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"DSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"Classical DSA (Java/JCA) is deprecated and forgeable by a quantum attacker.\",\n remediation: \"Rotate off DSA and migrate to ML-DSA-65 (FIPS 204).\",\n};\nconst RULE_JAVA_DH: RuleMeta = {\n id: \"java-dh\",\n title: \"Java Diffie-Hellman key exchange\",\n description: \"JCA DiffieHellman KeyPairGenerator / KeyAgreement\",\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"DH\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Finite-field Diffie-Hellman (Java/JCA) is broken by Shor's algorithm (harvest-now-decrypt-later).\",\n};\nconst RULE_JAVA_XDH: RuleMeta = {\n id: \"java-xdh\",\n title: \"Java X25519/X448 key agreement\",\n description: \"JCA XDH / X25519 / X448 (KeyPairGenerator / KeyAgreement)\",\n category: \"key-exchange\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"X25519\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"X25519/X448 (Java/JCA) is modern but still classical key agreement — harvest-now-decrypt-later.\",\n};\nconst RULE_JAVA_EDDSA: RuleMeta = {\n id: \"java-eddsa\",\n title: \"Java Ed25519/Ed448 signature\",\n description: \"JCA EdDSA / Ed25519 / Ed448\",\n category: \"signature\",\n severity: \"low\",\n confidence: \"high\",\n algorithm: \"EdDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"Ed25519/Ed448 (Java/JCA) is a modern but still classical signature scheme.\",\n};\n// BouncyCastle lightweight-API rules for bare (Kotlin-form) constructor calls.\n// Split by family so X448 and X25519 report their own algorithm string (java-xdh\n// lumps both under \"X25519\"). Severity/CWE copied from the JCA siblings above.\nconst RULE_JAVA_BC_X448: RuleMeta = {\n id: \"java-bc-x448\",\n title: \"Java/Kotlin X448 key agreement (BouncyCastle lightweight API)\",\n description: \"BouncyCastle X448KeyPairGenerator / X448Agreement / X448PrivateKeyParameters\",\n category: \"key-exchange\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"X448\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"X448 (Java/Kotlin, BouncyCastle lightweight API) is modern but still classical key agreement — harvest-now-decrypt-later.\",\n};\nconst RULE_JAVA_BC_X25519: RuleMeta = {\n id: \"java-bc-x25519\",\n title: \"Java/Kotlin X25519 key agreement (BouncyCastle lightweight API)\",\n description: \"BouncyCastle X25519KeyPairGenerator / X25519Agreement\",\n category: \"key-exchange\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"X25519\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"X25519 (Java/Kotlin, BouncyCastle lightweight API) is modern but still classical key agreement — harvest-now-decrypt-later.\",\n};\nconst RULE_JAVA_BC_EDDSA: RuleMeta = {\n id: \"java-bc-eddsa\",\n title: \"Java/Kotlin Ed25519/Ed448 signature (BouncyCastle lightweight API)\",\n description:\n \"BouncyCastle Ed448KeyPairGenerator / Ed448Signer / Ed25519KeyPairGenerator / Ed25519Signer\",\n category: \"signature\",\n severity: \"low\",\n confidence: \"high\",\n algorithm: \"EdDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Ed25519/Ed448 (Java/Kotlin, BouncyCastle lightweight API) is a modern but still classical signature scheme.\",\n};\nconst RULE_JAVA_TLS_LEGACY: RuleMeta = {\n id: \"java-tls-legacy-version\",\n title: \"Legacy SSL/TLS version requested\",\n description: 'SSLContext.getInstance(\"SSL\" | \"SSLv3\" | \"TLSv1\")',\n category: \"tls\",\n severity: \"medium\",\n confidence: \"high\",\n hndl: false,\n cwe: CWE_WEAK_STRENGTH,\n message: \"SSL/SSLv3/TLS 1.0 are deprecated and insecure (Java/JSSE); require TLS 1.3.\",\n remediation: 'Use SSLContext.getInstance(\"TLSv1.3\") and prefer PQC-hybrid key exchange.',\n};\nconst RULE_JAVA_TLS_NOVERIFY: RuleMeta = {\n id: \"java-tls-hostname-verification-disabled\",\n title: \"TLS hostname verification disabled\",\n description: \"NoopHostnameVerifier / ALLOW_ALL_HOSTNAME_VERIFIER\",\n category: \"tls\",\n severity: \"high\",\n confidence: \"high\",\n hndl: false,\n cwe: CWE_CERT_VALIDATION,\n message: \"An all-trusting hostname verifier (Java) disables TLS hostname checking (MITM risk).\",\n remediation: \"Remove the all-trusting verifier; rely on the default hostname verifier.\",\n};\nconst RULE_JAVA_JWT_ALG: RuleMeta = {\n id: \"java-jwt-alg\",\n title: \"Java identifier-form JWT/JOSE algorithm\",\n description: \"jjwt SignatureAlgorithm.RS/PS/ES* / auth0 Algorithm.RSA*/ECDSA*\",\n category: \"signature\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"A classical JWT/JOSE signature algorithm (Java, identifier form) is used, forgeable by a quantum attacker.\",\n remediation: \"ML-DSA-65 (FIPS 204); track IETF PQC JOSE/COSE algorithms\",\n};\n\n/**\n * Classify a `<factory>.getInstance(\"<alg>\")` pair into a rule, or null when the\n * algorithm is not classical asymmetric crypto (AES, HMAC, PBKDF2, hashes, …).\n * `alg` is normalised to upper-case with any Cipher transformation suffix\n * (`RSA/ECB/OAEPPadding` → `RSA`) stripped.\n */\nfunction classifyGetInstance(factory: string, rawAlg: string): RuleMeta | null {\n const alg = rawAlg.split(\"/\")[0].trim().toUpperCase();\n const isSignature = factory === \"Signature\";\n\n if (alg.includes(\"ECDSA\")) return RULE_JAVA_ECDSA_SIGN;\n // ECIES (EC Integrated Encryption Scheme, incl. `ECIESwithAES-CBC`) is classical EC\n // public-key ENCRYPTION — harvest-now-decrypt-later exposed. Checked before the EC\n // branches below (which would otherwise miss it) and the RSA/DSA checks.\n if (alg.includes(\"ECIES\")) return RULE_JAVA_ECDH;\n if (alg.includes(\"ECDH\")) return RULE_JAVA_ECDH;\n if (alg === \"EC\") return isSignature ? RULE_JAVA_ECDSA_SIGN : RULE_JAVA_EC_KEYGEN;\n if (alg.includes(\"ED25519\") || alg.includes(\"ED448\") || alg.includes(\"EDDSA\"))\n return RULE_JAVA_EDDSA;\n if (alg.includes(\"X25519\") || alg.includes(\"X448\") || alg === \"XDH\") return RULE_JAVA_XDH;\n // RSASSA-PSS is an RSA *signature* scheme, not encryption/KEM. The string\n // contains \"RSA\", so it must be caught here — BEFORE the generic RSA branch\n // below, which would otherwise (mis)classify it as HNDL-exposed RSA\n // encryption (java-rsa / hndl:true). Signatures are hndl:false. (Fixes F8.)\n if (alg.includes(\"PSS\")) return RULE_JAVA_RSA_SIGN;\n if (alg.includes(\"RSA\")) return isSignature ? RULE_JAVA_RSA_SIGN : RULE_JAVA_RSA;\n if (alg.includes(\"DSA\")) return RULE_JAVA_DSA; // ECDSA already handled above\n if (alg.includes(\"DH\") || alg.includes(\"DIFFIEHELLMAN\")) return RULE_JAVA_DH;\n return null;\n}\n\n/** BouncyCastle lightweight-API class name → rule. */\nconst BC_CLASS_RULES: Record<string, RuleMeta> = {\n RSAKeyPairGenerator: RULE_JAVA_RSA,\n DSAKeyPairGenerator: RULE_JAVA_DSA,\n ECKeyPairGenerator: RULE_JAVA_EC_KEYGEN,\n ECDSASigner: RULE_JAVA_ECDSA_SIGN,\n Ed25519Signer: RULE_JAVA_EDDSA,\n Ed448Signer: RULE_JAVA_EDDSA,\n X25519Agreement: RULE_JAVA_XDH,\n X448Agreement: RULE_JAVA_XDH,\n ECDHBasicAgreement: RULE_JAVA_ECDH,\n DHBasicAgreement: RULE_JAVA_DH,\n X25519KeyPairGenerator: RULE_JAVA_XDH,\n X448KeyPairGenerator: RULE_JAVA_XDH,\n X448PrivateKeyParameters: RULE_JAVA_XDH,\n Ed25519KeyPairGenerator: RULE_JAVA_EDDSA,\n Ed448KeyPairGenerator: RULE_JAVA_EDDSA,\n RSAEngine: RULE_JAVA_RSA,\n OAEPEncoding: RULE_JAVA_RSA,\n};\n\n/** BouncyCastle lightweight-API bare-constructor class name → family rule. */\nconst BC_CURVE_CLASS_RULES: Record<string, RuleMeta> = {\n X448KeyPairGenerator: RULE_JAVA_BC_X448,\n X448Agreement: RULE_JAVA_BC_X448,\n X448PrivateKeyParameters: RULE_JAVA_BC_X448,\n X25519KeyPairGenerator: RULE_JAVA_BC_X25519,\n X25519Agreement: RULE_JAVA_BC_X25519,\n Ed448KeyPairGenerator: RULE_JAVA_BC_EDDSA,\n Ed448Signer: RULE_JAVA_BC_EDDSA,\n Ed25519KeyPairGenerator: RULE_JAVA_BC_EDDSA,\n Ed25519Signer: RULE_JAVA_BC_EDDSA,\n};\n\n/** Detects classical asymmetric crypto in Java / Kotlin (JCA + BouncyCastle). */\nexport const javaDetector: Detector = {\n id: \"java-crypto\",\n description:\n \"Classical asymmetric crypto on the JVM — Java/Kotlin/Scala (JCA getInstance + BouncyCastle)\",\n scope: \"source\",\n language: \"java\",\n rules: [\n RULE_JAVA_RSA,\n RULE_JAVA_RSA_SIGN,\n RULE_JAVA_EC_KEYGEN,\n RULE_JAVA_ECDSA_SIGN,\n RULE_JAVA_ECDH,\n RULE_JAVA_DSA,\n RULE_JAVA_DH,\n RULE_JAVA_XDH,\n RULE_JAVA_EDDSA,\n RULE_JAVA_BC_X448,\n RULE_JAVA_BC_X25519,\n RULE_JAVA_BC_EDDSA,\n RULE_JAVA_TLS_LEGACY,\n RULE_JAVA_TLS_NOVERIFY,\n RULE_JAVA_JWT_ALG,\n ],\n appliesTo: (f) => hasExtension(f, JAVA_EXTENSIONS),\n detect({ file, content }): Finding[] {\n const findings: Finding[] = [];\n\n eachMatch(RE_JAVA_GETINSTANCE, content, (m) => {\n const rule = classifyGetInstance(m[1], m[2]);\n if (!rule) return; // symmetric / hashing algorithm — not our concern.\n findings.push(\n findingFromRule(rule, { file, content, index: m.index, matchLength: m[0].length }),\n );\n });\n\n eachMatch(RE_JAVA_BC, content, (m) => {\n const rule = BC_CLASS_RULES[m[1]];\n if (!rule) return;\n findings.push(\n findingFromRule(rule, { file, content, index: m.index, matchLength: m[0].length }),\n );\n });\n\n // BouncyCastle lightweight-API classes as a bare constructor call (Kotlin\n // form, no `new`). RE_JAVA_BC_CURVE's negative lookbehind excludes the\n // `new <Class>(` form already handled above, so this only adds the missed\n // 448/25519 Kotlin-style matches — no double-counting.\n eachMatch(RE_JAVA_BC_CURVE, content, (m) => {\n const rule = BC_CURVE_CLASS_RULES[m[1]];\n if (!rule) return;\n findings.push(\n findingFromRule(rule, { file, content, index: m.index, matchLength: m[0].length }),\n );\n });\n\n // Bare (Kotlin-form) constructor calls to the non-curve BC classes — same rules\n // as the `new` form, routed via BC_CLASS_RULES.\n eachMatch(RE_JAVA_BC_BARE, content, (m) => {\n const rule = BC_CLASS_RULES[m[1]];\n if (!rule) return;\n findings.push(\n findingFromRule(rule, { file, content, index: m.index, matchLength: m[0].length }),\n );\n });\n\n // Legacy SSL/TLS protocol version requested from SSLContext.\n eachMatch(RE_JAVA_TLS_LEGACY, content, (m) => {\n findings.push(\n findingFromRule(RULE_JAVA_TLS_LEGACY, {\n file,\n content,\n index: m.index,\n matchLength: m[0].length,\n }),\n );\n });\n\n // All-trusting hostname verifier — disables TLS hostname verification.\n eachMatch(RE_JAVA_TLS_NOVERIFY, content, (m) => {\n findings.push(\n findingFromRule(RULE_JAVA_TLS_NOVERIFY, {\n file,\n content,\n index: m.index,\n matchLength: m[0].length,\n }),\n );\n });\n\n // Identifier-form JWT/JOSE signature algorithms (jjwt / auth0).\n eachMatch(RE_JAVA_JWT_ALG, content, (m) => {\n findings.push(\n findingFromRule(RULE_JAVA_JWT_ALG, {\n file,\n content,\n index: m.index,\n matchLength: m[0].length,\n }),\n );\n });\n\n return findings;\n },\n};\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config detector: classical KEY-MANAGEMENT (JWE) algorithms in JOSE. This is
|
|
3
|
+
* distinct from the JWS signature side (RS256/ES256, handled elsewhere) and from
|
|
4
|
+
* the JWK key-material detector: here we flag the `alg` values that wrap a
|
|
5
|
+
* content-encryption key with classical asymmetric crypto, because the encrypted
|
|
6
|
+
* payload is CONFIDENTIALITY — harvest-now-decrypt-later exposed. A JWE token
|
|
7
|
+
* captured today (from a log, an audit trail, a stored assertion) is decryptable
|
|
8
|
+
* once the wrapping key falls to a CRQC.
|
|
9
|
+
*
|
|
10
|
+
* Covered `alg` (RFC 7518 §4) values:
|
|
11
|
+
* - `RSA-OAEP`, `RSA-OAEP-256`, `RSA1_5` → RSA key encryption.
|
|
12
|
+
* - `ECDH-ES`, `ECDH-ES+A128KW`, … → classical EC Diffie-Hellman key agreement.
|
|
13
|
+
*
|
|
14
|
+
* These exact strings are JOSE identifiers, so a content-level match is precise;
|
|
15
|
+
* the detector applies to any file (config, JSON, source) after a fast reject.
|
|
16
|
+
*/
|
|
17
|
+
import type { Detector } from "../types.js";
|
|
18
|
+
/** Detects classical JWE key-management (`alg`) values in JOSE tokens/config. */
|
|
19
|
+
export declare const joseDetector: Detector;
|
|
20
|
+
//# sourceMappingURL=jose.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jose.d.ts","sourceRoot":"","sources":["../../src/detectors/jose.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAqB,MAAM,aAAa,CAAC;AAuD/D,iFAAiF;AACjF,eAAO,MAAM,YAAY,EAAE,QAqC1B,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { JWT_HOST_EXTENSIONS, DOC_EXTENSIONS, eachMatch, enclosingObject, findingFromRule, hasExtension, } from "../detect-utils.js";
|
|
2
|
+
import { CWE_BROKEN_CRYPTO } from "../cwe.js";
|
|
3
|
+
const JOSE_RULES = [
|
|
4
|
+
{
|
|
5
|
+
re: /"alg"\s*:\s*"RSA(?:-OAEP(?:-256)?|1_5)"/g,
|
|
6
|
+
meta: {
|
|
7
|
+
id: "jose-jwe-rsa",
|
|
8
|
+
title: "JWE RSA key wrapping",
|
|
9
|
+
description: 'JWE "alg" of RSA-OAEP / RSA-OAEP-256 / RSA1_5 (RFC 7518)',
|
|
10
|
+
category: "kem",
|
|
11
|
+
severity: "high",
|
|
12
|
+
confidence: "high",
|
|
13
|
+
algorithm: "RSA",
|
|
14
|
+
hndl: true,
|
|
15
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
16
|
+
message: "JWE wraps the content-encryption key with classical RSA (RSA-OAEP/RSA1_5); the encrypted payload is harvest-now-decrypt-later exposed.",
|
|
17
|
+
remediation: "Plan migration to a post-quantum KEM (ML-KEM-768) for key wrapping as JOSE/COSE PQ algorithms are standardised.",
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
re: /"alg"\s*:\s*"ECDH-ES(?:\+A\d{3}KW)?"/g,
|
|
22
|
+
meta: {
|
|
23
|
+
id: "jose-jwe-ecdh",
|
|
24
|
+
title: "JWE ECDH-ES key agreement",
|
|
25
|
+
description: 'JWE "alg" of ECDH-ES / ECDH-ES+A*KW (RFC 7518)',
|
|
26
|
+
category: "key-exchange",
|
|
27
|
+
severity: "high",
|
|
28
|
+
confidence: "high",
|
|
29
|
+
algorithm: "ECDH",
|
|
30
|
+
hndl: true,
|
|
31
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
32
|
+
message: "JWE derives the content-encryption key via classical ECDH-ES; the encrypted payload is harvest-now-decrypt-later exposed.",
|
|
33
|
+
remediation: "Plan migration to hybrid post-quantum key agreement (X25519MLKEM768) as JOSE PQ algorithms are standardised.",
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
];
|
|
37
|
+
/** Detects classical JWE key-management (`alg`) values in JOSE tokens/config. */
|
|
38
|
+
export const joseDetector = {
|
|
39
|
+
id: "jose-jwe-keymgmt",
|
|
40
|
+
description: "Classical JWE key-management algorithms (RSA-OAEP, ECDH-ES) — confidentiality, HNDL",
|
|
41
|
+
scope: "config",
|
|
42
|
+
language: "any",
|
|
43
|
+
rules: JOSE_RULES.map((r) => r.meta),
|
|
44
|
+
// Prose examples (a README showing `"alg":"RSA-OAEP"`) are not JOSE config. In the
|
|
45
|
+
// JS/TS/Python/Go/Ruby source files that source.ts's `jose-rsa-oaep`/`jose-ecdh-es`
|
|
46
|
+
// token rules actually cover (JWT_HOST_EXTENSIONS), defer to them to avoid a
|
|
47
|
+
// double-count — but STILL run on other source languages (Java/C#/Rust/PHP/Elixir/
|
|
48
|
+
// C/C++), which source.ts does not cover for these tokens.
|
|
49
|
+
appliesTo: (f) => !hasExtension(f, DOC_EXTENSIONS) && !hasExtension(f, JWT_HOST_EXTENSIONS),
|
|
50
|
+
detect({ file, content }) {
|
|
51
|
+
// Fast reject: no JOSE key-management alg token present.
|
|
52
|
+
if (!content.includes("RSA-OAEP") &&
|
|
53
|
+
!content.includes("RSA1_5") &&
|
|
54
|
+
!content.includes("ECDH-ES")) {
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
const findings = [];
|
|
58
|
+
for (const rule of JOSE_RULES) {
|
|
59
|
+
eachMatch(rule.re, content, (m) => {
|
|
60
|
+
// If this `alg` belongs to a JWK (a `"kty"` sits in the SAME object), the jwk
|
|
61
|
+
// detector already reports the key — defer so it isn't counted twice. Scoped
|
|
62
|
+
// to the enclosing object so an unrelated nearby JWK doesn't suppress a real
|
|
63
|
+
// standalone JWE header.
|
|
64
|
+
if (enclosingObject(content, m.index).includes('"kty"'))
|
|
65
|
+
return;
|
|
66
|
+
findings.push(findingFromRule(rule.meta, { file, content, index: m.index, matchLength: m[0].length }));
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return findings;
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
//# sourceMappingURL=jose.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jose.js","sourceRoot":"","sources":["../../src/detectors/jose.ts"],"names":[],"mappings":"AAiBA,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,SAAS,EACT,eAAe,EACf,eAAe,EACf,YAAY,GACb,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAO9C,MAAM,UAAU,GAAe;IAC7B;QACE,EAAE,EAAE,0CAA0C;QAC9C,IAAI,EAAE;YACJ,EAAE,EAAE,cAAc;YAClB,KAAK,EAAE,sBAAsB;YAC7B,WAAW,EAAE,0DAA0D;YACvE,QAAQ,EAAE,KAAK;YACf,QAAQ,EAAE,MAAM;YAChB,UAAU,EAAE,MAAM;YAClB,SAAS,EAAE,KAAK;YAChB,IAAI,EAAE,IAAI;YACV,GAAG,EAAE,iBAAiB;YACtB,OAAO,EACL,wIAAwI;YAC1I,WAAW,EACT,iHAAiH;SACpH;KACF;IACD;QACE,EAAE,EAAE,uCAAuC;QAC3C,IAAI,EAAE;YACJ,EAAE,EAAE,eAAe;YACnB,KAAK,EAAE,2BAA2B;YAClC,WAAW,EAAE,gDAAgD;YAC7D,QAAQ,EAAE,cAAc;YACxB,QAAQ,EAAE,MAAM;YAChB,UAAU,EAAE,MAAM;YAClB,SAAS,EAAE,MAAM;YACjB,IAAI,EAAE,IAAI;YACV,GAAG,EAAE,iBAAiB;YACtB,OAAO,EACL,2HAA2H;YAC7H,WAAW,EACT,8GAA8G;SACjH;KACF;CACF,CAAC;AAEF,iFAAiF;AACjF,MAAM,CAAC,MAAM,YAAY,GAAa;IACpC,EAAE,EAAE,kBAAkB;IACtB,WAAW,EACT,qFAAqF;IACvF,KAAK,EAAE,QAAQ;IACf,QAAQ,EAAE,KAAK;IACf,KAAK,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACpC,mFAAmF;IACnF,oFAAoF;IACpF,6EAA6E;IAC7E,mFAAmF;IACnF,2DAA2D;IAC3D,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE,cAAc,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,mBAAmB,CAAC;IAC3F,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE;QACtB,yDAAyD;QACzD,IACE,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;YAC7B,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;YAC3B,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,EAC5B,CAAC;YACD,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,MAAM,QAAQ,GAAc,EAAE,CAAC;QAC/B,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;YAC9B,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;gBAChC,8EAA8E;gBAC9E,6EAA6E;gBAC7E,6EAA6E;gBAC7E,yBAAyB;gBACzB,IAAI,eAAe,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;oBAAE,OAAO;gBAChE,QAAQ,CAAC,IAAI,CACX,eAAe,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CACxF,CAAC;YACJ,CAAC,CAAC,CAAC;QACL,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC","sourcesContent":["/**\n * Config detector: classical KEY-MANAGEMENT (JWE) algorithms in JOSE. This is\n * distinct from the JWS signature side (RS256/ES256, handled elsewhere) and from\n * the JWK key-material detector: here we flag the `alg` values that wrap a\n * content-encryption key with classical asymmetric crypto, because the encrypted\n * payload is CONFIDENTIALITY — harvest-now-decrypt-later exposed. A JWE token\n * captured today (from a log, an audit trail, a stored assertion) is decryptable\n * once the wrapping key falls to a CRQC.\n *\n * Covered `alg` (RFC 7518 §4) values:\n * - `RSA-OAEP`, `RSA-OAEP-256`, `RSA1_5` → RSA key encryption.\n * - `ECDH-ES`, `ECDH-ES+A128KW`, … → classical EC Diffie-Hellman key agreement.\n *\n * These exact strings are JOSE identifiers, so a content-level match is precise;\n * the detector applies to any file (config, JSON, source) after a fast reject.\n */\nimport type { Detector, Finding, RuleMeta } from \"../types.js\";\nimport {\n JWT_HOST_EXTENSIONS,\n DOC_EXTENSIONS,\n eachMatch,\n enclosingObject,\n findingFromRule,\n hasExtension,\n} from \"../detect-utils.js\";\nimport { CWE_BROKEN_CRYPTO } from \"../cwe.js\";\n\ninterface JoseRule {\n re: RegExp;\n meta: RuleMeta;\n}\n\nconst JOSE_RULES: JoseRule[] = [\n {\n re: /\"alg\"\\s*:\\s*\"RSA(?:-OAEP(?:-256)?|1_5)\"/g,\n meta: {\n id: \"jose-jwe-rsa\",\n title: \"JWE RSA key wrapping\",\n description: 'JWE \"alg\" of RSA-OAEP / RSA-OAEP-256 / RSA1_5 (RFC 7518)',\n category: \"kem\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"RSA\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"JWE wraps the content-encryption key with classical RSA (RSA-OAEP/RSA1_5); the encrypted payload is harvest-now-decrypt-later exposed.\",\n remediation:\n \"Plan migration to a post-quantum KEM (ML-KEM-768) for key wrapping as JOSE/COSE PQ algorithms are standardised.\",\n },\n },\n {\n re: /\"alg\"\\s*:\\s*\"ECDH-ES(?:\\+A\\d{3}KW)?\"/g,\n meta: {\n id: \"jose-jwe-ecdh\",\n title: \"JWE ECDH-ES key agreement\",\n description: 'JWE \"alg\" of ECDH-ES / ECDH-ES+A*KW (RFC 7518)',\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"ECDH\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"JWE derives the content-encryption key via classical ECDH-ES; the encrypted payload is harvest-now-decrypt-later exposed.\",\n remediation:\n \"Plan migration to hybrid post-quantum key agreement (X25519MLKEM768) as JOSE PQ algorithms are standardised.\",\n },\n },\n];\n\n/** Detects classical JWE key-management (`alg`) values in JOSE tokens/config. */\nexport const joseDetector: Detector = {\n id: \"jose-jwe-keymgmt\",\n description:\n \"Classical JWE key-management algorithms (RSA-OAEP, ECDH-ES) — confidentiality, HNDL\",\n scope: \"config\",\n language: \"any\",\n rules: JOSE_RULES.map((r) => r.meta),\n // Prose examples (a README showing `\"alg\":\"RSA-OAEP\"`) are not JOSE config. In the\n // JS/TS/Python/Go/Ruby source files that source.ts's `jose-rsa-oaep`/`jose-ecdh-es`\n // token rules actually cover (JWT_HOST_EXTENSIONS), defer to them to avoid a\n // double-count — but STILL run on other source languages (Java/C#/Rust/PHP/Elixir/\n // C/C++), which source.ts does not cover for these tokens.\n appliesTo: (f) => !hasExtension(f, DOC_EXTENSIONS) && !hasExtension(f, JWT_HOST_EXTENSIONS),\n detect({ file, content }): Finding[] {\n // Fast reject: no JOSE key-management alg token present.\n if (\n !content.includes(\"RSA-OAEP\") &&\n !content.includes(\"RSA1_5\") &&\n !content.includes(\"ECDH-ES\")\n ) {\n return [];\n }\n const findings: Finding[] = [];\n for (const rule of JOSE_RULES) {\n eachMatch(rule.re, content, (m) => {\n // If this `alg` belongs to a JWK (a `\"kty\"` sits in the SAME object), the jwk\n // detector already reports the key — defer so it isn't counted twice. Scoped\n // to the enclosing object so an unrelated nearby JWK doesn't suppress a real\n // standalone JWE header.\n if (enclosingObject(content, m.index).includes('\"kty\"')) return;\n findings.push(\n findingFromRule(rule.meta, { file, content, index: m.index, matchLength: m[0].length }),\n );\n });\n }\n return findings;\n },\n};\n"]}
|