@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,119 @@
|
|
|
1
|
+
import { eachMatch, findingFromRule, hasExtension, maskCommentLines, DOC_EXTENSIONS, ANALYZABLE_SOURCE_EXTENSIONS, } from "../detect-utils.js";
|
|
2
|
+
import { CWE_BROKEN_CRYPTO } from "../cwe.js";
|
|
3
|
+
// --- OpenSSH certificate key types (`*-cert-v01@openssh.com`), by signing family. ---
|
|
4
|
+
// The `\b` after `.com` is a real boundary (`m` is a word char); the leading `\b`
|
|
5
|
+
// keeps `ssh-rsa-cert-v01@…` from matching inside a longer token. RSA covers the
|
|
6
|
+
// legacy `ssh-rsa` cert type plus the SHA-2 RSA cert types (`rsa-sha2-256/512`)
|
|
7
|
+
// OpenSSH emits for RSA CA/host certificates.
|
|
8
|
+
const RE_CERT_RSA = /\b(?:ssh-rsa|rsa-sha2-(?:256|512))-cert-v01@openssh\.com\b/g;
|
|
9
|
+
const RE_CERT_ECDSA = /\becdsa-sha2-nistp(?:256|384|521)-cert-v01@openssh\.com\b/g;
|
|
10
|
+
const RE_CERT_EDDSA = /\bssh-ed25519-cert-v01@openssh\.com\b/g;
|
|
11
|
+
// The canonical CA *deployment* directives — the most common way an SSH CA is
|
|
12
|
+
// configured (sshd_config `TrustedUserCAKeys` / `HostCertificate`, and the CA
|
|
13
|
+
// signing command `ssh-keygen -s`). These name the CA usage but not the algorithm
|
|
14
|
+
// (that lives in the referenced key file), so the finding is `algorithm: "unknown"`.
|
|
15
|
+
const RE_CA_DIRECTIVE = /\bTrustedUserCAKeys\b|\bHostCertificate\b|\bssh-keygen\s+-s\b/g;
|
|
16
|
+
const REMEDIATION = "No post-quantum SSH certificate format is standardized yet — track OpenSSH release notes and IETF work on PQC signatures for SSH. SSH CA keys are long-lived trust roots, so plan for their rotation to a PQC signing algorithm (e.g. ML-DSA) as soon as a cert format lands, and keep validity periods short in the interim.";
|
|
17
|
+
const RULE_CA_RSA = {
|
|
18
|
+
id: "ssh-ca-rsa-cert",
|
|
19
|
+
title: "SSH certificate authority — RSA signing",
|
|
20
|
+
description: "OpenSSH RSA certificate key type (ssh-rsa/rsa-sha2-*-cert-v01@openssh.com)",
|
|
21
|
+
category: "signature",
|
|
22
|
+
severity: "medium",
|
|
23
|
+
confidence: "high",
|
|
24
|
+
algorithm: "RSA",
|
|
25
|
+
hndl: false,
|
|
26
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
27
|
+
sensitive: true,
|
|
28
|
+
message: "SSH certificate uses a classical RSA key type (ssh-rsa/rsa-sha2-*-cert-v01@openssh.com); the CA signature is forgeable once a CRQC can recover the RSA CA key.",
|
|
29
|
+
remediation: REMEDIATION,
|
|
30
|
+
};
|
|
31
|
+
const RULE_CA_ECDSA = {
|
|
32
|
+
id: "ssh-ca-ecdsa-cert",
|
|
33
|
+
title: "SSH certificate authority — ECDSA signing",
|
|
34
|
+
description: "OpenSSH ECDSA certificate key type (ecdsa-sha2-nistp*-cert-v01@openssh.com)",
|
|
35
|
+
category: "signature",
|
|
36
|
+
severity: "medium",
|
|
37
|
+
confidence: "high",
|
|
38
|
+
algorithm: "ECDSA",
|
|
39
|
+
hndl: false,
|
|
40
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
41
|
+
sensitive: true,
|
|
42
|
+
message: "SSH certificate uses a classical ECDSA key type (ecdsa-sha2-nistp*-cert-v01@openssh.com); the CA signature is forgeable once a CRQC can recover the ECDSA CA key.",
|
|
43
|
+
remediation: REMEDIATION,
|
|
44
|
+
};
|
|
45
|
+
const RULE_CA_EDDSA = {
|
|
46
|
+
id: "ssh-ca-ed25519-cert",
|
|
47
|
+
title: "SSH certificate authority — EdDSA signing",
|
|
48
|
+
description: "OpenSSH Ed25519 certificate key type (ssh-ed25519-cert-v01@openssh.com)",
|
|
49
|
+
category: "signature",
|
|
50
|
+
severity: "medium",
|
|
51
|
+
confidence: "high",
|
|
52
|
+
algorithm: "EdDSA",
|
|
53
|
+
hndl: false,
|
|
54
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
55
|
+
sensitive: true,
|
|
56
|
+
message: "SSH certificate uses a classical Ed25519 key type (ssh-ed25519-cert-v01@openssh.com); modern but still classical — the CA signature is forgeable once a CRQC can recover the Ed25519 CA key.",
|
|
57
|
+
remediation: REMEDIATION,
|
|
58
|
+
};
|
|
59
|
+
const RULE_CA_CONFIG = {
|
|
60
|
+
id: "ssh-ca-config",
|
|
61
|
+
title: "SSH certificate authority configured",
|
|
62
|
+
description: "OpenSSH CA deployment directive (TrustedUserCAKeys / HostCertificate / ssh-keygen -s)",
|
|
63
|
+
category: "signature",
|
|
64
|
+
severity: "medium",
|
|
65
|
+
// The directive names CA usage, not the algorithm — hence a lower confidence and
|
|
66
|
+
// an unknown family; the CA key file itself carries the specific algorithm.
|
|
67
|
+
confidence: "medium",
|
|
68
|
+
algorithm: "unknown",
|
|
69
|
+
hndl: false,
|
|
70
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
71
|
+
message: "SSH certificate authority is configured (TrustedUserCAKeys / HostCertificate / ssh-keygen -s); the CA signing key is a long-lived classical trust root whose signatures become forgeable once a CRQC exists — verify the CA key's algorithm.",
|
|
72
|
+
remediation: REMEDIATION,
|
|
73
|
+
};
|
|
74
|
+
const SSH_CA_RULES = [
|
|
75
|
+
{ meta: RULE_CA_RSA, re: RE_CERT_RSA },
|
|
76
|
+
{ meta: RULE_CA_ECDSA, re: RE_CERT_ECDSA },
|
|
77
|
+
{ meta: RULE_CA_EDDSA, re: RE_CERT_EDDSA },
|
|
78
|
+
{ meta: RULE_CA_CONFIG, re: RE_CA_DIRECTIVE },
|
|
79
|
+
];
|
|
80
|
+
/** True when `content` carries some SSH-CA-specific marker (not just a bare token). */
|
|
81
|
+
function hasSshCaMarker(content) {
|
|
82
|
+
return (content.includes("cert-v01@openssh.com") ||
|
|
83
|
+
content.includes("@cert-authority") ||
|
|
84
|
+
content.includes("TrustedUserCAKeys") ||
|
|
85
|
+
content.includes("HostCertificate") ||
|
|
86
|
+
content.includes("ssh-keygen -s"));
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Detects classical SSH certificate-authority signing (OpenSSH cert key types)
|
|
90
|
+
* in SSH config, sshd_config, and known_hosts files. Distinct from SSH
|
|
91
|
+
* key-exchange (`ssh-kex-classical`): this is the certificate SIGNATURE surface.
|
|
92
|
+
*/
|
|
93
|
+
export const sshCaDetector = {
|
|
94
|
+
id: "ssh-ca",
|
|
95
|
+
description: "Classical SSH certificate-authority signing (OpenSSH *-cert-v01@openssh.com)",
|
|
96
|
+
scope: "config",
|
|
97
|
+
language: "any",
|
|
98
|
+
rules: SSH_CA_RULES.map((r) => r.meta),
|
|
99
|
+
// Apply broadly (SSH CA config lives in many differently-named / extensionless
|
|
100
|
+
// files: sshd_config, known_hosts, *.pub) but never on prose/docs OR on program
|
|
101
|
+
// SOURCE files — a vendored SSH library or a constants table that spells out
|
|
102
|
+
// `ssh-ed25519-cert-v01@openssh.com` as a string literal is not a live CA config.
|
|
103
|
+
// The strict fast-reject in detect() is the remaining gate.
|
|
104
|
+
appliesTo: (f) => !hasExtension(f, DOC_EXTENSIONS) && !hasExtension(f, ANALYZABLE_SOURCE_EXTENSIONS),
|
|
105
|
+
detect({ file, content }) {
|
|
106
|
+
if (!hasSshCaMarker(content))
|
|
107
|
+
return [];
|
|
108
|
+
// Mask `#` comment lines so a commented-out cert line can't fire; offsets are
|
|
109
|
+
// preserved. `@cert-authority` known_hosts lines start with `@`, not `#`, so
|
|
110
|
+
// they are intentionally left live.
|
|
111
|
+
const scan = maskCommentLines(content, ["#"]);
|
|
112
|
+
const findings = [];
|
|
113
|
+
for (const { meta, re } of SSH_CA_RULES) {
|
|
114
|
+
eachMatch(re, scan, (m) => findings.push(findingFromRule(meta, { file, content, index: m.index, matchLength: m[0].length })));
|
|
115
|
+
}
|
|
116
|
+
return findings;
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
//# sourceMappingURL=ssh-ca.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssh-ca.js","sourceRoot":"","sources":["../../src/detectors/ssh-ca.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Config detector: classical SSH **certificate-authority** cryptography — the\n * OpenSSH certificate mechanism, in which a CA key signs host/user certificates\n * (`*-cert-v01@openssh.com`) that servers and clients then trust in place of\n * bare public keys.\n *\n * This is DIFFERENT from the `ssh-kex-classical` rule in `source.ts`, and from\n * the `ssh-public-key` rule there — deliberately non-overlapping:\n * - `ssh-kex-classical` is about the SSH *key-exchange* (finite-field DH, ECDH,\n * curve25519): session-key *agreement*, `category: \"key-exchange\"`,\n * `hndl: true` — a passively-recorded handshake is decryptable once a CRQC\n * exists (harvest-now-decrypt-later confidentiality loss).\n * - `ssh-public-key` flags bare `ssh-rsa AAAA…` / `ecdsa-sha2-* …` key lines.\n * - THIS detector flags the SSH **certificate / CA signing** surface: the\n * `*-cert-v01@openssh.com` cert key types, the `@cert-authority` known_hosts\n * marker, the `TrustedUserCAKeys` / `HostCertificate` sshd directives, and\n * `ssh-keygen -s` (the command that signs a certificate with a CA key).\n *\n * WHY it matters for PQC: an SSH certificate is a *signature* made by a CA key\n * over a principal's public key + validity constraints. There is no\n * confidentiality to harvest (so `hndl: false`), but every such signature\n * becomes FORGEABLE the moment a cryptographically-relevant quantum computer\n * (CRQC) can recover the classical CA private key from its public key. Forging a\n * CA signature lets an attacker mint host or user certificates that every relying\n * party accepts — a full trust-root compromise. SSH CA keys are also unusually\n * long-lived (they are the anchor an entire fleet trusts and are rotated\n * rarely), so the exposure window is large. Hence `category: \"signature\"`,\n * `severity: \"medium\"`, `confidence: \"high\"`.\n *\n * Two match shapes:\n * 1. The cert key type, which NAMES the signing algorithm → an accurate\n * {@link AlgorithmFamily}:\n * - `ssh-rsa-cert-v01@openssh.com`, `rsa-sha2-256/512-cert-v01@openssh.com` → RSA\n * - `ecdsa-sha2-nistp256/384/521-cert-v01@openssh.com` → ECDSA\n * - `ssh-ed25519-cert-v01@openssh.com` → EdDSA\n * 2. The CA *deployment* directives — `TrustedUserCAKeys` / `HostCertificate`\n * (sshd_config) and `ssh-keygen -s` (the CA signing command). These are the\n * MOST COMMON way an SSH CA is configured, but they don't name the algorithm\n * (that lives in the referenced key file), so they emit the `ssh-ca-config`\n * rule with `algorithm: \"unknown\"` and `confidence: \"medium\"`.\n *\n * Precision:\n * - Fast reject: `detect()` bails unless the file carries an SSH-CA marker\n * (`cert-v01@openssh.com`, `@cert-authority`, `TrustedUserCAKeys`,\n * `HostCertificate`, or `ssh-keygen -s`) — so the algorithm tokens can't be\n * reached on unrelated config.\n * - The cert-type tokens are the full `*-cert-v01@openssh.com` strings. The\n * trailing `-cert-v01@openssh.com` suffix distinguishes a CA certificate type\n * from the plain `ssh-rsa` / `ssh-ed25519` public-key tokens handled by\n * `ssh-public-key`, so a non-cert `ssh-ed25519 AAAA…` line NEVER fires a cert\n * rule here.\n * - Comment lines (`#`) are masked with {@link maskCommentLines} (offsets\n * preserved) so a commented-out cert line can't fire. Known_hosts\n * `@cert-authority` lines start with `@`, not `#`, so masking leaves them\n * live — exactly what we want.\n * - Doc/prose files are excluded ({@link DOC_EXTENSIONS}), and so are program\n * SOURCE files ({@link ANALYZABLE_SOURCE_EXTENSIONS}) — a vendored SSH library\n * or constants table that spells a cert type as a string literal is not live\n * CA config. SSH CA config lives in extensionless / `.conf` / `.pub` files.\n *\n * The matched line frequently carries the CA public key's base64 blob (a\n * `@cert-authority` known_hosts entry), so findings are marked `sensitive` and\n * reporters drop the snippet, consistent with `ssh-public-key`.\n */\nimport type { Detector, Finding, RuleMeta } from \"../types.js\";\nimport {\n eachMatch,\n findingFromRule,\n hasExtension,\n maskCommentLines,\n DOC_EXTENSIONS,\n ANALYZABLE_SOURCE_EXTENSIONS,\n} from \"../detect-utils.js\";\nimport { CWE_BROKEN_CRYPTO } from \"../cwe.js\";\n\n// --- OpenSSH certificate key types (`*-cert-v01@openssh.com`), by signing family. ---\n// The `\\b` after `.com` is a real boundary (`m` is a word char); the leading `\\b`\n// keeps `ssh-rsa-cert-v01@…` from matching inside a longer token. RSA covers the\n// legacy `ssh-rsa` cert type plus the SHA-2 RSA cert types (`rsa-sha2-256/512`)\n// OpenSSH emits for RSA CA/host certificates.\nconst RE_CERT_RSA = /\\b(?:ssh-rsa|rsa-sha2-(?:256|512))-cert-v01@openssh\\.com\\b/g;\nconst RE_CERT_ECDSA = /\\becdsa-sha2-nistp(?:256|384|521)-cert-v01@openssh\\.com\\b/g;\nconst RE_CERT_EDDSA = /\\bssh-ed25519-cert-v01@openssh\\.com\\b/g;\n// The canonical CA *deployment* directives — the most common way an SSH CA is\n// configured (sshd_config `TrustedUserCAKeys` / `HostCertificate`, and the CA\n// signing command `ssh-keygen -s`). These name the CA usage but not the algorithm\n// (that lives in the referenced key file), so the finding is `algorithm: \"unknown\"`.\nconst RE_CA_DIRECTIVE = /\\bTrustedUserCAKeys\\b|\\bHostCertificate\\b|\\bssh-keygen\\s+-s\\b/g;\n\nconst REMEDIATION =\n \"No post-quantum SSH certificate format is standardized yet — track OpenSSH release notes and IETF work on PQC signatures for SSH. SSH CA keys are long-lived trust roots, so plan for their rotation to a PQC signing algorithm (e.g. ML-DSA) as soon as a cert format lands, and keep validity periods short in the interim.\";\n\nconst RULE_CA_RSA: RuleMeta = {\n id: \"ssh-ca-rsa-cert\",\n title: \"SSH certificate authority — RSA signing\",\n description: \"OpenSSH RSA certificate key type (ssh-rsa/rsa-sha2-*-cert-v01@openssh.com)\",\n category: \"signature\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"RSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n sensitive: true,\n message:\n \"SSH certificate uses a classical RSA key type (ssh-rsa/rsa-sha2-*-cert-v01@openssh.com); the CA signature is forgeable once a CRQC can recover the RSA CA key.\",\n remediation: REMEDIATION,\n};\nconst RULE_CA_ECDSA: RuleMeta = {\n id: \"ssh-ca-ecdsa-cert\",\n title: \"SSH certificate authority — ECDSA signing\",\n description: \"OpenSSH ECDSA certificate key type (ecdsa-sha2-nistp*-cert-v01@openssh.com)\",\n category: \"signature\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"ECDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n sensitive: true,\n message:\n \"SSH certificate uses a classical ECDSA key type (ecdsa-sha2-nistp*-cert-v01@openssh.com); the CA signature is forgeable once a CRQC can recover the ECDSA CA key.\",\n remediation: REMEDIATION,\n};\nconst RULE_CA_EDDSA: RuleMeta = {\n id: \"ssh-ca-ed25519-cert\",\n title: \"SSH certificate authority — EdDSA signing\",\n description: \"OpenSSH Ed25519 certificate key type (ssh-ed25519-cert-v01@openssh.com)\",\n category: \"signature\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"EdDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n sensitive: true,\n message:\n \"SSH certificate uses a classical Ed25519 key type (ssh-ed25519-cert-v01@openssh.com); modern but still classical — the CA signature is forgeable once a CRQC can recover the Ed25519 CA key.\",\n remediation: REMEDIATION,\n};\n\nconst RULE_CA_CONFIG: RuleMeta = {\n id: \"ssh-ca-config\",\n title: \"SSH certificate authority configured\",\n description:\n \"OpenSSH CA deployment directive (TrustedUserCAKeys / HostCertificate / ssh-keygen -s)\",\n category: \"signature\",\n severity: \"medium\",\n // The directive names CA usage, not the algorithm — hence a lower confidence and\n // an unknown family; the CA key file itself carries the specific algorithm.\n confidence: \"medium\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"SSH certificate authority is configured (TrustedUserCAKeys / HostCertificate / ssh-keygen -s); the CA signing key is a long-lived classical trust root whose signatures become forgeable once a CRQC exists — verify the CA key's algorithm.\",\n remediation: REMEDIATION,\n};\n\ninterface SshCaRule {\n meta: RuleMeta;\n re: RegExp;\n}\n\nconst SSH_CA_RULES: readonly SshCaRule[] = [\n { meta: RULE_CA_RSA, re: RE_CERT_RSA },\n { meta: RULE_CA_ECDSA, re: RE_CERT_ECDSA },\n { meta: RULE_CA_EDDSA, re: RE_CERT_EDDSA },\n { meta: RULE_CA_CONFIG, re: RE_CA_DIRECTIVE },\n];\n\n/** True when `content` carries some SSH-CA-specific marker (not just a bare token). */\nfunction hasSshCaMarker(content: string): boolean {\n return (\n content.includes(\"cert-v01@openssh.com\") ||\n content.includes(\"@cert-authority\") ||\n content.includes(\"TrustedUserCAKeys\") ||\n content.includes(\"HostCertificate\") ||\n content.includes(\"ssh-keygen -s\")\n );\n}\n\n/**\n * Detects classical SSH certificate-authority signing (OpenSSH cert key types)\n * in SSH config, sshd_config, and known_hosts files. Distinct from SSH\n * key-exchange (`ssh-kex-classical`): this is the certificate SIGNATURE surface.\n */\nexport const sshCaDetector: Detector = {\n id: \"ssh-ca\",\n description: \"Classical SSH certificate-authority signing (OpenSSH *-cert-v01@openssh.com)\",\n scope: \"config\",\n language: \"any\",\n rules: SSH_CA_RULES.map((r) => r.meta),\n // Apply broadly (SSH CA config lives in many differently-named / extensionless\n // files: sshd_config, known_hosts, *.pub) but never on prose/docs OR on program\n // SOURCE files — a vendored SSH library or a constants table that spells out\n // `ssh-ed25519-cert-v01@openssh.com` as a string literal is not a live CA config.\n // The strict fast-reject in detect() is the remaining gate.\n appliesTo: (f) =>\n !hasExtension(f, DOC_EXTENSIONS) && !hasExtension(f, ANALYZABLE_SOURCE_EXTENSIONS),\n detect({ file, content }): Finding[] {\n if (!hasSshCaMarker(content)) return [];\n\n // Mask `#` comment lines so a commented-out cert line can't fire; offsets are\n // preserved. `@cert-authority` known_hosts lines start with `@`, not `#`, so\n // they are intentionally left live.\n const scan = maskCommentLines(content, [\"#\"]);\n const findings: Finding[] = [];\n for (const { meta, re } of SSH_CA_RULES) {\n eachMatch(re, scan, (m) =>\n findings.push(\n findingFromRule(meta, { file, content, index: m.index, matchLength: m[0].length }),\n ),\n );\n }\n return findings;\n },\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stateful-hbs.d.ts","sourceRoot":"","sources":["../../src/detectors/stateful-hbs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAqB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"stateful-hbs.d.ts","sourceRoot":"","sources":["../../src/detectors/stateful-hbs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAqB,MAAM,aAAa,CAAC;AAuI/D,mFAAmF;AACnF,eAAO,MAAM,mBAAmB,EAAE,QAyBjC,CAAC"}
|
|
@@ -10,8 +10,9 @@ const STATEFUL_HBS_REMEDIATION = "LMS/HSS/XMSS/XMSSMT are NIST-approved (SP 800-
|
|
|
10
10
|
"stateless ML-DSA (FIPS 204) or SLH-DSA (FIPS 205).";
|
|
11
11
|
const HBS_RULES = [
|
|
12
12
|
{
|
|
13
|
-
// LMS parameter set, e.g. LMS_SHA256_M32_H10
|
|
14
|
-
|
|
13
|
+
// LMS parameter set, e.g. LMS_SHA256_M32_H10 / LMS_SHAKE_M24_H10 (SP 800-208
|
|
14
|
+
// adds SHAKE256 and the 192-bit M24/N24 sets to RFC 8554's SHA-256 sets).
|
|
15
|
+
re: /\bLMS_(?:SHA256|SHAKE(?:256)?)_[MN]\d+_[HW]\d+\b/g,
|
|
15
16
|
meta: {
|
|
16
17
|
id: "stateful-hbs-lms-param",
|
|
17
18
|
title: "LMS parameter set (stateful hash-based signature)",
|
|
@@ -61,8 +62,9 @@ const HBS_RULES = [
|
|
|
61
62
|
},
|
|
62
63
|
},
|
|
63
64
|
{
|
|
64
|
-
// XMSS parameter set, e.g. XMSS-SHA2_10_256
|
|
65
|
-
|
|
65
|
+
// XMSS parameter set, e.g. XMSS-SHA2_10_256 / XMSS-SHAKE256_10_192 (SP 800-208
|
|
66
|
+
// adds the SHAKE256 and 192-bit variants to RFC 8391's SHA-2/256 sets).
|
|
67
|
+
re: /\bXMSS-(?:SHA2|SHAKE(?:256)?)_\d+_(?:192|256)\b/g,
|
|
66
68
|
meta: {
|
|
67
69
|
id: "stateful-hbs-xmss-param",
|
|
68
70
|
title: "XMSS parameter set (stateful hash-based signature)",
|
|
@@ -78,8 +80,9 @@ const HBS_RULES = [
|
|
|
78
80
|
},
|
|
79
81
|
},
|
|
80
82
|
{
|
|
81
|
-
// XMSSMT (multi-tree XMSS) parameter set, e.g. XMSSMT-SHA2_20/2_256
|
|
82
|
-
|
|
83
|
+
// XMSSMT (multi-tree XMSS) parameter set, e.g. XMSSMT-SHA2_20/2_256 or the
|
|
84
|
+
// SP 800-208 SHAKE256 variant XMSSMT-SHAKE256_20/2_256.
|
|
85
|
+
re: /\bXMSSMT-(?:SHA2|SHAKE(?:256)?)_\d+\b/g,
|
|
83
86
|
meta: {
|
|
84
87
|
id: "stateful-hbs-xmssmt-param",
|
|
85
88
|
title: "XMSSMT parameter set (stateful hash-based signature)",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stateful-hbs.js","sourceRoot":"","sources":["../../src/detectors/stateful-hbs.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Config / source-agnostic detector: stateful hash-based signatures\n * (NIST SP 800-208) — LMS, HSS, XMSS and XMSSMT.\n *\n * These schemes ARE quantum-safe and NIST-approved (SP 800-208, for firmware /\n * secure-boot signing), so this is NOT a \"broken crypto\" finding. The hazard it\n * flags is STATE MANAGEMENT: each private key holds a bounded set of one-time\n * key indices, and reusing an index is catastrophic (it enables signature\n * forgery). The detector therefore surfaces the usage so a reviewer can confirm\n * rigorous state handling exists — or migrate to a stateless scheme.\n *\n * Like {@link pemDetector}, this is a `scope: \"config\"`, `language: \"any\"`\n * detector that runs on every text file, because the distinctive LMS/XMSS\n * parameter strings and library tokens (`LMS_SHA256_M32_H10`, `pyhsslms`,\n * `XMSS-SHA2_10_256`, …) appear identically across languages, config, and docs.\n * Every rule's metadata lives in the {@link RuleMeta} declaration below; the\n * regexes are tightly bounded and `\\b`-anchored to stay high-signal.\n */\nimport type { Detector, Finding, RuleMeta } from \"../types.js\";\nimport { eachMatch, findingFromRule } from \"../detect-utils.js\";\nimport { CWE_RISKY_PRIMITIVE } from \"../cwe.js\";\n\n/**\n * Shared remediation for every stateful-HBS finding: these are approved but\n * STATEFUL, so the reviewer must confirm state management before trusting them.\n */\nconst STATEFUL_HBS_REMEDIATION =\n \"LMS/HSS/XMSS/XMSSMT are NIST-approved (SP 800-208) but STATEFUL: the signer \" +\n \"must NEVER reuse a one-time key index (reuse enables signature forgery). Use \" +\n \"only with rigorous, crash-safe state management; otherwise prefer the \" +\n \"stateless ML-DSA (FIPS 204) or SLH-DSA (FIPS 205).\";\n\n/** A stateful-HBS rule: its catalog metadata plus the token regex that triggers it. */\ninterface HbsRule {\n /** Global regex matching the distinctive token. */\n re: RegExp;\n meta: RuleMeta;\n}\n\nconst HBS_RULES: HbsRule[] = [\n {\n // LMS parameter set, e.g. LMS_SHA256_M32_H10 (RFC 8554 / SP 800-208).\n re: /\\bLMS_SHA256_[MN]\\d+_[HW]\\d+\\b/g,\n meta: {\n id: \"stateful-hbs-lms-param\",\n title: \"LMS parameter set (stateful hash-based signature)\",\n description: \"LMS/HSS one-time-signature parameter string (SP 800-208)\",\n category: \"signature\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_RISKY_PRIMITIVE,\n message:\n \"LMS parameter set — NIST-approved (SP 800-208) but STATEFUL: reusing a one-time key index is catastrophic.\",\n remediation: STATEFUL_HBS_REMEDIATION,\n },\n },\n {\n // HSS keygen (hierarchical LMS), e.g. pyhsslms.hss_generate_private_key(...).\n re: /\\bhss_generate_private_key\\b/g,\n meta: {\n id: \"stateful-hbs-hss-keygen\",\n title: \"HSS private-key generation (stateful hash-based signature)\",\n description: \"HSS (hierarchical LMS) private-key generation call (SP 800-208)\",\n category: \"signature\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_RISKY_PRIMITIVE,\n message:\n \"HSS private-key generation — NIST-approved (SP 800-208) but STATEFUL: never reuse a one-time key index.\",\n remediation: STATEFUL_HBS_REMEDIATION,\n },\n },\n {\n // pyhsslms — the Python LMS/HSS library import token.\n re: /\\bpyhsslms\\b/g,\n meta: {\n id: \"stateful-hbs-pyhsslms\",\n title: \"pyhsslms library (stateful LMS/HSS signatures)\",\n description: \"Reference to the pyhsslms LMS/HSS library (SP 800-208)\",\n category: \"signature\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_RISKY_PRIMITIVE,\n message:\n \"pyhsslms (LMS/HSS) — NIST-approved (SP 800-208) but STATEFUL: the signer must never reuse a one-time key index.\",\n remediation: STATEFUL_HBS_REMEDIATION,\n },\n },\n {\n // XMSS parameter set, e.g. XMSS-SHA2_10_256 (RFC 8391 / SP 800-208).\n re: /\\bXMSS-SHA2_\\d+_256\\b/g,\n meta: {\n id: \"stateful-hbs-xmss-param\",\n title: \"XMSS parameter set (stateful hash-based signature)\",\n description: \"XMSS one-time-signature parameter string (SP 800-208)\",\n category: \"signature\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_RISKY_PRIMITIVE,\n message:\n \"XMSS parameter set — NIST-approved (SP 800-208) but STATEFUL: reusing a one-time key index is catastrophic.\",\n remediation: STATEFUL_HBS_REMEDIATION,\n },\n },\n {\n // XMSSMT (multi-tree XMSS) parameter set, e.g. XMSSMT-SHA2_20/2_256.\n re: /\\bXMSSMT-SHA2_\\d+\\b/g,\n meta: {\n id: \"stateful-hbs-xmssmt-param\",\n title: \"XMSSMT parameter set (stateful hash-based signature)\",\n description: \"XMSSMT (multi-tree XMSS) parameter string (SP 800-208)\",\n category: \"signature\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_RISKY_PRIMITIVE,\n message:\n \"XMSSMT parameter set — NIST-approved (SP 800-208) but STATEFUL: never reuse a one-time key index.\",\n remediation: STATEFUL_HBS_REMEDIATION,\n },\n },\n {\n // XMSS keypair generation, e.g. xmss_keypair(...) (liboqs / xmss reference).\n re: /\\bxmss_keypair\\b/g,\n meta: {\n id: \"stateful-hbs-xmss-keypair\",\n title: \"XMSS keypair generation (stateful hash-based signature)\",\n description: \"XMSS keypair-generation call (SP 800-208)\",\n category: \"signature\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_RISKY_PRIMITIVE,\n message:\n \"XMSS keypair generation — NIST-approved (SP 800-208) but STATEFUL: the signer must never reuse a one-time key index.\",\n remediation: STATEFUL_HBS_REMEDIATION,\n },\n },\n];\n\n/** Detects stateful hash-based signature (SP 800-208) usage in arbitrary files. */\nexport const statefulHbsDetector: Detector = {\n id: \"stateful-hbs\",\n description:\n \"Stateful hash-based signatures (NIST SP 800-208: LMS / HSS / XMSS / XMSSMT) in any file\",\n scope: \"config\",\n language: \"any\",\n rules: HBS_RULES.map((r) => r.meta),\n // Applies to every text file; the walker already filters out binaries.\n appliesTo: () => true,\n detect({ file, content }): Finding[] {\n const findings: Finding[] = [];\n for (const rule of HBS_RULES) {\n eachMatch(rule.re, content, (m) => {\n findings.push(\n findingFromRule(rule.meta, {\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":"stateful-hbs.js","sourceRoot":"","sources":["../../src/detectors/stateful-hbs.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Config / source-agnostic detector: stateful hash-based signatures\n * (NIST SP 800-208) — LMS, HSS, XMSS and XMSSMT.\n *\n * These schemes ARE quantum-safe and NIST-approved (SP 800-208, for firmware /\n * secure-boot signing), so this is NOT a \"broken crypto\" finding. The hazard it\n * flags is STATE MANAGEMENT: each private key holds a bounded set of one-time\n * key indices, and reusing an index is catastrophic (it enables signature\n * forgery). The detector therefore surfaces the usage so a reviewer can confirm\n * rigorous state handling exists — or migrate to a stateless scheme.\n *\n * Like {@link pemDetector}, this is a `scope: \"config\"`, `language: \"any\"`\n * detector that runs on every text file, because the distinctive LMS/XMSS\n * parameter strings and library tokens (`LMS_SHA256_M32_H10`, `pyhsslms`,\n * `XMSS-SHA2_10_256`, …) appear identically across languages, config, and docs.\n * Every rule's metadata lives in the {@link RuleMeta} declaration below; the\n * regexes are tightly bounded and `\\b`-anchored to stay high-signal.\n */\nimport type { Detector, Finding, RuleMeta } from \"../types.js\";\nimport { eachMatch, findingFromRule } from \"../detect-utils.js\";\nimport { CWE_RISKY_PRIMITIVE } from \"../cwe.js\";\n\n/**\n * Shared remediation for every stateful-HBS finding: these are approved but\n * STATEFUL, so the reviewer must confirm state management before trusting them.\n */\nconst STATEFUL_HBS_REMEDIATION =\n \"LMS/HSS/XMSS/XMSSMT are NIST-approved (SP 800-208) but STATEFUL: the signer \" +\n \"must NEVER reuse a one-time key index (reuse enables signature forgery). Use \" +\n \"only with rigorous, crash-safe state management; otherwise prefer the \" +\n \"stateless ML-DSA (FIPS 204) or SLH-DSA (FIPS 205).\";\n\n/** A stateful-HBS rule: its catalog metadata plus the token regex that triggers it. */\ninterface HbsRule {\n /** Global regex matching the distinctive token. */\n re: RegExp;\n meta: RuleMeta;\n}\n\nconst HBS_RULES: HbsRule[] = [\n {\n // LMS parameter set, e.g. LMS_SHA256_M32_H10 / LMS_SHAKE_M24_H10 (SP 800-208\n // adds SHAKE256 and the 192-bit M24/N24 sets to RFC 8554's SHA-256 sets).\n re: /\\bLMS_(?:SHA256|SHAKE(?:256)?)_[MN]\\d+_[HW]\\d+\\b/g,\n meta: {\n id: \"stateful-hbs-lms-param\",\n title: \"LMS parameter set (stateful hash-based signature)\",\n description: \"LMS/HSS one-time-signature parameter string (SP 800-208)\",\n category: \"signature\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_RISKY_PRIMITIVE,\n message:\n \"LMS parameter set — NIST-approved (SP 800-208) but STATEFUL: reusing a one-time key index is catastrophic.\",\n remediation: STATEFUL_HBS_REMEDIATION,\n },\n },\n {\n // HSS keygen (hierarchical LMS), e.g. pyhsslms.hss_generate_private_key(...).\n re: /\\bhss_generate_private_key\\b/g,\n meta: {\n id: \"stateful-hbs-hss-keygen\",\n title: \"HSS private-key generation (stateful hash-based signature)\",\n description: \"HSS (hierarchical LMS) private-key generation call (SP 800-208)\",\n category: \"signature\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_RISKY_PRIMITIVE,\n message:\n \"HSS private-key generation — NIST-approved (SP 800-208) but STATEFUL: never reuse a one-time key index.\",\n remediation: STATEFUL_HBS_REMEDIATION,\n },\n },\n {\n // pyhsslms — the Python LMS/HSS library import token.\n re: /\\bpyhsslms\\b/g,\n meta: {\n id: \"stateful-hbs-pyhsslms\",\n title: \"pyhsslms library (stateful LMS/HSS signatures)\",\n description: \"Reference to the pyhsslms LMS/HSS library (SP 800-208)\",\n category: \"signature\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_RISKY_PRIMITIVE,\n message:\n \"pyhsslms (LMS/HSS) — NIST-approved (SP 800-208) but STATEFUL: the signer must never reuse a one-time key index.\",\n remediation: STATEFUL_HBS_REMEDIATION,\n },\n },\n {\n // XMSS parameter set, e.g. XMSS-SHA2_10_256 / XMSS-SHAKE256_10_192 (SP 800-208\n // adds the SHAKE256 and 192-bit variants to RFC 8391's SHA-2/256 sets).\n re: /\\bXMSS-(?:SHA2|SHAKE(?:256)?)_\\d+_(?:192|256)\\b/g,\n meta: {\n id: \"stateful-hbs-xmss-param\",\n title: \"XMSS parameter set (stateful hash-based signature)\",\n description: \"XMSS one-time-signature parameter string (SP 800-208)\",\n category: \"signature\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_RISKY_PRIMITIVE,\n message:\n \"XMSS parameter set — NIST-approved (SP 800-208) but STATEFUL: reusing a one-time key index is catastrophic.\",\n remediation: STATEFUL_HBS_REMEDIATION,\n },\n },\n {\n // XMSSMT (multi-tree XMSS) parameter set, e.g. XMSSMT-SHA2_20/2_256 or the\n // SP 800-208 SHAKE256 variant XMSSMT-SHAKE256_20/2_256.\n re: /\\bXMSSMT-(?:SHA2|SHAKE(?:256)?)_\\d+\\b/g,\n meta: {\n id: \"stateful-hbs-xmssmt-param\",\n title: \"XMSSMT parameter set (stateful hash-based signature)\",\n description: \"XMSSMT (multi-tree XMSS) parameter string (SP 800-208)\",\n category: \"signature\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_RISKY_PRIMITIVE,\n message:\n \"XMSSMT parameter set — NIST-approved (SP 800-208) but STATEFUL: never reuse a one-time key index.\",\n remediation: STATEFUL_HBS_REMEDIATION,\n },\n },\n {\n // XMSS keypair generation, e.g. xmss_keypair(...) (liboqs / xmss reference).\n re: /\\bxmss_keypair\\b/g,\n meta: {\n id: \"stateful-hbs-xmss-keypair\",\n title: \"XMSS keypair generation (stateful hash-based signature)\",\n description: \"XMSS keypair-generation call (SP 800-208)\",\n category: \"signature\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_RISKY_PRIMITIVE,\n message:\n \"XMSS keypair generation — NIST-approved (SP 800-208) but STATEFUL: the signer must never reuse a one-time key index.\",\n remediation: STATEFUL_HBS_REMEDIATION,\n },\n },\n];\n\n/** Detects stateful hash-based signature (SP 800-208) usage in arbitrary files. */\nexport const statefulHbsDetector: Detector = {\n id: \"stateful-hbs\",\n description:\n \"Stateful hash-based signatures (NIST SP 800-208: LMS / HSS / XMSS / XMSSMT) in any file\",\n scope: \"config\",\n language: \"any\",\n rules: HBS_RULES.map((r) => r.meta),\n // Applies to every text file; the walker already filters out binaries.\n appliesTo: () => true,\n detect({ file, content }): Finding[] {\n const findings: Finding[] = [];\n for (const rule of HBS_RULES) {\n eachMatch(rule.re, content, (m) => {\n findings.push(\n findingFromRule(rule.meta, {\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,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config detector: classical supply-chain / artifact signing beyond the cosign +
|
|
3
|
+
* GPG cases the `cicd` detector covers — Docker Content Trust (Notary v1 / TUF),
|
|
4
|
+
* CNCF Notation, and in-toto. These sign container images, OCI artifacts, and
|
|
5
|
+
* build provenance with classical keys (ECDSA / RSA / Ed25519). Like all signing,
|
|
6
|
+
* this is the signature-side analogue of harvest-now-decrypt-later: a signature
|
|
7
|
+
* produced today is forgeable once a CRQC exists, and the signed artifact keeps
|
|
8
|
+
* verifying against that classical key for years — so these are `hndl:false` but
|
|
9
|
+
* real quantum-migration debt.
|
|
10
|
+
*
|
|
11
|
+
* Gated to CI pipeline files, Dockerfiles, and shell scripts, over comment-masked
|
|
12
|
+
* content, and keyed on distinctive command/env tokens to keep false positives low.
|
|
13
|
+
*/
|
|
14
|
+
import type { Detector } from "../types.js";
|
|
15
|
+
/** Detects classical Docker Content Trust / Notation / in-toto signing. */
|
|
16
|
+
export declare const supplyChainDetector: Detector;
|
|
17
|
+
//# sourceMappingURL=supply-chain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supply-chain.d.ts","sourceRoot":"","sources":["../../src/detectors/supply-chain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAqB,MAAM,aAAa,CAAC;AAiF/D,2EAA2E;AAC3E,eAAO,MAAM,mBAAmB,EAAE,QAqBjC,CAAC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { eachMatch, findingFromRule, maskCommentLines } from "../detect-utils.js";
|
|
2
|
+
import { CWE_BROKEN_CRYPTO } from "../cwe.js";
|
|
3
|
+
/** CI pipeline files, Dockerfiles, and shell scripts — where signing runs. */
|
|
4
|
+
function isSigningContext(filePath) {
|
|
5
|
+
const lower = filePath.toLowerCase();
|
|
6
|
+
const base = lower.split("/").pop() ?? lower;
|
|
7
|
+
return ((lower.includes(".github/workflows/") && (lower.endsWith(".yml") || lower.endsWith(".yaml"))) ||
|
|
8
|
+
base === ".gitlab-ci.yml" ||
|
|
9
|
+
lower.endsWith(".gitlab-ci.yml") ||
|
|
10
|
+
base === "jenkinsfile" ||
|
|
11
|
+
lower.endsWith(".jenkinsfile") ||
|
|
12
|
+
base === "dockerfile" ||
|
|
13
|
+
base.startsWith("dockerfile.") ||
|
|
14
|
+
lower.endsWith(".dockerfile") ||
|
|
15
|
+
lower.endsWith(".sh") ||
|
|
16
|
+
lower.endsWith(".bash"));
|
|
17
|
+
}
|
|
18
|
+
const SC_RULES = [
|
|
19
|
+
{
|
|
20
|
+
re: /\bDOCKER_CONTENT_TRUST\s*[:=]\s*["']?1\b|\bdocker\s+trust\s+sign\b/g,
|
|
21
|
+
meta: {
|
|
22
|
+
id: "sc-docker-content-trust",
|
|
23
|
+
title: "Docker Content Trust signing (Notary v1)",
|
|
24
|
+
description: "Docker Content Trust / docker trust sign — Notary v1 (TUF) classical keys",
|
|
25
|
+
category: "signature",
|
|
26
|
+
severity: "medium",
|
|
27
|
+
confidence: "high",
|
|
28
|
+
algorithm: "ECDSA",
|
|
29
|
+
hndl: false,
|
|
30
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
31
|
+
message: "Docker Content Trust signs images with Notary v1 (TUF) classical keys (ECDSA/Ed25519); signatures are forgeable once a CRQC exists.",
|
|
32
|
+
remediation: "Track sigstore/Notary v2 (Notation) PQC roadmap; plan hybrid image signing.",
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
re: /\bnotation\s+(?:sign|key\s+generate|cert\s+generate)\b/g,
|
|
37
|
+
meta: {
|
|
38
|
+
id: "sc-notation-sign",
|
|
39
|
+
title: "Notation artifact signing",
|
|
40
|
+
description: "CNCF Notation signing of OCI artifacts with classical keys",
|
|
41
|
+
category: "signature",
|
|
42
|
+
severity: "medium",
|
|
43
|
+
confidence: "high",
|
|
44
|
+
algorithm: "RSA",
|
|
45
|
+
hndl: false,
|
|
46
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
47
|
+
message: "Notation signs OCI artifacts with a classical key (RSA/ECDSA); signatures are forgeable once a CRQC exists.",
|
|
48
|
+
remediation: "Track Notation's PQC signature support (ML-DSA) and plan migration.",
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
re: /\bin[-_]toto[-_]?run\b|\bin-toto\b/g,
|
|
53
|
+
meta: {
|
|
54
|
+
id: "sc-in-toto",
|
|
55
|
+
title: "in-toto supply-chain signing",
|
|
56
|
+
description: "in-toto build provenance signed with classical keys",
|
|
57
|
+
category: "signature",
|
|
58
|
+
severity: "medium",
|
|
59
|
+
confidence: "high",
|
|
60
|
+
algorithm: "RSA",
|
|
61
|
+
hndl: false,
|
|
62
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
63
|
+
message: "in-toto signs build provenance with a classical key (RSA/Ed25519); the attestation is forgeable once a CRQC exists.",
|
|
64
|
+
remediation: "Track in-toto/DSSE PQC signature support and plan migration.",
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
];
|
|
68
|
+
/** Detects classical Docker Content Trust / Notation / in-toto signing. */
|
|
69
|
+
export const supplyChainDetector = {
|
|
70
|
+
id: "supply-chain-signing",
|
|
71
|
+
description: "Classical container/artifact signing (Docker Content Trust, Notation, in-toto)",
|
|
72
|
+
scope: "config",
|
|
73
|
+
language: "any",
|
|
74
|
+
rules: SC_RULES.map((r) => r.meta),
|
|
75
|
+
appliesTo: isSigningContext,
|
|
76
|
+
detect({ file, content }) {
|
|
77
|
+
// `#` covers YAML/Dockerfile/shell; `//` covers Jenkinsfile (Groovy), which has no
|
|
78
|
+
// extension so it is never centrally comment-stripped.
|
|
79
|
+
const scan = maskCommentLines(content, ["#", "//"]);
|
|
80
|
+
const findings = [];
|
|
81
|
+
for (const rule of SC_RULES) {
|
|
82
|
+
eachMatch(rule.re, scan, (m) => {
|
|
83
|
+
findings.push(findingFromRule(rule.meta, { file, content, index: m.index, matchLength: m[0].length }));
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
return findings;
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
//# sourceMappingURL=supply-chain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supply-chain.js","sourceRoot":"","sources":["../../src/detectors/supply-chain.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAClF,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAE9C,8EAA8E;AAC9E,SAAS,gBAAgB,CAAC,QAAgB;IACxC,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IACrC,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,KAAK,CAAC;IAC7C,OAAO,CACL,CAAC,KAAK,CAAC,QAAQ,CAAC,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;QAC7F,IAAI,KAAK,gBAAgB;QACzB,KAAK,CAAC,QAAQ,CAAC,gBAAgB,CAAC;QAChC,IAAI,KAAK,aAAa;QACtB,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC;QAC9B,IAAI,KAAK,YAAY;QACrB,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC;QAC9B,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC;QAC7B,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC;QACrB,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CACxB,CAAC;AACJ,CAAC;AAOD,MAAM,QAAQ,GAAa;IACzB;QACE,EAAE,EAAE,qEAAqE;QACzE,IAAI,EAAE;YACJ,EAAE,EAAE,yBAAyB;YAC7B,KAAK,EAAE,0CAA0C;YACjD,WAAW,EAAE,2EAA2E;YACxF,QAAQ,EAAE,WAAW;YACrB,QAAQ,EAAE,QAAQ;YAClB,UAAU,EAAE,MAAM;YAClB,SAAS,EAAE,OAAO;YAClB,IAAI,EAAE,KAAK;YACX,GAAG,EAAE,iBAAiB;YACtB,OAAO,EACL,qIAAqI;YACvI,WAAW,EAAE,6EAA6E;SAC3F;KACF;IACD;QACE,EAAE,EAAE,yDAAyD;QAC7D,IAAI,EAAE;YACJ,EAAE,EAAE,kBAAkB;YACtB,KAAK,EAAE,2BAA2B;YAClC,WAAW,EAAE,4DAA4D;YACzE,QAAQ,EAAE,WAAW;YACrB,QAAQ,EAAE,QAAQ;YAClB,UAAU,EAAE,MAAM;YAClB,SAAS,EAAE,KAAK;YAChB,IAAI,EAAE,KAAK;YACX,GAAG,EAAE,iBAAiB;YACtB,OAAO,EACL,6GAA6G;YAC/G,WAAW,EAAE,qEAAqE;SACnF;KACF;IACD;QACE,EAAE,EAAE,qCAAqC;QACzC,IAAI,EAAE;YACJ,EAAE,EAAE,YAAY;YAChB,KAAK,EAAE,8BAA8B;YACrC,WAAW,EAAE,qDAAqD;YAClE,QAAQ,EAAE,WAAW;YACrB,QAAQ,EAAE,QAAQ;YAClB,UAAU,EAAE,MAAM;YAClB,SAAS,EAAE,KAAK;YAChB,IAAI,EAAE,KAAK;YACX,GAAG,EAAE,iBAAiB;YACtB,OAAO,EACL,qHAAqH;YACvH,WAAW,EAAE,8DAA8D;SAC5E;KACF;CACF,CAAC;AAEF,2EAA2E;AAC3E,MAAM,CAAC,MAAM,mBAAmB,GAAa;IAC3C,EAAE,EAAE,sBAAsB;IAC1B,WAAW,EAAE,gFAAgF;IAC7F,KAAK,EAAE,QAAQ;IACf,QAAQ,EAAE,KAAK;IACf,KAAK,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAClC,SAAS,EAAE,gBAAgB;IAC3B,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE;QACtB,mFAAmF;QACnF,uDAAuD;QACvD,MAAM,IAAI,GAAG,gBAAgB,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;QACpD,MAAM,QAAQ,GAAc,EAAE,CAAC;QAC/B,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;YAC5B,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE;gBAC7B,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 supply-chain / artifact signing beyond the cosign +\n * GPG cases the `cicd` detector covers — Docker Content Trust (Notary v1 / TUF),\n * CNCF Notation, and in-toto. These sign container images, OCI artifacts, and\n * build provenance with classical keys (ECDSA / RSA / Ed25519). Like all signing,\n * this is the signature-side analogue of harvest-now-decrypt-later: a signature\n * produced today is forgeable once a CRQC exists, and the signed artifact keeps\n * verifying against that classical key for years — so these are `hndl:false` but\n * real quantum-migration debt.\n *\n * Gated to CI pipeline files, Dockerfiles, and shell scripts, over comment-masked\n * content, and keyed on distinctive command/env tokens to keep false positives low.\n */\nimport type { Detector, Finding, RuleMeta } from \"../types.js\";\nimport { eachMatch, findingFromRule, maskCommentLines } from \"../detect-utils.js\";\nimport { CWE_BROKEN_CRYPTO } from \"../cwe.js\";\n\n/** CI pipeline files, Dockerfiles, and shell scripts — where signing runs. */\nfunction isSigningContext(filePath: string): boolean {\n const lower = filePath.toLowerCase();\n const base = lower.split(\"/\").pop() ?? lower;\n return (\n (lower.includes(\".github/workflows/\") && (lower.endsWith(\".yml\") || lower.endsWith(\".yaml\"))) ||\n base === \".gitlab-ci.yml\" ||\n lower.endsWith(\".gitlab-ci.yml\") ||\n base === \"jenkinsfile\" ||\n lower.endsWith(\".jenkinsfile\") ||\n base === \"dockerfile\" ||\n base.startsWith(\"dockerfile.\") ||\n lower.endsWith(\".dockerfile\") ||\n lower.endsWith(\".sh\") ||\n lower.endsWith(\".bash\")\n );\n}\n\ninterface ScRule {\n re: RegExp;\n meta: RuleMeta;\n}\n\nconst SC_RULES: ScRule[] = [\n {\n re: /\\bDOCKER_CONTENT_TRUST\\s*[:=]\\s*[\"']?1\\b|\\bdocker\\s+trust\\s+sign\\b/g,\n meta: {\n id: \"sc-docker-content-trust\",\n title: \"Docker Content Trust signing (Notary v1)\",\n description: \"Docker Content Trust / docker trust sign — Notary v1 (TUF) classical keys\",\n category: \"signature\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"ECDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Docker Content Trust signs images with Notary v1 (TUF) classical keys (ECDSA/Ed25519); signatures are forgeable once a CRQC exists.\",\n remediation: \"Track sigstore/Notary v2 (Notation) PQC roadmap; plan hybrid image signing.\",\n },\n },\n {\n re: /\\bnotation\\s+(?:sign|key\\s+generate|cert\\s+generate)\\b/g,\n meta: {\n id: \"sc-notation-sign\",\n title: \"Notation artifact signing\",\n description: \"CNCF Notation signing of OCI artifacts with classical keys\",\n category: \"signature\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"RSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Notation signs OCI artifacts with a classical key (RSA/ECDSA); signatures are forgeable once a CRQC exists.\",\n remediation: \"Track Notation's PQC signature support (ML-DSA) and plan migration.\",\n },\n },\n {\n re: /\\bin[-_]toto[-_]?run\\b|\\bin-toto\\b/g,\n meta: {\n id: \"sc-in-toto\",\n title: \"in-toto supply-chain signing\",\n description: \"in-toto build provenance signed with classical keys\",\n category: \"signature\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"RSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"in-toto signs build provenance with a classical key (RSA/Ed25519); the attestation is forgeable once a CRQC exists.\",\n remediation: \"Track in-toto/DSSE PQC signature support and plan migration.\",\n },\n },\n];\n\n/** Detects classical Docker Content Trust / Notation / in-toto signing. */\nexport const supplyChainDetector: Detector = {\n id: \"supply-chain-signing\",\n description: \"Classical container/artifact signing (Docker Content Trust, Notation, in-toto)\",\n scope: \"config\",\n language: \"any\",\n rules: SC_RULES.map((r) => r.meta),\n appliesTo: isSigningContext,\n detect({ file, content }): Finding[] {\n // `#` covers YAML/Dockerfile/shell; `//` covers Jenkinsfile (Groovy), which has no\n // extension so it is never centrally comment-stripped.\n const scan = maskCommentLines(content, [\"#\", \"//\"]);\n const findings: Finding[] = [];\n for (const rule of SC_RULES) {\n eachMatch(rule.re, scan, (m) => {\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"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Source detector for classical asymmetric cryptography in Swift (Apple platforms) —
|
|
3
|
+
* Apple CryptoKit and the older Security framework (`SecKey*`). Lexical, same strategy
|
|
4
|
+
* as the other language packs; the API names are distinctive enough to keep the
|
|
5
|
+
* false-positive risk low. Comment/string suppression is handled centrally
|
|
6
|
+
* (`.swift` is a C-style comment language).
|
|
7
|
+
*
|
|
8
|
+
* CryptoKit:
|
|
9
|
+
* - `P256|P384|P521.Signing.PrivateKey` → ECDSA signature (hndl:false)
|
|
10
|
+
* - `P256|P384|P521.KeyAgreement.PrivateKey` → ECDH key agreement (hndl:true)
|
|
11
|
+
* - `Curve25519.Signing.PrivateKey` → Ed25519 signature (hndl:false)
|
|
12
|
+
* - `Curve25519.KeyAgreement.PrivateKey` → X25519 key agreement (hndl:true)
|
|
13
|
+
* (`SecureEnclave.P256.…` forms are covered by the same P-curve regexes.)
|
|
14
|
+
*
|
|
15
|
+
* Security framework:
|
|
16
|
+
* - `SecKeyCreateRandomKey` with `kSecAttrKeyTypeRSA` → RSA
|
|
17
|
+
* - … with `kSecAttrKeyTypeEC` / `kSecAttrKeyTypeECSECPrimeRandom` → EC
|
|
18
|
+
*/
|
|
19
|
+
import type { Detector } from "../types.js";
|
|
20
|
+
/** Detects classical asymmetric crypto in Swift (CryptoKit + Security framework). */
|
|
21
|
+
export declare const swiftDetector: Detector;
|
|
22
|
+
//# sourceMappingURL=swift.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"swift.d.ts","sourceRoot":"","sources":["../../src/detectors/swift.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAqB,MAAM,aAAa,CAAC;AAmG/D,qFAAqF;AACrF,eAAO,MAAM,aAAa,EAAE,QA8B3B,CAAC"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { SWIFT_EXTENSIONS, eachMatch, findingFromRule, hasExtension } from "../detect-utils.js";
|
|
2
|
+
import { CWE_BROKEN_CRYPTO } from "../cwe.js";
|
|
3
|
+
// CryptoKit P-curve keys, split by usage (Signing vs KeyAgreement). `SecureEnclave.`
|
|
4
|
+
// may prefix the P-curve type, so it is allowed optionally.
|
|
5
|
+
const RE_SWIFT_P_SIGN = /\b(?:SecureEnclave\.)?P(?:256|384|521)\.Signing\.PrivateKey\b/g;
|
|
6
|
+
const RE_SWIFT_P_KEX = /\b(?:SecureEnclave\.)?P(?:256|384|521)\.KeyAgreement\.PrivateKey\b/g;
|
|
7
|
+
// CryptoKit Curve25519: Signing = Ed25519 (EdDSA); KeyAgreement = X25519.
|
|
8
|
+
const RE_SWIFT_ED25519 = /\bCurve25519\.Signing\.PrivateKey\b/g;
|
|
9
|
+
const RE_SWIFT_X25519 = /\bCurve25519\.KeyAgreement\.PrivateKey\b/g;
|
|
10
|
+
// Security framework key-type attributes (used with SecKeyCreateRandomKey).
|
|
11
|
+
const RE_SWIFT_SEC_RSA = /\bkSecAttrKeyTypeRSA\b/g;
|
|
12
|
+
const RE_SWIFT_SEC_EC = /\bkSecAttrKeyType(?:EC|ECSECPrimeRandom)\b/g;
|
|
13
|
+
const RULE_SWIFT_ECDSA = {
|
|
14
|
+
id: "swift-ecdsa",
|
|
15
|
+
title: "Swift CryptoKit ECDSA signing key",
|
|
16
|
+
description: "CryptoKit P256/P384/P521 Signing.PrivateKey",
|
|
17
|
+
category: "signature",
|
|
18
|
+
severity: "high",
|
|
19
|
+
confidence: "high",
|
|
20
|
+
algorithm: "ECDSA",
|
|
21
|
+
hndl: false,
|
|
22
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
23
|
+
message: "CryptoKit P-curve ECDSA signing (Swift) is forgeable by a quantum attacker.",
|
|
24
|
+
remediation: "ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205).",
|
|
25
|
+
};
|
|
26
|
+
const RULE_SWIFT_ECDH = {
|
|
27
|
+
id: "swift-ecdh",
|
|
28
|
+
title: "Swift CryptoKit ECDH key agreement",
|
|
29
|
+
description: "CryptoKit P256/P384/P521 KeyAgreement.PrivateKey",
|
|
30
|
+
category: "key-exchange",
|
|
31
|
+
severity: "high",
|
|
32
|
+
confidence: "high",
|
|
33
|
+
algorithm: "ECDH",
|
|
34
|
+
hndl: true,
|
|
35
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
36
|
+
message: "CryptoKit P-curve ECDH key agreement (Swift) is harvest-now-decrypt-later exposed.",
|
|
37
|
+
remediation: "Migrate key agreement to hybrid X25519MLKEM768 (ML-KEM-768).",
|
|
38
|
+
};
|
|
39
|
+
const RULE_SWIFT_ED25519 = {
|
|
40
|
+
id: "swift-ed25519",
|
|
41
|
+
title: "Swift CryptoKit Ed25519 signing key",
|
|
42
|
+
description: "CryptoKit Curve25519.Signing.PrivateKey (Ed25519)",
|
|
43
|
+
category: "signature",
|
|
44
|
+
// `low`, aligned with Ed25519 in every other source pack (go/rust/ruby/python/node)
|
|
45
|
+
// — the same primitive must not flip CI exit codes based on which language wrote it.
|
|
46
|
+
severity: "low",
|
|
47
|
+
confidence: "high",
|
|
48
|
+
algorithm: "EdDSA",
|
|
49
|
+
hndl: false,
|
|
50
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
51
|
+
message: "CryptoKit Ed25519 signing (Swift) is classical and forgeable by a quantum attacker.",
|
|
52
|
+
remediation: "ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205).",
|
|
53
|
+
};
|
|
54
|
+
const RULE_SWIFT_X25519 = {
|
|
55
|
+
id: "swift-x25519",
|
|
56
|
+
title: "Swift CryptoKit X25519 key agreement",
|
|
57
|
+
description: "CryptoKit Curve25519.KeyAgreement.PrivateKey (X25519)",
|
|
58
|
+
category: "key-exchange",
|
|
59
|
+
severity: "medium",
|
|
60
|
+
confidence: "high",
|
|
61
|
+
algorithm: "X25519",
|
|
62
|
+
hndl: true,
|
|
63
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
64
|
+
message: "CryptoKit X25519 key agreement (Swift) is classical and harvest-now-decrypt-later exposed.",
|
|
65
|
+
remediation: "Migrate key agreement to hybrid X25519MLKEM768 (ML-KEM-768).",
|
|
66
|
+
};
|
|
67
|
+
const RULE_SWIFT_RSA = {
|
|
68
|
+
id: "swift-rsa",
|
|
69
|
+
title: "Swift Security-framework RSA key",
|
|
70
|
+
description: "SecKeyCreateRandomKey with kSecAttrKeyTypeRSA",
|
|
71
|
+
category: "kem",
|
|
72
|
+
severity: "high",
|
|
73
|
+
confidence: "high",
|
|
74
|
+
algorithm: "RSA",
|
|
75
|
+
hndl: true,
|
|
76
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
77
|
+
message: "Security-framework RSA key (Swift) is classical and not quantum-safe.",
|
|
78
|
+
remediation: "Plan migration to PQC (ML-KEM-768 for encryption, ML-DSA-65 for signatures).",
|
|
79
|
+
};
|
|
80
|
+
const RULE_SWIFT_SEC_EC = {
|
|
81
|
+
id: "swift-sec-ec",
|
|
82
|
+
title: "Swift Security-framework EC key",
|
|
83
|
+
description: "SecKeyCreateRandomKey with kSecAttrKeyTypeEC",
|
|
84
|
+
category: "key-exchange",
|
|
85
|
+
severity: "high",
|
|
86
|
+
confidence: "high",
|
|
87
|
+
algorithm: "ECDH",
|
|
88
|
+
hndl: true,
|
|
89
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
90
|
+
message: "Security-framework EC key (Swift); EC keys feed ECDSA signatures and ECDH key agreement (the ECDH path is harvest-now-decrypt-later exposed).",
|
|
91
|
+
remediation: "For key agreement: hybrid X25519MLKEM768 (ML-KEM-768). For signatures: ML-DSA-65 (FIPS 204).",
|
|
92
|
+
};
|
|
93
|
+
/** Detects classical asymmetric crypto in Swift (CryptoKit + Security framework). */
|
|
94
|
+
export const swiftDetector = {
|
|
95
|
+
id: "swift-crypto",
|
|
96
|
+
description: "Classical asymmetric crypto in Swift (CryptoKit, Security framework)",
|
|
97
|
+
scope: "source",
|
|
98
|
+
language: "swift",
|
|
99
|
+
rules: [
|
|
100
|
+
RULE_SWIFT_ECDSA,
|
|
101
|
+
RULE_SWIFT_ECDH,
|
|
102
|
+
RULE_SWIFT_ED25519,
|
|
103
|
+
RULE_SWIFT_X25519,
|
|
104
|
+
RULE_SWIFT_RSA,
|
|
105
|
+
RULE_SWIFT_SEC_EC,
|
|
106
|
+
],
|
|
107
|
+
appliesTo: (f) => hasExtension(f, SWIFT_EXTENSIONS),
|
|
108
|
+
detect({ file, content }) {
|
|
109
|
+
const findings = [];
|
|
110
|
+
const add = (re, rule) => eachMatch(re, content, (m) => findings.push(findingFromRule(rule, { file, content, index: m.index, matchLength: m[0].length })));
|
|
111
|
+
add(RE_SWIFT_P_SIGN, RULE_SWIFT_ECDSA);
|
|
112
|
+
add(RE_SWIFT_P_KEX, RULE_SWIFT_ECDH);
|
|
113
|
+
add(RE_SWIFT_ED25519, RULE_SWIFT_ED25519);
|
|
114
|
+
add(RE_SWIFT_X25519, RULE_SWIFT_X25519);
|
|
115
|
+
add(RE_SWIFT_SEC_RSA, RULE_SWIFT_RSA);
|
|
116
|
+
add(RE_SWIFT_SEC_EC, RULE_SWIFT_SEC_EC);
|
|
117
|
+
return findings;
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
//# sourceMappingURL=swift.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"swift.js","sourceRoot":"","sources":["../../src/detectors/swift.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Source detector for classical asymmetric cryptography in Swift (Apple platforms) —\n * Apple CryptoKit and the older Security framework (`SecKey*`). Lexical, same strategy\n * as the other language packs; the API names are distinctive enough to keep the\n * false-positive risk low. Comment/string suppression is handled centrally\n * (`.swift` is a C-style comment language).\n *\n * CryptoKit:\n * - `P256|P384|P521.Signing.PrivateKey` → ECDSA signature (hndl:false)\n * - `P256|P384|P521.KeyAgreement.PrivateKey` → ECDH key agreement (hndl:true)\n * - `Curve25519.Signing.PrivateKey` → Ed25519 signature (hndl:false)\n * - `Curve25519.KeyAgreement.PrivateKey` → X25519 key agreement (hndl:true)\n * (`SecureEnclave.P256.…` forms are covered by the same P-curve regexes.)\n *\n * Security framework:\n * - `SecKeyCreateRandomKey` with `kSecAttrKeyTypeRSA` → RSA\n * - … with `kSecAttrKeyTypeEC` / `kSecAttrKeyTypeECSECPrimeRandom` → EC\n */\nimport type { Detector, Finding, RuleMeta } from \"../types.js\";\nimport { SWIFT_EXTENSIONS, eachMatch, findingFromRule, hasExtension } from \"../detect-utils.js\";\nimport { CWE_BROKEN_CRYPTO } from \"../cwe.js\";\n\n// CryptoKit P-curve keys, split by usage (Signing vs KeyAgreement). `SecureEnclave.`\n// may prefix the P-curve type, so it is allowed optionally.\nconst RE_SWIFT_P_SIGN = /\\b(?:SecureEnclave\\.)?P(?:256|384|521)\\.Signing\\.PrivateKey\\b/g;\nconst RE_SWIFT_P_KEX = /\\b(?:SecureEnclave\\.)?P(?:256|384|521)\\.KeyAgreement\\.PrivateKey\\b/g;\n// CryptoKit Curve25519: Signing = Ed25519 (EdDSA); KeyAgreement = X25519.\nconst RE_SWIFT_ED25519 = /\\bCurve25519\\.Signing\\.PrivateKey\\b/g;\nconst RE_SWIFT_X25519 = /\\bCurve25519\\.KeyAgreement\\.PrivateKey\\b/g;\n// Security framework key-type attributes (used with SecKeyCreateRandomKey).\nconst RE_SWIFT_SEC_RSA = /\\bkSecAttrKeyTypeRSA\\b/g;\nconst RE_SWIFT_SEC_EC = /\\bkSecAttrKeyType(?:EC|ECSECPrimeRandom)\\b/g;\n\nconst RULE_SWIFT_ECDSA: RuleMeta = {\n id: \"swift-ecdsa\",\n title: \"Swift CryptoKit ECDSA signing key\",\n description: \"CryptoKit P256/P384/P521 Signing.PrivateKey\",\n category: \"signature\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"ECDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"CryptoKit P-curve ECDSA signing (Swift) is forgeable by a quantum attacker.\",\n remediation: \"ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205).\",\n};\nconst RULE_SWIFT_ECDH: RuleMeta = {\n id: \"swift-ecdh\",\n title: \"Swift CryptoKit ECDH key agreement\",\n description: \"CryptoKit P256/P384/P521 KeyAgreement.PrivateKey\",\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"ECDH\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"CryptoKit P-curve ECDH key agreement (Swift) is harvest-now-decrypt-later exposed.\",\n remediation: \"Migrate key agreement to hybrid X25519MLKEM768 (ML-KEM-768).\",\n};\nconst RULE_SWIFT_ED25519: RuleMeta = {\n id: \"swift-ed25519\",\n title: \"Swift CryptoKit Ed25519 signing key\",\n description: \"CryptoKit Curve25519.Signing.PrivateKey (Ed25519)\",\n category: \"signature\",\n // `low`, aligned with Ed25519 in every other source pack (go/rust/ruby/python/node)\n // — the same primitive must not flip CI exit codes based on which language wrote it.\n severity: \"low\",\n confidence: \"high\",\n algorithm: \"EdDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"CryptoKit Ed25519 signing (Swift) is classical and forgeable by a quantum attacker.\",\n remediation: \"ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205).\",\n};\nconst RULE_SWIFT_X25519: RuleMeta = {\n id: \"swift-x25519\",\n title: \"Swift CryptoKit X25519 key agreement\",\n description: \"CryptoKit Curve25519.KeyAgreement.PrivateKey (X25519)\",\n category: \"key-exchange\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"X25519\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"CryptoKit X25519 key agreement (Swift) is classical and harvest-now-decrypt-later exposed.\",\n remediation: \"Migrate key agreement to hybrid X25519MLKEM768 (ML-KEM-768).\",\n};\nconst RULE_SWIFT_RSA: RuleMeta = {\n id: \"swift-rsa\",\n title: \"Swift Security-framework RSA key\",\n description: \"SecKeyCreateRandomKey with kSecAttrKeyTypeRSA\",\n category: \"kem\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"RSA\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"Security-framework RSA key (Swift) is classical and not quantum-safe.\",\n remediation: \"Plan migration to PQC (ML-KEM-768 for encryption, ML-DSA-65 for signatures).\",\n};\nconst RULE_SWIFT_SEC_EC: RuleMeta = {\n id: \"swift-sec-ec\",\n title: \"Swift Security-framework EC key\",\n description: \"SecKeyCreateRandomKey with kSecAttrKeyTypeEC\",\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"ECDH\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Security-framework EC key (Swift); EC keys feed 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};\n\n/** Detects classical asymmetric crypto in Swift (CryptoKit + Security framework). */\nexport const swiftDetector: Detector = {\n id: \"swift-crypto\",\n description: \"Classical asymmetric crypto in Swift (CryptoKit, Security framework)\",\n scope: \"source\",\n language: \"swift\",\n rules: [\n RULE_SWIFT_ECDSA,\n RULE_SWIFT_ECDH,\n RULE_SWIFT_ED25519,\n RULE_SWIFT_X25519,\n RULE_SWIFT_RSA,\n RULE_SWIFT_SEC_EC,\n ],\n appliesTo: (f) => hasExtension(f, SWIFT_EXTENSIONS),\n detect({ file, content }): Finding[] {\n const findings: Finding[] = [];\n const add = (re: RegExp, rule: RuleMeta) =>\n eachMatch(re, content, (m) =>\n findings.push(\n findingFromRule(rule, { file, content, index: m.index, matchLength: m[0].length }),\n ),\n );\n add(RE_SWIFT_P_SIGN, RULE_SWIFT_ECDSA);\n add(RE_SWIFT_P_KEX, RULE_SWIFT_ECDH);\n add(RE_SWIFT_ED25519, RULE_SWIFT_ED25519);\n add(RE_SWIFT_X25519, RULE_SWIFT_X25519);\n add(RE_SWIFT_SEC_RSA, RULE_SWIFT_RSA);\n add(RE_SWIFT_SEC_EC, RULE_SWIFT_SEC_EC);\n return findings;\n },\n};\n"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IaC detector: classical asymmetric cryptography provisioned by Terraform /
|
|
3
|
+
* OpenTofu (`.tf`, `.tf.json`). Infrastructure-as-code mints real keys and CMKs
|
|
4
|
+
* that never appear in application source, so this is a distinct surface from the
|
|
5
|
+
* language packs.
|
|
6
|
+
*
|
|
7
|
+
* Covered:
|
|
8
|
+
* - hashicorp/tls `tls_private_key`: `algorithm = "RSA" | "ECDSA"`
|
|
9
|
+
* - Google Cloud KMS `version_template`: `algorithm = "RSA_SIGN_…" | "EC_SIGN_…"`
|
|
10
|
+
* - AWS KMS `aws_kms_key`: `customer_master_key_spec = "RSA_…" | "ECC_…"`
|
|
11
|
+
* - Azure `azurerm_key_vault_key`: `key_type = "RSA" | "EC"` (+ HSM variants)
|
|
12
|
+
*
|
|
13
|
+
* The HCL assignment forms (`algorithm = "…"`, `customer_master_key_spec = "…"`,
|
|
14
|
+
* `key_type = "…"`) are specific enough inside `.tf` files that the false-positive
|
|
15
|
+
* risk is low. EC keys are classified conservatively as key-agreement-capable
|
|
16
|
+
* (hndl:true) since a provisioned EC key can feed ECDH.
|
|
17
|
+
*/
|
|
18
|
+
import type { Detector } from "../types.js";
|
|
19
|
+
/** Detects classical asymmetric crypto provisioned in Terraform / OpenTofu. */
|
|
20
|
+
export declare const terraformDetector: Detector;
|
|
21
|
+
//# sourceMappingURL=terraform.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terraform.d.ts","sourceRoot":"","sources":["../../src/detectors/terraform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAqB,MAAM,aAAa,CAAC;AAqI/D,+EAA+E;AAC/E,eAAO,MAAM,iBAAiB,EAAE,QAoC/B,CAAC"}
|