@quantakrypto/core 0.4.2 → 0.4.4
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/LICENSE +201 -0
- package/README.md +38 -10
- package/dist/agent-types.js.map +1 -1
- package/dist/baseline.js.map +1 -1
- package/dist/cache.js.map +1 -1
- package/dist/cbom-merge.d.ts +9 -0
- package/dist/cbom-merge.d.ts.map +1 -0
- package/dist/cbom-merge.js +99 -0
- package/dist/cbom-merge.js.map +1 -0
- package/dist/cbom.js.map +1 -1
- package/dist/changed.js.map +1 -1
- package/dist/codemods/config-toggle.js.map +1 -1
- package/dist/codemods/registry.js.map +1 -1
- package/dist/comments.d.ts +29 -2
- package/dist/comments.d.ts.map +1 -1
- package/dist/comments.js +178 -18
- package/dist/comments.js.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/cwe.js.map +1 -1
- package/dist/dependencies.d.ts +3 -2
- package/dist/dependencies.d.ts.map +1 -1
- package/dist/dependencies.js +138 -2
- package/dist/dependencies.js.map +1 -1
- package/dist/detect-utils.d.ts +19 -4
- package/dist/detect-utils.d.ts.map +1 -1
- package/dist/detect-utils.js +43 -6
- package/dist/detect-utils.js.map +1 -1
- package/dist/detectors/c.d.ts +4 -2
- package/dist/detectors/c.d.ts.map +1 -1
- package/dist/detectors/c.js +382 -3
- 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 +116 -0
- package/dist/detectors/cicd.js.map +1 -0
- package/dist/detectors/cloud-kms.d.ts +21 -0
- package/dist/detectors/cloud-kms.d.ts.map +1 -0
- package/dist/detectors/cloud-kms.js +57 -0
- package/dist/detectors/cloud-kms.js.map +1 -0
- package/dist/detectors/cloudformation.d.ts +30 -0
- package/dist/detectors/cloudformation.d.ts.map +1 -0
- package/dist/detectors/cloudformation.js +170 -0
- package/dist/detectors/cloudformation.js.map +1 -0
- package/dist/detectors/csharp.d.ts.map +1 -1
- package/dist/detectors/csharp.js +141 -3
- package/dist/detectors/csharp.js.map +1 -1
- package/dist/detectors/database.d.ts +17 -0
- package/dist/detectors/database.d.ts.map +1 -0
- package/dist/detectors/database.js +60 -0
- package/dist/detectors/database.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 +107 -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 +195 -0
- package/dist/detectors/elixir.js.map +1 -0
- package/dist/detectors/go.d.ts +5 -3
- package/dist/detectors/go.d.ts.map +1 -1
- package/dist/detectors/go.js +187 -3
- package/dist/detectors/go.js.map +1 -1
- package/dist/detectors/java.d.ts.map +1 -1
- package/dist/detectors/java.js +169 -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 +62 -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 +95 -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 +85 -0
- package/dist/detectors/k8s.js.map +1 -0
- package/dist/detectors/mesh.d.ts +35 -0
- package/dist/detectors/mesh.d.ts.map +1 -0
- package/dist/detectors/mesh.js +109 -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 +72 -0
- package/dist/detectors/messaging.js.map +1 -0
- package/dist/detectors/pem.d.ts.map +1 -1
- package/dist/detectors/pem.js +50 -2
- package/dist/detectors/pem.js.map +1 -1
- package/dist/detectors/php.d.ts +24 -0
- package/dist/detectors/php.d.ts.map +1 -0
- package/dist/detectors/php.js +167 -0
- package/dist/detectors/php.js.map +1 -0
- package/dist/detectors/python.d.ts.map +1 -1
- package/dist/detectors/python.js +144 -3
- package/dist/detectors/python.js.map +1 -1
- package/dist/detectors/ruby.d.ts +9 -5
- package/dist/detectors/ruby.d.ts.map +1 -1
- package/dist/detectors/ruby.js +122 -2
- package/dist/detectors/ruby.js.map +1 -1
- package/dist/detectors/rust.d.ts +8 -3
- package/dist/detectors/rust.d.ts.map +1 -1
- package/dist/detectors/rust.js +253 -3
- package/dist/detectors/rust.js.map +1 -1
- package/dist/detectors/secrets.d.ts +21 -0
- package/dist/detectors/secrets.d.ts.map +1 -0
- package/dist/detectors/secrets.js +79 -0
- package/dist/detectors/secrets.js.map +1 -0
- package/dist/detectors/source.d.ts.map +1 -1
- package/dist/detectors/source.js +305 -52
- package/dist/detectors/source.js.map +1 -1
- package/dist/detectors/stateful-hbs.d.ts +22 -0
- package/dist/detectors/stateful-hbs.d.ts.map +1 -0
- package/dist/detectors/stateful-hbs.js +142 -0
- package/dist/detectors/stateful-hbs.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 +123 -0
- package/dist/detectors/terraform.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 +99 -0
- package/dist/detectors/vpn.js.map +1 -0
- package/dist/errors.js.map +1 -1
- package/dist/evidence.d.ts +53 -0
- package/dist/evidence.d.ts.map +1 -0
- package/dist/evidence.js +81 -0
- package/dist/evidence.js.map +1 -0
- package/dist/index.d.ts +9 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -2
- package/dist/index.js.map +1 -1
- package/dist/inventory.d.ts +2 -0
- package/dist/inventory.d.ts.map +1 -1
- package/dist/inventory.js +27 -1
- package/dist/inventory.js.map +1 -1
- package/dist/parallel.js.map +1 -1
- package/dist/patch-policy.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/redact.d.ts.map +1 -1
- package/dist/redact.js +39 -0
- package/dist/redact.js.map +1 -1
- package/dist/registry.d.ts +2 -2
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +34 -2
- package/dist/registry.js.map +1 -1
- package/dist/remediate-pipeline.d.ts +3 -0
- package/dist/remediate-pipeline.d.ts.map +1 -1
- package/dist/remediate-pipeline.js +71 -0
- package/dist/remediate-pipeline.js.map +1 -1
- package/dist/remediate-request.js.map +1 -1
- package/dist/remediation.d.ts +9 -3
- package/dist/remediation.d.ts.map +1 -1
- package/dist/remediation.js +17 -5
- 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 -0
- package/dist/report.js.map +1 -1
- package/dist/scan-worker.js.map +1 -1
- package/dist/scan.d.ts.map +1 -1
- package/dist/scan.js +8 -1
- package/dist/scan.js.map +1 -1
- package/dist/severity.js.map +1 -1
- 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/triage.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/verify.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/walk.js.map +1 -1
- package/dist/worktree.js.map +1 -1
- package/package.json +1 -1
- package/src/cbom-merge.ts +116 -0
- package/src/comments.ts +183 -18
- package/src/dependencies.ts +144 -4
- package/src/detect-utils.ts +47 -6
- package/src/detectors/c.ts +411 -5
- package/src/detectors/cicd.ts +158 -0
- package/src/detectors/cloud-kms.ts +87 -0
- package/src/detectors/cloudformation.ts +215 -0
- package/src/detectors/csharp.ts +154 -3
- package/src/detectors/database.ts +88 -0
- package/src/detectors/dnssec.ts +186 -0
- package/src/detectors/elixir.ts +237 -0
- package/src/detectors/go.ts +209 -6
- package/src/detectors/java.ts +191 -4
- package/src/detectors/jose.ts +94 -0
- package/src/detectors/jwk.ts +128 -0
- package/src/detectors/k8s.ts +112 -0
- package/src/detectors/mesh.ts +154 -0
- package/src/detectors/messaging.ts +98 -0
- package/src/detectors/pem.ts +54 -2
- package/src/detectors/php.ts +225 -0
- package/src/detectors/python.ts +153 -3
- package/src/detectors/ruby.ts +138 -7
- package/src/detectors/rust.ts +282 -7
- package/src/detectors/secrets.ts +114 -0
- package/src/detectors/source.ts +382 -72
- package/src/detectors/stateful-hbs.ts +180 -0
- package/src/detectors/terraform.ts +154 -0
- package/src/detectors/vpn.ts +131 -0
- package/src/evidence.ts +135 -0
- package/src/index.ts +15 -1
- package/src/inventory.ts +31 -1
- package/src/policy.ts +180 -0
- package/src/redact.ts +41 -0
- package/src/registry.ts +34 -2
- package/src/remediate-pipeline.ts +78 -0
- package/src/remediation.ts +23 -8
- package/src/report.ts +48 -2
- package/src/scan.ts +13 -1
- package/src/standards.ts +186 -0
- package/src/types.ts +3 -1
- package/src/version.ts +1 -1
package/src/detectors/go.ts
CHANGED
|
@@ -6,11 +6,13 @@
|
|
|
6
6
|
* `ecdsa.SignASN1`, `ecdh.X25519`, …) are precise, low-false-positive signals.
|
|
7
7
|
*
|
|
8
8
|
* Covered:
|
|
9
|
-
* - crypto/rsa — GenerateKey, EncryptOAEP/PKCS1v15, SignPKCS1v15/PSS
|
|
10
|
-
* - crypto/ecdsa — GenerateKey, Sign/SignASN1
|
|
9
|
+
* - crypto/rsa — GenerateKey, EncryptOAEP/PKCS1v15, SignPKCS1v15/PSS, DecryptOAEP, VerifyPKCS1v15/PSS
|
|
10
|
+
* - crypto/ecdsa — GenerateKey, Sign/SignASN1, Verify/VerifyASN1
|
|
11
11
|
* - crypto/ecdh — P256/P384/P521/X25519 curve construction (key agreement)
|
|
12
|
-
* - crypto/
|
|
12
|
+
* - crypto/elliptic — GenerateKey / ScalarMult (classic pre-1.20 ECDH)
|
|
13
|
+
* - crypto/ed25519 — GenerateKey, Sign, Verify
|
|
13
14
|
* - crypto/dsa — GenerateKey, GenerateParameters (deprecated)
|
|
15
|
+
* - crypto/tls — InsecureSkipVerify, legacy MinVersion (transport config hygiene)
|
|
14
16
|
*
|
|
15
17
|
* HNDL policy mirrors the other detectors: KEM / key agreement (RSA encryption,
|
|
16
18
|
* ECDH) is harvest-now-decrypt-later exposed (hndl:true); signatures (RSA-sign,
|
|
@@ -21,7 +23,7 @@
|
|
|
21
23
|
*/
|
|
22
24
|
import type { Detector, Finding, RuleMeta } from "../types.js";
|
|
23
25
|
import { GO_EXTENSIONS, eachMatch, findingFromRule, hasExtension } from "../detect-utils.js";
|
|
24
|
-
import { CWE_BROKEN_CRYPTO } from "../cwe.js";
|
|
26
|
+
import { CWE_BROKEN_CRYPTO, CWE_CERT_VALIDATION, CWE_WEAK_STRENGTH } from "../cwe.js";
|
|
25
27
|
|
|
26
28
|
/* -------------------------------------------------------------------------- */
|
|
27
29
|
/* Precompiled regexes (module scope) */
|
|
@@ -31,9 +33,37 @@ const RE_GO_RSA_KEYGEN = /\brsa\.GenerateKey\s*\(|\brsa\.GenerateMultiPrimeKey\s
|
|
|
31
33
|
const RE_GO_RSA_ENCRYPT = /\brsa\.EncryptOAEP\s*\(|\brsa\.EncryptPKCS1v15\s*\(/g;
|
|
32
34
|
const RE_GO_RSA_SIGN = /\brsa\.SignPKCS1v15\s*\(|\brsa\.SignPSS\s*\(/g;
|
|
33
35
|
const RE_GO_ECDSA = /\becdsa\.GenerateKey\s*\(|\becdsa\.SignASN1\s*\(|\becdsa\.Sign\s*\(/g;
|
|
34
|
-
const RE_GO_ECDH = /\becdh\.(?:P256|P384|P521
|
|
36
|
+
const RE_GO_ECDH = /\becdh\.(?:P256|P384|P521)\s*\(/g;
|
|
37
|
+
// X25519 gets its own family (algorithm "X25519", lower severity) to match how
|
|
38
|
+
// every other pack classifies it — Go was the lone site reporting it as ECDH/high
|
|
39
|
+
// (audit F9). Still key-exchange + hndl:true.
|
|
40
|
+
const RE_GO_X25519 = /\becdh\.X25519\s*\(/g;
|
|
35
41
|
const RE_GO_ED25519 = /\bed25519\.GenerateKey\s*\(|\bed25519\.Sign\s*\(/g;
|
|
36
42
|
const RE_GO_DSA = /\bdsa\.GenerateKey\s*\(|\bdsa\.GenerateParameters\s*\(/g;
|
|
43
|
+
// Verify / decrypt call sites — the inverse operations the Sign/Encrypt/
|
|
44
|
+
// GenerateKey rules above miss today (audit F4/F6). Deliberately disjoint from
|
|
45
|
+
// those rules to avoid double-counting: DecryptOAEP≠EncryptOAEP, Verify*≠Sign*.
|
|
46
|
+
const RE_GO_RSA_DECRYPT = /\brsa\.DecryptOAEP\s*\(/g;
|
|
47
|
+
const RE_GO_RSA_VERIFY = /\brsa\.VerifyPKCS1v15\s*\(|\brsa\.VerifyPSS\s*\(/g;
|
|
48
|
+
const RE_GO_ECDSA_VERIFY = /\becdsa\.Verify(?:ASN1)?\s*\(/g;
|
|
49
|
+
const RE_GO_ED25519_VERIFY = /\bed25519\.Verify\s*\(/g;
|
|
50
|
+
// Classic pre-1.20 elliptic-curve key agreement (crypto/elliptic), superseded by
|
|
51
|
+
// crypto/ecdh but still widespread. GenerateKey + ScalarMult are the low-level
|
|
52
|
+
// ECDH building blocks the crypto/ecdh rule does not see. `.ScalarMult(` is an
|
|
53
|
+
// unqualified method call, so this rule carries medium confidence.
|
|
54
|
+
const RE_GO_ECDH_CLASSIC = /\belliptic\.GenerateKey\s*\(|\.ScalarMult\s*\(/g;
|
|
55
|
+
// Go TLS misconfiguration (crypto/tls). Mirrors the JS tlsDetector: disabled
|
|
56
|
+
// certificate verification and a legacy TLS/SSL version floor.
|
|
57
|
+
const RE_GO_TLS_SKIP_VERIFY = /InsecureSkipVerify:\s*true/g;
|
|
58
|
+
const RE_GO_TLS_LEGACY_VERSION = /MinVersion:\s*tls\.Version(?:TLS1[01]|SSL30)/g;
|
|
59
|
+
// Identifier-form golang-jwt signing methods (audit gap: the quoted "RS256" alg
|
|
60
|
+
// token is caught by the language-agnostic jwt-jose detector, but golang-jwt
|
|
61
|
+
// passes the alg as an EXPORTED IDENTIFIER — `jwt.SigningMethodRS256`,
|
|
62
|
+
// `jwt.SigningMethodES256`, `jwt.SigningMethodEdDSA` — which the string rule
|
|
63
|
+
// misses. RS*/PS* → RSA, ES* → ECDSA, EdDSA → EdDSA. The `\b`s keep it precise:
|
|
64
|
+
// HS* HMAC methods and longer look-alikes (`SigningMethodRS2560`) do not match.
|
|
65
|
+
const RE_GO_JWT_SIGNINGMETHOD =
|
|
66
|
+
/\bSigningMethod(RS|PS|ES)(?:256|384|512)\b|\bSigningMethodEdDSA\b/g;
|
|
37
67
|
|
|
38
68
|
/* -------------------------------------------------------------------------- */
|
|
39
69
|
/* Rule catalog */
|
|
@@ -93,7 +123,7 @@ const RULE_GO_ECDSA: RuleMeta = {
|
|
|
93
123
|
const RULE_GO_ECDH: RuleMeta = {
|
|
94
124
|
id: "go-ecdh",
|
|
95
125
|
title: "Go ECDH key exchange",
|
|
96
|
-
description: "crypto/ecdh P256/P384/P521
|
|
126
|
+
description: "crypto/ecdh P256/P384/P521 key agreement",
|
|
97
127
|
category: "key-exchange",
|
|
98
128
|
severity: "high",
|
|
99
129
|
confidence: "high",
|
|
@@ -103,6 +133,19 @@ const RULE_GO_ECDH: RuleMeta = {
|
|
|
103
133
|
message:
|
|
104
134
|
"Elliptic-curve Diffie-Hellman (Go crypto/ecdh) is broken by Shor's algorithm (harvest-now-decrypt-later).",
|
|
105
135
|
};
|
|
136
|
+
const RULE_GO_X25519: RuleMeta = {
|
|
137
|
+
id: "go-x25519",
|
|
138
|
+
title: "Go X25519 key exchange",
|
|
139
|
+
description: "crypto/ecdh X25519 key agreement",
|
|
140
|
+
category: "key-exchange",
|
|
141
|
+
severity: "medium",
|
|
142
|
+
confidence: "high",
|
|
143
|
+
algorithm: "X25519",
|
|
144
|
+
hndl: true,
|
|
145
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
146
|
+
message:
|
|
147
|
+
"X25519 (Go crypto/ecdh) is modern but still classical key agreement — harvest-now-decrypt-later.",
|
|
148
|
+
};
|
|
106
149
|
const RULE_GO_ED25519: RuleMeta = {
|
|
107
150
|
id: "go-ed25519",
|
|
108
151
|
title: "Go Ed25519 signature",
|
|
@@ -128,6 +171,132 @@ const RULE_GO_DSA: RuleMeta = {
|
|
|
128
171
|
message: "Classical DSA (Go) is deprecated and forgeable by a quantum attacker.",
|
|
129
172
|
remediation: "Rotate off DSA and migrate to ML-DSA-65 (FIPS 204).",
|
|
130
173
|
};
|
|
174
|
+
const RULE_GO_RSA_DECRYPT: RuleMeta = {
|
|
175
|
+
id: "go-rsa-decrypt",
|
|
176
|
+
title: "Go RSA public-key decryption",
|
|
177
|
+
description: "crypto/rsa DecryptOAEP",
|
|
178
|
+
category: "kem",
|
|
179
|
+
severity: "high",
|
|
180
|
+
confidence: "high",
|
|
181
|
+
algorithm: "RSA",
|
|
182
|
+
hndl: true,
|
|
183
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
184
|
+
message:
|
|
185
|
+
"RSA public-key decryption (Go) recovers data protected by a classical KEM — harvest-now-decrypt-later exposed.",
|
|
186
|
+
};
|
|
187
|
+
const RULE_GO_RSA_VERIFY: RuleMeta = {
|
|
188
|
+
id: "go-rsa-verify",
|
|
189
|
+
title: "Go RSA signature verification",
|
|
190
|
+
description: "crypto/rsa VerifyPKCS1v15 / VerifyPSS",
|
|
191
|
+
category: "signature",
|
|
192
|
+
severity: "high",
|
|
193
|
+
confidence: "high",
|
|
194
|
+
algorithm: "RSA",
|
|
195
|
+
hndl: false,
|
|
196
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
197
|
+
message: "Verifies classical RSA signatures (Go), which are forgeable by a quantum attacker.",
|
|
198
|
+
remediation: "ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205)",
|
|
199
|
+
};
|
|
200
|
+
const RULE_GO_ECDSA_VERIFY: RuleMeta = {
|
|
201
|
+
id: "go-ecdsa-verify",
|
|
202
|
+
title: "Go ECDSA signature verification",
|
|
203
|
+
description: "crypto/ecdsa Verify / VerifyASN1",
|
|
204
|
+
category: "signature",
|
|
205
|
+
severity: "high",
|
|
206
|
+
confidence: "high",
|
|
207
|
+
algorithm: "ECDSA",
|
|
208
|
+
hndl: false,
|
|
209
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
210
|
+
message: "Verifies classical ECDSA signatures (Go), which are forgeable by a quantum attacker.",
|
|
211
|
+
remediation: "ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205)",
|
|
212
|
+
};
|
|
213
|
+
const RULE_GO_ED25519_VERIFY: RuleMeta = {
|
|
214
|
+
id: "go-ed25519-verify",
|
|
215
|
+
title: "Go Ed25519 signature verification",
|
|
216
|
+
description: "crypto/ed25519 Verify",
|
|
217
|
+
category: "signature",
|
|
218
|
+
severity: "low",
|
|
219
|
+
confidence: "high",
|
|
220
|
+
algorithm: "EdDSA",
|
|
221
|
+
hndl: false,
|
|
222
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
223
|
+
message: "Verifies Ed25519 signatures (Go) — modern but still classical and quantum-forgeable.",
|
|
224
|
+
};
|
|
225
|
+
const RULE_GO_ECDH_CLASSIC: RuleMeta = {
|
|
226
|
+
id: "go-ecdh-classic",
|
|
227
|
+
title: "Go classic EC key agreement (crypto/elliptic)",
|
|
228
|
+
description: "crypto/elliptic GenerateKey / ScalarMult (pre-1.20 ECDH)",
|
|
229
|
+
category: "key-exchange",
|
|
230
|
+
severity: "high",
|
|
231
|
+
confidence: "medium",
|
|
232
|
+
algorithm: "ECDH",
|
|
233
|
+
hndl: true,
|
|
234
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
235
|
+
message:
|
|
236
|
+
"Low-level elliptic-curve key agreement (Go crypto/elliptic) is broken by Shor's algorithm (harvest-now-decrypt-later).",
|
|
237
|
+
};
|
|
238
|
+
const RULE_GO_TLS_SKIP_VERIFY: RuleMeta = {
|
|
239
|
+
id: "go-tls-insecure-skip-verify",
|
|
240
|
+
title: "Go TLS certificate verification disabled",
|
|
241
|
+
description: "crypto/tls Config InsecureSkipVerify: true",
|
|
242
|
+
category: "tls",
|
|
243
|
+
severity: "high",
|
|
244
|
+
confidence: "high",
|
|
245
|
+
hndl: false,
|
|
246
|
+
cwe: CWE_CERT_VALIDATION,
|
|
247
|
+
message: "InsecureSkipVerify:true disables TLS certificate verification (Go) — MITM risk.",
|
|
248
|
+
remediation: "Remove InsecureSkipVerify:true; verify certificates properly.",
|
|
249
|
+
};
|
|
250
|
+
const RULE_GO_TLS_LEGACY_VERSION: RuleMeta = {
|
|
251
|
+
id: "go-tls-legacy-version",
|
|
252
|
+
title: "Go legacy TLS version pinned",
|
|
253
|
+
description: "crypto/tls MinVersion pinned to TLS 1.0/1.1 or SSL 3.0",
|
|
254
|
+
category: "tls",
|
|
255
|
+
severity: "medium",
|
|
256
|
+
confidence: "high",
|
|
257
|
+
hndl: false,
|
|
258
|
+
cwe: CWE_WEAK_STRENGTH,
|
|
259
|
+
message:
|
|
260
|
+
"MinVersion pins a deprecated TLS/SSL floor (TLS 1.0/1.1 or SSL 3.0) in Go; require TLS 1.3.",
|
|
261
|
+
remediation: "Set MinVersion: tls.VersionTLS13 and prefer PQC-hybrid key exchange.",
|
|
262
|
+
};
|
|
263
|
+
const RULE_GO_JWT_SIGNINGMETHOD: RuleMeta = {
|
|
264
|
+
id: "go-jwt-signingmethod",
|
|
265
|
+
title: "Go identifier-form JWT signing method",
|
|
266
|
+
description: "golang-jwt SigningMethodRS/PS/ES* / SigningMethodEdDSA identifier",
|
|
267
|
+
category: "signature",
|
|
268
|
+
severity: "high",
|
|
269
|
+
confidence: "high",
|
|
270
|
+
algorithm: "unknown", // representative umbrella; refined per-match (RSA/ECDSA/EdDSA)
|
|
271
|
+
hndl: false,
|
|
272
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
273
|
+
message:
|
|
274
|
+
"A classical JWT signature algorithm (Go golang-jwt, identifier form) is used, forgeable by a quantum attacker.",
|
|
275
|
+
remediation: "ML-DSA-65 (FIPS 204); track IETF PQC JOSE/COSE algorithms",
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
// The x509 PEM/DER key + certificate layer: parsing/marshalling classical RSA,
|
|
279
|
+
// EC and PKIX key material and X.509 certificates. This is the "handles classical
|
|
280
|
+
// keys" surface the Sign/Verify/GenerateKey rules miss — a key-loading utility
|
|
281
|
+
// (`x509.ParsePKCS8PrivateKey`) touches quantum-vulnerable material without ever
|
|
282
|
+
// naming rsa/ecdsa. Family is ambiguous at the parse site, so `unknown`.
|
|
283
|
+
const RE_GO_X509_PARSE =
|
|
284
|
+
/\bx509\.(?:ParsePKCS1PrivateKey|ParsePKCS8PrivateKey|ParsePKIXPublicKey|ParseECPrivateKey|ParsePKCS1PublicKey|MarshalPKCS1PrivateKey|MarshalPKCS8PrivateKey|MarshalPKIXPublicKey|MarshalECPrivateKey|ParseCertificates?|ParseCertificateRequest|CreateCertificate|CreateCertificateRequest)\b/g;
|
|
285
|
+
const RULE_GO_X509_PARSE: RuleMeta = {
|
|
286
|
+
id: "go-x509-parse",
|
|
287
|
+
title: "Go x509 classical key/certificate handling",
|
|
288
|
+
description: "x509.Parse*/Marshal*/Create* for RSA/EC/PKIX keys and X.509 certificates",
|
|
289
|
+
category: "certificate",
|
|
290
|
+
severity: "medium",
|
|
291
|
+
confidence: "medium",
|
|
292
|
+
algorithm: "unknown",
|
|
293
|
+
hndl: false,
|
|
294
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
295
|
+
message:
|
|
296
|
+
"This code parses/marshals classical asymmetric key or X.509 certificate material (x509.*), a quantum forgery/harvest surface.",
|
|
297
|
+
remediation:
|
|
298
|
+
"Inventory the key/cert types handled here; plan PQC (ML-DSA) certificate + key migration.",
|
|
299
|
+
};
|
|
131
300
|
|
|
132
301
|
/** Detects classical asymmetric crypto in Go source (crypto/* standard library). */
|
|
133
302
|
export const goDetector: Detector = {
|
|
@@ -141,8 +310,18 @@ export const goDetector: Detector = {
|
|
|
141
310
|
RULE_GO_RSA_SIGN,
|
|
142
311
|
RULE_GO_ECDSA,
|
|
143
312
|
RULE_GO_ECDH,
|
|
313
|
+
RULE_GO_X25519,
|
|
144
314
|
RULE_GO_ED25519,
|
|
145
315
|
RULE_GO_DSA,
|
|
316
|
+
RULE_GO_RSA_DECRYPT,
|
|
317
|
+
RULE_GO_RSA_VERIFY,
|
|
318
|
+
RULE_GO_ECDSA_VERIFY,
|
|
319
|
+
RULE_GO_ED25519_VERIFY,
|
|
320
|
+
RULE_GO_ECDH_CLASSIC,
|
|
321
|
+
RULE_GO_TLS_SKIP_VERIFY,
|
|
322
|
+
RULE_GO_TLS_LEGACY_VERSION,
|
|
323
|
+
RULE_GO_JWT_SIGNINGMETHOD,
|
|
324
|
+
RULE_GO_X509_PARSE,
|
|
146
325
|
],
|
|
147
326
|
appliesTo: (f) => hasExtension(f, GO_EXTENSIONS),
|
|
148
327
|
detect({ file, content }): Finding[] {
|
|
@@ -159,8 +338,32 @@ export const goDetector: Detector = {
|
|
|
159
338
|
add(RE_GO_RSA_SIGN, RULE_GO_RSA_SIGN);
|
|
160
339
|
add(RE_GO_ECDSA, RULE_GO_ECDSA);
|
|
161
340
|
add(RE_GO_ECDH, RULE_GO_ECDH);
|
|
341
|
+
add(RE_GO_X25519, RULE_GO_X25519);
|
|
162
342
|
add(RE_GO_ED25519, RULE_GO_ED25519);
|
|
163
343
|
add(RE_GO_DSA, RULE_GO_DSA);
|
|
344
|
+
add(RE_GO_RSA_DECRYPT, RULE_GO_RSA_DECRYPT);
|
|
345
|
+
add(RE_GO_RSA_VERIFY, RULE_GO_RSA_VERIFY);
|
|
346
|
+
add(RE_GO_ECDSA_VERIFY, RULE_GO_ECDSA_VERIFY);
|
|
347
|
+
add(RE_GO_ED25519_VERIFY, RULE_GO_ED25519_VERIFY);
|
|
348
|
+
add(RE_GO_ECDH_CLASSIC, RULE_GO_ECDH_CLASSIC);
|
|
349
|
+
add(RE_GO_TLS_SKIP_VERIFY, RULE_GO_TLS_SKIP_VERIFY);
|
|
350
|
+
add(RE_GO_TLS_LEGACY_VERSION, RULE_GO_TLS_LEGACY_VERSION);
|
|
351
|
+
add(RE_GO_X509_PARSE, RULE_GO_X509_PARSE);
|
|
352
|
+
|
|
353
|
+
// Identifier-form golang-jwt signing methods (jwt.SigningMethodRS256, …).
|
|
354
|
+
// Refine the umbrella "unknown" algorithm per match: m[1] is the RS/PS/ES
|
|
355
|
+
// prefix (RS/PS → RSA, ES → ECDSA); when it is undefined the EdDSA branch
|
|
356
|
+
// matched, so the family is EdDSA.
|
|
357
|
+
eachMatch(RE_GO_JWT_SIGNINGMETHOD, content, (m) => {
|
|
358
|
+
const algorithm: Finding["algorithm"] = m[1] === "ES" ? "ECDSA" : m[1] ? "RSA" : "EdDSA";
|
|
359
|
+
findings.push(
|
|
360
|
+
findingFromRule(
|
|
361
|
+
RULE_GO_JWT_SIGNINGMETHOD,
|
|
362
|
+
{ file, content, index: m.index, matchLength: m[0].length },
|
|
363
|
+
{ algorithm },
|
|
364
|
+
),
|
|
365
|
+
);
|
|
366
|
+
});
|
|
164
367
|
|
|
165
368
|
return findings;
|
|
166
369
|
},
|
package/src/detectors/java.ts
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
*/
|
|
22
22
|
import type { Detector, Finding, RuleMeta } from "../types.js";
|
|
23
23
|
import { JAVA_EXTENSIONS, eachMatch, findingFromRule, hasExtension } from "../detect-utils.js";
|
|
24
|
-
import { CWE_BROKEN_CRYPTO } from "../cwe.js";
|
|
24
|
+
import { CWE_BROKEN_CRYPTO, CWE_CERT_VALIDATION, CWE_WEAK_STRENGTH } from "../cwe.js";
|
|
25
25
|
|
|
26
26
|
/* -------------------------------------------------------------------------- */
|
|
27
27
|
/* Regexes */
|
|
@@ -35,7 +35,34 @@ const RE_JAVA_GETINSTANCE =
|
|
|
35
35
|
|
|
36
36
|
// BouncyCastle lightweight-API class instantiations.
|
|
37
37
|
const RE_JAVA_BC =
|
|
38
|
-
/\bnew\s+(RSAKeyPairGenerator|DSAKeyPairGenerator|ECKeyPairGenerator|ECDSASigner|Ed25519Signer|Ed448Signer|X25519Agreement|X448Agreement)\s*\(/g;
|
|
38
|
+
/\bnew\s+(RSAKeyPairGenerator|DSAKeyPairGenerator|ECKeyPairGenerator|ECDSASigner|Ed25519Signer|Ed448Signer|X25519Agreement|X448Agreement|ECDHBasicAgreement|DHBasicAgreement|X25519KeyPairGenerator|Ed25519KeyPairGenerator|RSAEngine|OAEPEncoding)\s*\(/g;
|
|
39
|
+
|
|
40
|
+
// BouncyCastle lightweight-API curve/EdDSA classes as a BARE constructor call —
|
|
41
|
+
// the Kotlin form (`X448KeyPairGenerator()`, no `new` keyword). RE_JAVA_BC above
|
|
42
|
+
// only matches the Java `new <Class>(` form, so Kotlin sources that drive the
|
|
43
|
+
// lightweight API directly are missed. The negative lookbehind `(?<!\bnew\s+)`
|
|
44
|
+
// keeps this additive: `new X448Agreement(` stays with RE_JAVA_BC (java-xdh),
|
|
45
|
+
// while bare `X448Agreement(` routes to the family-specific rules below. Scoped
|
|
46
|
+
// to the exact X448/X25519/Ed448/Ed25519 class names to stay precise.
|
|
47
|
+
const RE_JAVA_BC_CURVE =
|
|
48
|
+
/(?<!\bnew\s+)\b(X448KeyPairGenerator|X448Agreement|X448PrivateKeyParameters|X25519KeyPairGenerator|X25519Agreement|Ed448KeyPairGenerator|Ed448Signer|Ed25519KeyPairGenerator|Ed25519Signer)\s*\(/g;
|
|
49
|
+
|
|
50
|
+
// Insecure JSSE / TLS configuration expressed in Java source. Mirrors the JS
|
|
51
|
+
// tlsDetector in source.ts (category "tls"): a legacy SSL/TLS protocol version
|
|
52
|
+
// requested from SSLContext, and TLS hostname verification neutered via an
|
|
53
|
+
// all-trusting verifier (Apache HttpClient's NoopHostnameVerifier /
|
|
54
|
+
// ALLOW_ALL_HOSTNAME_VERIFIER).
|
|
55
|
+
const RE_JAVA_TLS_LEGACY = /\bSSLContext\s*\.\s*getInstance\s*\(\s*"(SSL|SSLv3|TLSv1)"/g;
|
|
56
|
+
const RE_JAVA_TLS_NOVERIFY = /\b(NoopHostnameVerifier|ALLOW_ALL_HOSTNAME_VERIFIER)\b/g;
|
|
57
|
+
|
|
58
|
+
// Identifier-form JWT/JOSE signature algorithms (audit F7). The quoted-string
|
|
59
|
+
// alg token ("RS256") is caught by the language-agnostic jwt-jose detector, but
|
|
60
|
+
// the Java JWT libraries pass the alg as an IDENTIFIER, not a string literal:
|
|
61
|
+
// jjwt's `SignatureAlgorithm.RS256` and auth0 java-jwt's `Algorithm.RSA256` /
|
|
62
|
+
// `Algorithm.ECDSA256`. ("SignatureAlgorithm" has no word boundary before its
|
|
63
|
+
// "Algorithm", so the auth0 branch cannot re-match the jjwt form.)
|
|
64
|
+
const RE_JAVA_JWT_ALG =
|
|
65
|
+
/\bSignatureAlgorithm\.(?:RS|PS|ES)(?:256|384|512)\b|\bAlgorithm\.(?:RSA|ECDSA)(?:256|384|512)\b/g;
|
|
39
66
|
|
|
40
67
|
/* -------------------------------------------------------------------------- */
|
|
41
68
|
/* Rule catalog */
|
|
@@ -138,7 +165,7 @@ const RULE_JAVA_XDH: RuleMeta = {
|
|
|
138
165
|
title: "Java X25519/X448 key agreement",
|
|
139
166
|
description: "JCA XDH / X25519 / X448 (KeyPairGenerator / KeyAgreement)",
|
|
140
167
|
category: "key-exchange",
|
|
141
|
-
severity: "
|
|
168
|
+
severity: "medium",
|
|
142
169
|
confidence: "high",
|
|
143
170
|
algorithm: "X25519",
|
|
144
171
|
hndl: true,
|
|
@@ -158,6 +185,87 @@ const RULE_JAVA_EDDSA: RuleMeta = {
|
|
|
158
185
|
cwe: CWE_BROKEN_CRYPTO,
|
|
159
186
|
message: "Ed25519/Ed448 (Java/JCA) is a modern but still classical signature scheme.",
|
|
160
187
|
};
|
|
188
|
+
// BouncyCastle lightweight-API rules for bare (Kotlin-form) constructor calls.
|
|
189
|
+
// Split by family so X448 and X25519 report their own algorithm string (java-xdh
|
|
190
|
+
// lumps both under "X25519"). Severity/CWE copied from the JCA siblings above.
|
|
191
|
+
const RULE_JAVA_BC_X448: RuleMeta = {
|
|
192
|
+
id: "java-bc-x448",
|
|
193
|
+
title: "Java/Kotlin X448 key agreement (BouncyCastle lightweight API)",
|
|
194
|
+
description: "BouncyCastle X448KeyPairGenerator / X448Agreement / X448PrivateKeyParameters",
|
|
195
|
+
category: "key-exchange",
|
|
196
|
+
severity: "medium",
|
|
197
|
+
confidence: "high",
|
|
198
|
+
algorithm: "X448",
|
|
199
|
+
hndl: true,
|
|
200
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
201
|
+
message:
|
|
202
|
+
"X448 (Java/Kotlin, BouncyCastle lightweight API) is modern but still classical key agreement — harvest-now-decrypt-later.",
|
|
203
|
+
};
|
|
204
|
+
const RULE_JAVA_BC_X25519: RuleMeta = {
|
|
205
|
+
id: "java-bc-x25519",
|
|
206
|
+
title: "Java/Kotlin X25519 key agreement (BouncyCastle lightweight API)",
|
|
207
|
+
description: "BouncyCastle X25519KeyPairGenerator / X25519Agreement",
|
|
208
|
+
category: "key-exchange",
|
|
209
|
+
severity: "medium",
|
|
210
|
+
confidence: "high",
|
|
211
|
+
algorithm: "X25519",
|
|
212
|
+
hndl: true,
|
|
213
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
214
|
+
message:
|
|
215
|
+
"X25519 (Java/Kotlin, BouncyCastle lightweight API) is modern but still classical key agreement — harvest-now-decrypt-later.",
|
|
216
|
+
};
|
|
217
|
+
const RULE_JAVA_BC_EDDSA: RuleMeta = {
|
|
218
|
+
id: "java-bc-eddsa",
|
|
219
|
+
title: "Java/Kotlin Ed25519/Ed448 signature (BouncyCastle lightweight API)",
|
|
220
|
+
description:
|
|
221
|
+
"BouncyCastle Ed448KeyPairGenerator / Ed448Signer / Ed25519KeyPairGenerator / Ed25519Signer",
|
|
222
|
+
category: "signature",
|
|
223
|
+
severity: "low",
|
|
224
|
+
confidence: "high",
|
|
225
|
+
algorithm: "EdDSA",
|
|
226
|
+
hndl: false,
|
|
227
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
228
|
+
message:
|
|
229
|
+
"Ed25519/Ed448 (Java/Kotlin, BouncyCastle lightweight API) is a modern but still classical signature scheme.",
|
|
230
|
+
};
|
|
231
|
+
const RULE_JAVA_TLS_LEGACY: RuleMeta = {
|
|
232
|
+
id: "java-tls-legacy-version",
|
|
233
|
+
title: "Legacy SSL/TLS version requested",
|
|
234
|
+
description: 'SSLContext.getInstance("SSL" | "SSLv3" | "TLSv1")',
|
|
235
|
+
category: "tls",
|
|
236
|
+
severity: "medium",
|
|
237
|
+
confidence: "high",
|
|
238
|
+
hndl: false,
|
|
239
|
+
cwe: CWE_WEAK_STRENGTH,
|
|
240
|
+
message: "SSL/SSLv3/TLS 1.0 are deprecated and insecure (Java/JSSE); require TLS 1.3.",
|
|
241
|
+
remediation: 'Use SSLContext.getInstance("TLSv1.3") and prefer PQC-hybrid key exchange.',
|
|
242
|
+
};
|
|
243
|
+
const RULE_JAVA_TLS_NOVERIFY: RuleMeta = {
|
|
244
|
+
id: "java-tls-hostname-verification-disabled",
|
|
245
|
+
title: "TLS hostname verification disabled",
|
|
246
|
+
description: "NoopHostnameVerifier / ALLOW_ALL_HOSTNAME_VERIFIER",
|
|
247
|
+
category: "tls",
|
|
248
|
+
severity: "high",
|
|
249
|
+
confidence: "high",
|
|
250
|
+
hndl: false,
|
|
251
|
+
cwe: CWE_CERT_VALIDATION,
|
|
252
|
+
message: "An all-trusting hostname verifier (Java) disables TLS hostname checking (MITM risk).",
|
|
253
|
+
remediation: "Remove the all-trusting verifier; rely on the default hostname verifier.",
|
|
254
|
+
};
|
|
255
|
+
const RULE_JAVA_JWT_ALG: RuleMeta = {
|
|
256
|
+
id: "java-jwt-alg",
|
|
257
|
+
title: "Java identifier-form JWT/JOSE algorithm",
|
|
258
|
+
description: "jjwt SignatureAlgorithm.RS/PS/ES* / auth0 Algorithm.RSA*/ECDSA*",
|
|
259
|
+
category: "signature",
|
|
260
|
+
severity: "high",
|
|
261
|
+
confidence: "high",
|
|
262
|
+
algorithm: "unknown",
|
|
263
|
+
hndl: false,
|
|
264
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
265
|
+
message:
|
|
266
|
+
"A classical JWT/JOSE signature algorithm (Java, identifier form) is used, forgeable by a quantum attacker.",
|
|
267
|
+
remediation: "ML-DSA-65 (FIPS 204); track IETF PQC JOSE/COSE algorithms",
|
|
268
|
+
};
|
|
161
269
|
|
|
162
270
|
/**
|
|
163
271
|
* Classify a `<factory>.getInstance("<alg>")` pair into a rule, or null when the
|
|
@@ -175,6 +283,11 @@ function classifyGetInstance(factory: string, rawAlg: string): RuleMeta | null {
|
|
|
175
283
|
if (alg.includes("ED25519") || alg.includes("ED448") || alg.includes("EDDSA"))
|
|
176
284
|
return RULE_JAVA_EDDSA;
|
|
177
285
|
if (alg.includes("X25519") || alg.includes("X448") || alg === "XDH") return RULE_JAVA_XDH;
|
|
286
|
+
// RSASSA-PSS is an RSA *signature* scheme, not encryption/KEM. The string
|
|
287
|
+
// contains "RSA", so it must be caught here — BEFORE the generic RSA branch
|
|
288
|
+
// below, which would otherwise (mis)classify it as HNDL-exposed RSA
|
|
289
|
+
// encryption (java-rsa / hndl:true). Signatures are hndl:false. (Fixes F8.)
|
|
290
|
+
if (alg.includes("PSS")) return RULE_JAVA_RSA_SIGN;
|
|
178
291
|
if (alg.includes("RSA")) return isSignature ? RULE_JAVA_RSA_SIGN : RULE_JAVA_RSA;
|
|
179
292
|
if (alg.includes("DSA")) return RULE_JAVA_DSA; // ECDSA already handled above
|
|
180
293
|
if (alg.includes("DH") || alg.includes("DIFFIEHELLMAN")) return RULE_JAVA_DH;
|
|
@@ -191,12 +304,32 @@ const BC_CLASS_RULES: Record<string, RuleMeta> = {
|
|
|
191
304
|
Ed448Signer: RULE_JAVA_EDDSA,
|
|
192
305
|
X25519Agreement: RULE_JAVA_XDH,
|
|
193
306
|
X448Agreement: RULE_JAVA_XDH,
|
|
307
|
+
ECDHBasicAgreement: RULE_JAVA_ECDH,
|
|
308
|
+
DHBasicAgreement: RULE_JAVA_DH,
|
|
309
|
+
X25519KeyPairGenerator: RULE_JAVA_XDH,
|
|
310
|
+
Ed25519KeyPairGenerator: RULE_JAVA_EDDSA,
|
|
311
|
+
RSAEngine: RULE_JAVA_RSA,
|
|
312
|
+
OAEPEncoding: RULE_JAVA_RSA,
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
/** BouncyCastle lightweight-API bare-constructor class name → family rule. */
|
|
316
|
+
const BC_CURVE_CLASS_RULES: Record<string, RuleMeta> = {
|
|
317
|
+
X448KeyPairGenerator: RULE_JAVA_BC_X448,
|
|
318
|
+
X448Agreement: RULE_JAVA_BC_X448,
|
|
319
|
+
X448PrivateKeyParameters: RULE_JAVA_BC_X448,
|
|
320
|
+
X25519KeyPairGenerator: RULE_JAVA_BC_X25519,
|
|
321
|
+
X25519Agreement: RULE_JAVA_BC_X25519,
|
|
322
|
+
Ed448KeyPairGenerator: RULE_JAVA_BC_EDDSA,
|
|
323
|
+
Ed448Signer: RULE_JAVA_BC_EDDSA,
|
|
324
|
+
Ed25519KeyPairGenerator: RULE_JAVA_BC_EDDSA,
|
|
325
|
+
Ed25519Signer: RULE_JAVA_BC_EDDSA,
|
|
194
326
|
};
|
|
195
327
|
|
|
196
328
|
/** Detects classical asymmetric crypto in Java / Kotlin (JCA + BouncyCastle). */
|
|
197
329
|
export const javaDetector: Detector = {
|
|
198
330
|
id: "java-crypto",
|
|
199
|
-
description:
|
|
331
|
+
description:
|
|
332
|
+
"Classical asymmetric crypto on the JVM — Java/Kotlin/Scala (JCA getInstance + BouncyCastle)",
|
|
200
333
|
scope: "source",
|
|
201
334
|
language: "java",
|
|
202
335
|
rules: [
|
|
@@ -209,6 +342,12 @@ export const javaDetector: Detector = {
|
|
|
209
342
|
RULE_JAVA_DH,
|
|
210
343
|
RULE_JAVA_XDH,
|
|
211
344
|
RULE_JAVA_EDDSA,
|
|
345
|
+
RULE_JAVA_BC_X448,
|
|
346
|
+
RULE_JAVA_BC_X25519,
|
|
347
|
+
RULE_JAVA_BC_EDDSA,
|
|
348
|
+
RULE_JAVA_TLS_LEGACY,
|
|
349
|
+
RULE_JAVA_TLS_NOVERIFY,
|
|
350
|
+
RULE_JAVA_JWT_ALG,
|
|
212
351
|
],
|
|
213
352
|
appliesTo: (f) => hasExtension(f, JAVA_EXTENSIONS),
|
|
214
353
|
detect({ file, content }): Finding[] {
|
|
@@ -230,6 +369,54 @@ export const javaDetector: Detector = {
|
|
|
230
369
|
);
|
|
231
370
|
});
|
|
232
371
|
|
|
372
|
+
// BouncyCastle lightweight-API classes as a bare constructor call (Kotlin
|
|
373
|
+
// form, no `new`). RE_JAVA_BC_CURVE's negative lookbehind excludes the
|
|
374
|
+
// `new <Class>(` form already handled above, so this only adds the missed
|
|
375
|
+
// 448/25519 Kotlin-style matches — no double-counting.
|
|
376
|
+
eachMatch(RE_JAVA_BC_CURVE, content, (m) => {
|
|
377
|
+
const rule = BC_CURVE_CLASS_RULES[m[1]];
|
|
378
|
+
if (!rule) return;
|
|
379
|
+
findings.push(
|
|
380
|
+
findingFromRule(rule, { file, content, index: m.index, matchLength: m[0].length }),
|
|
381
|
+
);
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
// Legacy SSL/TLS protocol version requested from SSLContext.
|
|
385
|
+
eachMatch(RE_JAVA_TLS_LEGACY, content, (m) => {
|
|
386
|
+
findings.push(
|
|
387
|
+
findingFromRule(RULE_JAVA_TLS_LEGACY, {
|
|
388
|
+
file,
|
|
389
|
+
content,
|
|
390
|
+
index: m.index,
|
|
391
|
+
matchLength: m[0].length,
|
|
392
|
+
}),
|
|
393
|
+
);
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
// All-trusting hostname verifier — disables TLS hostname verification.
|
|
397
|
+
eachMatch(RE_JAVA_TLS_NOVERIFY, content, (m) => {
|
|
398
|
+
findings.push(
|
|
399
|
+
findingFromRule(RULE_JAVA_TLS_NOVERIFY, {
|
|
400
|
+
file,
|
|
401
|
+
content,
|
|
402
|
+
index: m.index,
|
|
403
|
+
matchLength: m[0].length,
|
|
404
|
+
}),
|
|
405
|
+
);
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
// Identifier-form JWT/JOSE signature algorithms (jjwt / auth0).
|
|
409
|
+
eachMatch(RE_JAVA_JWT_ALG, content, (m) => {
|
|
410
|
+
findings.push(
|
|
411
|
+
findingFromRule(RULE_JAVA_JWT_ALG, {
|
|
412
|
+
file,
|
|
413
|
+
content,
|
|
414
|
+
index: m.index,
|
|
415
|
+
matchLength: m[0].length,
|
|
416
|
+
}),
|
|
417
|
+
);
|
|
418
|
+
});
|
|
419
|
+
|
|
233
420
|
return findings;
|
|
234
421
|
},
|
|
235
422
|
};
|
|
@@ -0,0 +1,94 @@
|
|
|
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, Finding, RuleMeta } from "../types.js";
|
|
18
|
+
import { DOC_EXTENSIONS, eachMatch, findingFromRule, hasExtension } from "../detect-utils.js";
|
|
19
|
+
import { CWE_BROKEN_CRYPTO } from "../cwe.js";
|
|
20
|
+
|
|
21
|
+
interface JoseRule {
|
|
22
|
+
re: RegExp;
|
|
23
|
+
meta: RuleMeta;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const JOSE_RULES: JoseRule[] = [
|
|
27
|
+
{
|
|
28
|
+
re: /"alg"\s*:\s*"RSA(?:-OAEP(?:-256)?|1_5)"/g,
|
|
29
|
+
meta: {
|
|
30
|
+
id: "jose-jwe-rsa",
|
|
31
|
+
title: "JWE RSA key wrapping",
|
|
32
|
+
description: 'JWE "alg" of RSA-OAEP / RSA-OAEP-256 / RSA1_5 (RFC 7518)',
|
|
33
|
+
category: "kem",
|
|
34
|
+
severity: "high",
|
|
35
|
+
confidence: "high",
|
|
36
|
+
algorithm: "RSA",
|
|
37
|
+
hndl: true,
|
|
38
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
39
|
+
message:
|
|
40
|
+
"JWE wraps the content-encryption key with classical RSA (RSA-OAEP/RSA1_5); the encrypted payload is harvest-now-decrypt-later exposed.",
|
|
41
|
+
remediation:
|
|
42
|
+
"Plan migration to a post-quantum KEM (ML-KEM-768) for key wrapping as JOSE/COSE PQ algorithms are standardised.",
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
re: /"alg"\s*:\s*"ECDH-ES(?:\+A\d{3}KW)?"/g,
|
|
47
|
+
meta: {
|
|
48
|
+
id: "jose-jwe-ecdh",
|
|
49
|
+
title: "JWE ECDH-ES key agreement",
|
|
50
|
+
description: 'JWE "alg" of ECDH-ES / ECDH-ES+A*KW (RFC 7518)',
|
|
51
|
+
category: "key-exchange",
|
|
52
|
+
severity: "high",
|
|
53
|
+
confidence: "high",
|
|
54
|
+
algorithm: "ECDH",
|
|
55
|
+
hndl: true,
|
|
56
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
57
|
+
message:
|
|
58
|
+
"JWE derives the content-encryption key via classical ECDH-ES; the encrypted payload is harvest-now-decrypt-later exposed.",
|
|
59
|
+
remediation:
|
|
60
|
+
"Plan migration to hybrid post-quantum key agreement (X25519MLKEM768) as JOSE PQ algorithms are standardised.",
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
/** Detects classical JWE key-management (`alg`) values in JOSE tokens/config. */
|
|
66
|
+
export const joseDetector: Detector = {
|
|
67
|
+
id: "jose-jwe-keymgmt",
|
|
68
|
+
description:
|
|
69
|
+
"Classical JWE key-management algorithms (RSA-OAEP, ECDH-ES) — confidentiality, HNDL",
|
|
70
|
+
scope: "config",
|
|
71
|
+
language: "any",
|
|
72
|
+
rules: JOSE_RULES.map((r) => r.meta),
|
|
73
|
+
// Prose examples (a README showing `"alg":"RSA-OAEP"`) are not JOSE config.
|
|
74
|
+
appliesTo: (f) => !hasExtension(f, DOC_EXTENSIONS),
|
|
75
|
+
detect({ file, content }): Finding[] {
|
|
76
|
+
// Fast reject: no JOSE key-management alg token present.
|
|
77
|
+
if (
|
|
78
|
+
!content.includes("RSA-OAEP") &&
|
|
79
|
+
!content.includes("RSA1_5") &&
|
|
80
|
+
!content.includes("ECDH-ES")
|
|
81
|
+
) {
|
|
82
|
+
return [];
|
|
83
|
+
}
|
|
84
|
+
const findings: Finding[] = [];
|
|
85
|
+
for (const rule of JOSE_RULES) {
|
|
86
|
+
eachMatch(rule.re, content, (m) => {
|
|
87
|
+
findings.push(
|
|
88
|
+
findingFromRule(rule.meta, { file, content, index: m.index, matchLength: m[0].length }),
|
|
89
|
+
);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
return findings;
|
|
93
|
+
},
|
|
94
|
+
};
|