@quantakrypto/core 0.5.0 → 0.6.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/dist/crypto-agility.d.ts +158 -0
- package/dist/crypto-agility.d.ts.map +1 -0
- package/dist/crypto-agility.js +285 -0
- package/dist/crypto-agility.js.map +1 -0
- package/dist/dependencies.d.ts.map +1 -1
- package/dist/dependencies.js +180 -18
- package/dist/dependencies.js.map +1 -1
- package/dist/detectors/source.d.ts.map +1 -1
- package/dist/detectors/source.js +52 -0
- package/dist/detectors/source.js.map +1 -1
- package/dist/hndl.d.ts +241 -0
- package/dist/hndl.d.ts.map +1 -0
- package/dist/hndl.js +752 -0
- package/dist/hndl.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/parallel.d.ts.map +1 -1
- package/dist/parallel.js +22 -23
- package/dist/parallel.js.map +1 -1
- package/dist/report.d.ts +8 -0
- package/dist/report.d.ts.map +1 -1
- package/dist/report.js +75 -19
- package/dist/report.js.map +1 -1
- package/dist/types.d.ts +1 -1
- 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/walk.d.ts +31 -1
- package/dist/walk.d.ts.map +1 -1
- package/dist/walk.js +30 -9
- package/dist/walk.js.map +1 -1
- package/package.json +1 -1
- package/src/crypto-agility.ts +407 -0
- package/src/dependencies.ts +182 -16
- package/src/detectors/source.ts +62 -0
- package/src/hndl.ts +1012 -0
- package/src/index.ts +52 -0
- package/src/parallel.ts +21 -20
- package/src/report.ts +84 -19
- package/src/types.ts +9 -1
- package/src/version.ts +1 -1
- package/src/walk.ts +47 -10
package/src/dependencies.ts
CHANGED
|
@@ -401,6 +401,14 @@ export const vulnerableDependencies: VulnerableDependency[] = [
|
|
|
401
401
|
algorithms: ["X25519", "EdDSA"],
|
|
402
402
|
severity: "low",
|
|
403
403
|
},
|
|
404
|
+
{
|
|
405
|
+
name: "tink",
|
|
406
|
+
ecosystem: "pypi",
|
|
407
|
+
reason:
|
|
408
|
+
"Google Tink (Python) — classical RSA/ECDSA/Ed25519 signatures and ECIES hybrid encryption.",
|
|
409
|
+
algorithms: ["RSA", "ECDSA", "EdDSA", "ECIES"],
|
|
410
|
+
severity: "high",
|
|
411
|
+
},
|
|
404
412
|
|
|
405
413
|
// --- crates.io (Rust) ---
|
|
406
414
|
{
|
|
@@ -513,6 +521,21 @@ export const vulnerableDependencies: VulnerableDependency[] = [
|
|
|
513
521
|
algorithms: ["ECDSA", "ECDH"],
|
|
514
522
|
severity: "medium",
|
|
515
523
|
},
|
|
524
|
+
{
|
|
525
|
+
name: "github.com/tink-crypto/tink-go/v2",
|
|
526
|
+
ecosystem: "go",
|
|
527
|
+
reason:
|
|
528
|
+
"Google Tink (Go) — classical RSA/ECDSA/Ed25519 signatures and ECIES hybrid encryption.",
|
|
529
|
+
algorithms: ["RSA", "ECDSA", "EdDSA", "ECIES"],
|
|
530
|
+
severity: "high",
|
|
531
|
+
},
|
|
532
|
+
{
|
|
533
|
+
name: "github.com/google/tink/go",
|
|
534
|
+
ecosystem: "go",
|
|
535
|
+
reason: "Google Tink (legacy Go module) — classical RSA/ECDSA/Ed25519 and ECIES hybrid.",
|
|
536
|
+
algorithms: ["RSA", "ECDSA", "EdDSA", "ECIES"],
|
|
537
|
+
severity: "high",
|
|
538
|
+
},
|
|
516
539
|
|
|
517
540
|
// --- Maven (Java) ---
|
|
518
541
|
{
|
|
@@ -559,6 +582,14 @@ export const vulnerableDependencies: VulnerableDependency[] = [
|
|
|
559
582
|
severity: "medium",
|
|
560
583
|
hndl: false,
|
|
561
584
|
},
|
|
585
|
+
{
|
|
586
|
+
name: "tink",
|
|
587
|
+
ecosystem: "maven",
|
|
588
|
+
reason:
|
|
589
|
+
"Google Tink (com.google.crypto.tink) — classical RSA/ECDSA/Ed25519 signatures and ECIES hybrid encryption.",
|
|
590
|
+
algorithms: ["RSA", "ECDSA", "EdDSA", "ECIES"],
|
|
591
|
+
severity: "high",
|
|
592
|
+
},
|
|
562
593
|
|
|
563
594
|
// --- RubyGems ---
|
|
564
595
|
{
|
|
@@ -623,14 +654,83 @@ export const vulnerableDependencies: VulnerableDependency[] = [
|
|
|
623
654
|
severity: "medium",
|
|
624
655
|
hndl: false,
|
|
625
656
|
},
|
|
657
|
+
|
|
658
|
+
// --- Composer (PHP) ---
|
|
659
|
+
{
|
|
660
|
+
name: "phpseclib/phpseclib",
|
|
661
|
+
ecosystem: "composer",
|
|
662
|
+
reason: "Pure-PHP RSA / DSA / ECDSA / Diffie-Hellman public-key crypto and X.509.",
|
|
663
|
+
algorithms: ["RSA", "DSA", "ECDSA", "DH"],
|
|
664
|
+
severity: "high",
|
|
665
|
+
},
|
|
666
|
+
{
|
|
667
|
+
name: "paragonie/sodium_compat",
|
|
668
|
+
ecosystem: "composer",
|
|
669
|
+
reason: "Pure-PHP libsodium polyfill: X25519 key agreement and Ed25519 signatures.",
|
|
670
|
+
algorithms: ["X25519", "EdDSA"],
|
|
671
|
+
severity: "low",
|
|
672
|
+
},
|
|
673
|
+
{
|
|
674
|
+
name: "paragonie/halite",
|
|
675
|
+
ecosystem: "composer",
|
|
676
|
+
reason: "libsodium wrapper: X25519 key agreement and Ed25519 signatures.",
|
|
677
|
+
algorithms: ["X25519", "EdDSA"],
|
|
678
|
+
severity: "low",
|
|
679
|
+
},
|
|
680
|
+
{
|
|
681
|
+
name: "paragonie/paseto",
|
|
682
|
+
ecosystem: "composer",
|
|
683
|
+
reason: "PASETO public tokens signed with classical Ed25519 (v2/v4) or RSA.",
|
|
684
|
+
algorithms: ["EdDSA", "RSA"],
|
|
685
|
+
severity: "medium",
|
|
686
|
+
hndl: false,
|
|
687
|
+
},
|
|
688
|
+
{
|
|
689
|
+
name: "firebase/php-jwt",
|
|
690
|
+
ecosystem: "composer",
|
|
691
|
+
reason: "PHP JWT signing/verification with classical RS*/ES* algorithms.",
|
|
692
|
+
algorithms: ["RSA", "ECDSA"],
|
|
693
|
+
severity: "medium",
|
|
694
|
+
hndl: false,
|
|
695
|
+
},
|
|
696
|
+
{
|
|
697
|
+
name: "lcobucci/jwt",
|
|
698
|
+
ecosystem: "composer",
|
|
699
|
+
reason: "PHP JWT with classical RSA/ECDSA signature algorithms.",
|
|
700
|
+
algorithms: ["RSA", "ECDSA"],
|
|
701
|
+
severity: "medium",
|
|
702
|
+
hndl: false,
|
|
703
|
+
},
|
|
704
|
+
{
|
|
705
|
+
name: "web-token/jwt-framework",
|
|
706
|
+
ecosystem: "composer",
|
|
707
|
+
reason: "JOSE (JWS/JWE) framework: classical RSA/ECDSA signatures and ECDH-ES key agreement.",
|
|
708
|
+
algorithms: ["RSA", "ECDSA", "ECDH"],
|
|
709
|
+
severity: "medium",
|
|
710
|
+
},
|
|
711
|
+
{
|
|
712
|
+
name: "mdanter/ecc",
|
|
713
|
+
ecosystem: "composer",
|
|
714
|
+
reason: "Pure-PHP elliptic-curve ECDSA signatures and ECDH key agreement.",
|
|
715
|
+
algorithms: ["ECDSA", "ECDH"],
|
|
716
|
+
severity: "high",
|
|
717
|
+
},
|
|
718
|
+
{
|
|
719
|
+
name: "simplito/elliptic-php",
|
|
720
|
+
ecosystem: "composer",
|
|
721
|
+
reason: "secp256k1 / NIST-curve ECDSA and ECDH in pure PHP (blockchain keys).",
|
|
722
|
+
algorithms: ["ECDSA", "ECDH"],
|
|
723
|
+
severity: "high",
|
|
724
|
+
},
|
|
626
725
|
];
|
|
627
726
|
|
|
628
727
|
/**
|
|
629
728
|
* Normalise a package name for matching within its ecosystem. PyPI is
|
|
630
729
|
* case-insensitive and folds runs of `-_.` to a single `-` (PEP 503); cargo /
|
|
631
|
-
* maven / rubygems / nuget are effectively lower-case (NuGet ids are
|
|
632
|
-
* case-insensitively
|
|
633
|
-
* and go paths are
|
|
730
|
+
* maven / rubygems / nuget / composer are effectively lower-case (NuGet ids are
|
|
731
|
+
* matched case-insensitively; Composer `vendor/package` names are lower-cased by
|
|
732
|
+
* Packagist); npm and go module paths are matched verbatim (npm scopes and go
|
|
733
|
+
* paths are case-sensitive).
|
|
634
734
|
*/
|
|
635
735
|
function normalizeName(ecosystem: DependencyEcosystem, name: string): string {
|
|
636
736
|
const n = name.trim();
|
|
@@ -718,6 +818,7 @@ export function manifestEcosystem(file: string): DependencyEcosystem | null {
|
|
|
718
818
|
if (base === "gemfile" || base.endsWith(".gemspec")) return "rubygems";
|
|
719
819
|
if (base === "packages.config" || base === "directory.packages.props" || base.endsWith(".csproj"))
|
|
720
820
|
return "nuget";
|
|
821
|
+
if (base === "composer.json" || base === "composer.lock") return "composer";
|
|
721
822
|
return null;
|
|
722
823
|
}
|
|
723
824
|
|
|
@@ -797,6 +898,20 @@ function candidateNames(ecosystem: DependencyEcosystem, content: string): string
|
|
|
797
898
|
}
|
|
798
899
|
break;
|
|
799
900
|
}
|
|
901
|
+
case "composer": {
|
|
902
|
+
// composer.json `require`/`require-dev` maps are keyed by "vendor/package";
|
|
903
|
+
// composer.lock lists `{"name": "vendor/package", …}`. Both are JSON, so
|
|
904
|
+
// grab every quoted `vendor/package` token (a lower-case vendor + package
|
|
905
|
+
// separated by a single `/`). PHP platform requirements ("php", "ext-*")
|
|
906
|
+
// carry no slash and so are naturally excluded; the curated DB filters the
|
|
907
|
+
// rest, so over-capture is safe.
|
|
908
|
+
for (const m of content.matchAll(
|
|
909
|
+
/["']([a-z0-9](?:[a-z0-9._-]*[a-z0-9])?\/[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?)["']/gi,
|
|
910
|
+
)) {
|
|
911
|
+
names.push(m[1]);
|
|
912
|
+
}
|
|
913
|
+
break;
|
|
914
|
+
}
|
|
800
915
|
case "npm":
|
|
801
916
|
break; // npm uses the JSON path, not this extractor.
|
|
802
917
|
}
|
|
@@ -893,10 +1008,33 @@ export function scanManifest(file: string, content: string): Finding[] {
|
|
|
893
1008
|
return sortByTitle(findings);
|
|
894
1009
|
}
|
|
895
1010
|
|
|
1011
|
+
/**
|
|
1012
|
+
* Resolve an npm `npm:` alias spec to the real package it installs, or null when
|
|
1013
|
+
* the spec is not an alias. An aliased dependency records the alias as the map
|
|
1014
|
+
* KEY and `npm:<real-name>@<range>` as the VALUE (in package.json and in a
|
|
1015
|
+
* lockfile entry's `version`), so the vulnerable package hides behind a benign
|
|
1016
|
+
* alias name. Keeps a leading scope `@` (only a version `@` past index 0 is a
|
|
1017
|
+
* separator): `npm:node-forge@^1` → `node-forge`, `npm:@scope/pkg@1` → `@scope/pkg`.
|
|
1018
|
+
*/
|
|
1019
|
+
function npmAliasTarget(spec: string): string | null {
|
|
1020
|
+
if (!spec.startsWith("npm:")) return null;
|
|
1021
|
+
const rest = spec.slice(4);
|
|
1022
|
+
const at = rest.lastIndexOf("@");
|
|
1023
|
+
const name = at > 0 ? rest.slice(0, at) : rest;
|
|
1024
|
+
return name || null;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
/** Guard against a pathological / hostile lockfile nesting the walk unbounded. */
|
|
1028
|
+
const NPM_TREE_MAX_DEPTH = 64;
|
|
1029
|
+
|
|
896
1030
|
/**
|
|
897
1031
|
* npm manifest scan.
|
|
898
|
-
* - `package.json`: dependencies / devDependencies / peerDependencies / optionalDependencies
|
|
899
|
-
*
|
|
1032
|
+
* - `package.json`: dependencies / devDependencies / peerDependencies / optionalDependencies,
|
|
1033
|
+
* including `npm:`-aliased entries (the alias key hides the real package name).
|
|
1034
|
+
* - `package-lock.json` v1: the NESTED `dependencies` tree, where each entry may carry
|
|
1035
|
+
* its own `dependencies` (transitive deps) and an `npm:` alias in `version`.
|
|
1036
|
+
* - `package-lock.json` v2/v3: the flat `packages` map keys (node_modules/<name>),
|
|
1037
|
+
* plus each entry's own `name` field (set for aliased installs).
|
|
900
1038
|
*/
|
|
901
1039
|
function scanNpmManifest(
|
|
902
1040
|
content: string,
|
|
@@ -914,26 +1052,54 @@ function scanNpmManifest(
|
|
|
914
1052
|
const found = new Set<string>();
|
|
915
1053
|
const obj = json as Record<string, unknown>;
|
|
916
1054
|
|
|
917
|
-
const
|
|
918
|
-
if (
|
|
919
|
-
|
|
920
|
-
|
|
1055
|
+
const add = (name: string): void => {
|
|
1056
|
+
if (db.has(name)) found.add(name);
|
|
1057
|
+
};
|
|
1058
|
+
|
|
1059
|
+
/**
|
|
1060
|
+
* Walk a dependency map that may be either a flat package.json map
|
|
1061
|
+
* (name → version-range string) or a legacy package-lock v1 tree (name →
|
|
1062
|
+
* `{ version, requires, dependencies }`, arbitrarily nested). Matches keys,
|
|
1063
|
+
* resolves `npm:` aliases from string values and entry `version` fields, and
|
|
1064
|
+
* recurses into a nested `dependencies` sub-tree.
|
|
1065
|
+
*/
|
|
1066
|
+
const walkDepTree = (deps: unknown, depth: number): void => {
|
|
1067
|
+
if (depth > NPM_TREE_MAX_DEPTH || deps === null || typeof deps !== "object") return;
|
|
1068
|
+
for (const [name, node] of Object.entries(deps as Record<string, unknown>)) {
|
|
1069
|
+
add(name);
|
|
1070
|
+
if (typeof node === "string") {
|
|
1071
|
+
// package.json form: the value is a range, possibly `npm:<real>@<range>`.
|
|
1072
|
+
const aliased = npmAliasTarget(node);
|
|
1073
|
+
if (aliased) add(aliased);
|
|
1074
|
+
} else if (node !== null && typeof node === "object") {
|
|
1075
|
+
const rec = node as Record<string, unknown>;
|
|
1076
|
+
if (typeof rec.version === "string") {
|
|
1077
|
+
const aliased = npmAliasTarget(rec.version);
|
|
1078
|
+
if (aliased) add(aliased);
|
|
1079
|
+
}
|
|
1080
|
+
walkDepTree(rec.dependencies, depth + 1); // v1 nests transitive deps here
|
|
1081
|
+
}
|
|
921
1082
|
}
|
|
922
1083
|
};
|
|
923
1084
|
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
1085
|
+
walkDepTree(obj.dependencies, 0);
|
|
1086
|
+
walkDepTree(obj.devDependencies, 0);
|
|
1087
|
+
walkDepTree(obj.peerDependencies, 0);
|
|
1088
|
+
walkDepTree(obj.optionalDependencies, 0);
|
|
928
1089
|
|
|
929
1090
|
const packages = obj.packages;
|
|
930
1091
|
if (packages !== null && typeof packages === "object") {
|
|
931
|
-
for (const key of Object.
|
|
1092
|
+
for (const [key, entry] of Object.entries(packages as Record<string, unknown>)) {
|
|
932
1093
|
if (!key) continue; // root package entry
|
|
933
1094
|
const marker = "node_modules/";
|
|
934
1095
|
const idx = key.lastIndexOf(marker);
|
|
935
|
-
|
|
936
|
-
|
|
1096
|
+
add(idx >= 0 ? key.slice(idx + marker.length) : key);
|
|
1097
|
+
// Aliased install: the entry's own `name` field is the real package, which
|
|
1098
|
+
// differs from the alias embedded in the node_modules/<alias> key.
|
|
1099
|
+
if (entry !== null && typeof entry === "object") {
|
|
1100
|
+
const realName = (entry as Record<string, unknown>).name;
|
|
1101
|
+
if (typeof realName === "string") add(realName);
|
|
1102
|
+
}
|
|
937
1103
|
}
|
|
938
1104
|
}
|
|
939
1105
|
|
package/src/detectors/source.ts
CHANGED
|
@@ -47,6 +47,15 @@ import { CWE_BROKEN_CRYPTO, CWE_CERT_VALIDATION, CWE_WEAK_STRENGTH } from "../cw
|
|
|
47
47
|
// (ordered alternation would otherwise match `rsa` and reject the `-pss` tail).
|
|
48
48
|
const RE_GENERATE_KEYPAIR =
|
|
49
49
|
/generateKeyPair(?:Sync)?\s*\(\s*['"`](rsa-pss|rsa|ec|dsa|dh|x25519|x448|ed25519|ed448)['"`]/g;
|
|
50
|
+
// Variable-typed key generation: `generateKeyPair(kind, …)` where the algorithm
|
|
51
|
+
// argument is an IDENTIFIER (a variable), not a quoted literal, so the concrete
|
|
52
|
+
// family is unknown at scan time but a classical key is still being generated.
|
|
53
|
+
// The lookbehind anchors the call to a word boundary so it does not fire inside
|
|
54
|
+
// a longer identifier (e.g. `myGenerateKeyPair(`); the first argument must be a
|
|
55
|
+
// bare identifier immediately followed by `,` or `)` so a quoted-literal call
|
|
56
|
+
// (handled by RE_GENERATE_KEYPAIR) never matches here.
|
|
57
|
+
const RE_GENERATE_KEYPAIR_VAR =
|
|
58
|
+
/(?<![\w$])generateKeyPair(?:Sync)?\s*\(\s*([A-Za-z_$][\w$]*)\s*[,)]/g;
|
|
50
59
|
|
|
51
60
|
/** Per-key-type classification for `generateKeyPair(Sync)('<type>', …)`. Hoisted
|
|
52
61
|
* to module scope so the direct matcher AND the import-alias pass (below) share
|
|
@@ -177,6 +186,20 @@ function escapeRe(s: string): string {
|
|
|
177
186
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
178
187
|
}
|
|
179
188
|
const RE_CREATE_SIGN_VERIFY = /create(?:Sign|Verify)\s*\(/g;
|
|
189
|
+
// Computed-member (bracket) access to a Node `crypto` method:
|
|
190
|
+
// `crypto['createSign'](…)`, `c["createECDH"](…)`. Bracket access defeats the
|
|
191
|
+
// dotted-call regexes above (which require `name(`), so match a quoted method
|
|
192
|
+
// name inside a `[ '…' ]( ` computed call and route it to the right rule. The
|
|
193
|
+
// method names here take no key-type argument, so no argument parsing is needed;
|
|
194
|
+
// `generateKeyPair(Sync)` bracket access is handled separately (it carries the
|
|
195
|
+
// key-type literal). None of these overlap the dotted regexes (those require the
|
|
196
|
+
// name immediately before `(`, whereas here it is followed by a closing quote).
|
|
197
|
+
const RE_BRACKET_CRYPTO_METHOD =
|
|
198
|
+
/\[\s*['"`](createSign|createVerify|createECDH|createDiffieHellman|createDiffieHellmanGroup|publicEncrypt|privateDecrypt)['"`]\s*\]\s*\(/g;
|
|
199
|
+
// `crypto['generateKeyPairSync']('rsa', …)`: bracket access carrying the quoted
|
|
200
|
+
// key-type literal, classified exactly like the dotted `generateKeyPair` call.
|
|
201
|
+
const RE_BRACKET_KEYGEN =
|
|
202
|
+
/\[\s*['"`]generateKeyPair(?:Sync)?['"`]\s*\]\s*\(\s*['"`](rsa-pss|rsa|ec|dsa|dh|x25519|x448|ed25519|ed448)['"`]/g;
|
|
180
203
|
// One-shot crypto.sign/verify(algorithm, data, key). A LOOKBEHIND (not a
|
|
181
204
|
// consumed char) anchors it so it doesn't fire inside identifiers like `assign(`
|
|
182
205
|
// or `createSign(` (handled by the dedicated createSign/createVerify rule) —
|
|
@@ -375,6 +398,28 @@ const nodeCryptoDetector: Detector = {
|
|
|
375
398
|
pushKeygenFinding(findings, m[1], file, content, m.index, m[0].length);
|
|
376
399
|
});
|
|
377
400
|
|
|
401
|
+
// generateKeyPair(Sync)(<variable>, …): key type passed as a variable, so the
|
|
402
|
+
// family is unknown; emit the generic keygen rule (unknown / key-exchange /
|
|
403
|
+
// HNDL-conservative) rather than missing the classical key generation.
|
|
404
|
+
eachMatch(RE_GENERATE_KEYPAIR_VAR, content, (m) => {
|
|
405
|
+
findings.push(
|
|
406
|
+
findingFromRule(
|
|
407
|
+
RULE_NODE_KEYGEN,
|
|
408
|
+
{ file, content, index: m.index, matchLength: m[0].length },
|
|
409
|
+
{
|
|
410
|
+
title: "Classical key generation (variable key type)",
|
|
411
|
+
message:
|
|
412
|
+
"Generates a classical asymmetric key pair (key type passed as a variable), which is not quantum-safe.",
|
|
413
|
+
},
|
|
414
|
+
),
|
|
415
|
+
);
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
// Bracket (computed-member) key generation: crypto['generateKeyPairSync']('rsa').
|
|
419
|
+
eachMatch(RE_BRACKET_KEYGEN, content, (m) => {
|
|
420
|
+
pushKeygenFinding(findings, m[1], file, content, m.index, m[0].length);
|
|
421
|
+
});
|
|
422
|
+
|
|
378
423
|
// Import-alias resolution: follow `import { generateKeyPairSync as gk }` (and
|
|
379
424
|
// the CommonJS destructure-rename) so an aliased call still detects. Only the
|
|
380
425
|
// keygen / ECDH / DH constructors are resolved — their classification is
|
|
@@ -432,6 +477,23 @@ const nodeCryptoDetector: Detector = {
|
|
|
432
477
|
);
|
|
433
478
|
});
|
|
434
479
|
|
|
480
|
+
// Bracket (computed-member) access to argument-free crypto methods:
|
|
481
|
+
// crypto['createSign'](…), c["createECDH"](…). Route each to its rule.
|
|
482
|
+
eachMatch(RE_BRACKET_CRYPTO_METHOD, content, (m) => {
|
|
483
|
+
const loc = { file, content, index: m.index, matchLength: m[0].length };
|
|
484
|
+
const method = m[1];
|
|
485
|
+
if (method === "createSign" || method === "createVerify") {
|
|
486
|
+
findings.push(findingFromRule(RULE_NODE_SIGN, loc));
|
|
487
|
+
} else if (method === "createECDH") {
|
|
488
|
+
findings.push(findingFromRule(RULE_NODE_ECDH, loc));
|
|
489
|
+
} else if (method === "publicEncrypt" || method === "privateDecrypt") {
|
|
490
|
+
findings.push(findingFromRule(RULE_NODE_RSA_ENCRYPT, loc));
|
|
491
|
+
} else {
|
|
492
|
+
// createDiffieHellman / createDiffieHellmanGroup: finite-field DH.
|
|
493
|
+
findings.push(findingFromRule(RULE_NODE_DH, loc));
|
|
494
|
+
}
|
|
495
|
+
});
|
|
496
|
+
|
|
435
497
|
// One-shot crypto.sign(algorithm, data, key) / crypto.verify(...) (Node ≥ 12).
|
|
436
498
|
eachMatch(RE_ONESHOT_SIGN_VERIFY, content, (m) => {
|
|
437
499
|
findings.push(
|