Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
6953360
docs: add crypto behavior taxonomy design spec
n1ckl0sk0rtge Jul 3, 2026
24ea385
docs: add Part A implementation plan for crypto behavior taxonomy
n1ckl0sk0rtge Jul 3, 2026
40fe9dd
feat(output): add crypto behavior taxonomy snapshot and enum
n1ckl0sk0rtge Jul 3, 2026
f819fe9
feat(output): map detected assets to crypto behaviors
n1ckl0sk0rtge Jul 3, 2026
09872d3
feat(output): emit aggregated crypto behavior on metadata.component
n1ckl0sk0rtge Jul 3, 2026
7e0827e
update git ignore
n1ckl0sk0rtge Jul 3, 2026
163d667
fix(output): map protocol/cipher-suite constituents; broaden tests; p…
n1ckl0sk0rtge Jul 3, 2026
f858180
docs: add Part B implementation plan (curated detection: wrapsKey, ge…
n1ckl0sk0rtge Jul 3, 2026
fad6119
feat(java): detect Cipher.unwrap as Decapsulate (wrapsKey)
n1ckl0sk0rtge Jul 3, 2026
3b0faf1
feat(output): map KeyWrap-kind ciphers to wrapsKey
n1ckl0sk0rtge Jul 3, 2026
9fcd711
feat(mapper): add generic PRNG model and map JCA DRBG names
n1ckl0sk0rtge Jul 3, 2026
b8ab5a0
feat(java): detect SecureRandom usage as PRNG with Generate (generate…
n1ckl0sk0rtge Jul 3, 2026
a8c5953
test(output): cover Decapsulate+KeyWrap wrapsKey; clarify PRNG probe/…
n1ckl0sk0rtge Jul 4, 2026
c5bd74d
docs: add contextual evidence layer design (crypto behavior taxonomy)
n1ckl0sk0rtge Jul 4, 2026
8cae4ac
docs: add implementation plan for crypto behavior context layer
n1ckl0sk0rtge Jul 4, 2026
c0de21e
feat(engine): add AuthContext detection-context kind for auth-interfa…
n1ckl0sk0rtge Jul 4, 2026
2f0cea5
feat(output): add validatesToken/usesIdentity behaviors and Confidenc…
n1ckl0sk0rtge Jul 4, 2026
ff6e433
feat(output): add two-tier BehaviorInferenceEngine gating app-level b…
n1ckl0sk0rtge Jul 4, 2026
5e0350d
feat(output): run behavior inference at emission with confidence-suff…
n1ckl0sk0rtge Jul 4, 2026
28950f4
feat(java): detect JWT and servlet-principal auth interfaces as AuthC…
n1ckl0sk0rtge Jul 4, 2026
d263434
feat(java): route AuthContext findings into scan-wide BehaviorEvidenc…
n1ckl0sk0rtge Jul 4, 2026
72a3263
feat(plugin): forward auth evidence signals from ScannerManager into …
n1ckl0sk0rtge Jul 4, 2026
fc4ee63
test(java): restore SecureRandom scaffolding with PRNG annotations
n1ckl0sk0rtge Jul 5, 2026
d543283
docs: rework evidence channel as a ContextualEvidence IR node (supers…
n1ckl0sk0rtge Jul 5, 2026
2e31021
docs: add implementation plan for ContextualEvidence node rework
n1ckl0sk0rtge Jul 5, 2026
705df95
feat(mapper): add generic ContextualEvidence IR node
n1ckl0sk0rtge Jul 5, 2026
8de507f
feat(java): translate AuthContext findings to ContextualEvidence nodes
n1ckl0sk0rtge Jul 5, 2026
7d137f9
refactor: collect contextual evidence from IR nodes, remove BehaviorE…
n1ckl0sk0rtge Jul 5, 2026
2216a84
test(java): resolve auth-interface types via pinned test jars
n1ckl0sk0rtge Jul 5, 2026
c356ce0
refactor(output): drop Confidence tier from crypto behaviors
n1ckl0sk0rtge Jul 5, 2026
2121afd
docs: add design for completing AuthContext detection family (Java)
n1ckl0sk0rtge Jul 5, 2026
cade608
docs: add implementation plan for completing AuthContext detection (J…
n1ckl0sk0rtge Jul 5, 2026
07e1889
feat(engine): add API_KEY and MTLS auth context kinds
n1ckl0sk0rtge Jul 5, 2026
1ed8c1e
feat(output): map SAML to validatesToken; add API_KEY and MTLS behaviors
n1ckl0sk0rtge Jul 5, 2026
c8f18dd
refactor(java): split auth detection into per-kind rule classes
n1ckl0sk0rtge Jul 5, 2026
ca8f8f8
feat(java): verify-anchored JWT auth rules (jjwt retighten, Nimbus, A…
n1ckl0sk0rtge Jul 5, 2026
66cc215
feat(java): OAuth auth rules (Spring JwtDecoder/introspect, Nimbus OIDC)
n1ckl0sk0rtge Jul 5, 2026
5186732
feat(java): SAML auth rules (OpenSAML validators, Spring SAML2)
n1ckl0sk0rtge Jul 5, 2026
167c26e
feat(java): broaden PRINCIPAL rules (javax servlet, JAX-RS, Spring Au…
n1ckl0sk0rtge Jul 5, 2026
4e6a8f0
feat(java): mTLS auth rules (X509TrustManager, SSLSession, Spring X50…
n1ckl0sk0rtge Jul 5, 2026
d9c941c
feat(java): API_KEY auth rules (pac4j direct clients, Spring header f…
n1ckl0sk0rtge Jul 5, 2026
aa90a88
docs: document Scanner Engine heap workaround for rule-graph OOM
n1ckl0sk0rtge Jul 5, 2026
57c9e96
docs: fix heap workaround for mvn sonar:sonar (use MAVEN_OPTS)
n1ckl0sk0rtge Jul 5, 2026
f2bf4f7
docs: correct heap knob to SONAR_SCANNER_JAVA_OPTS for scanner-for-ma…
n1ckl0sk0rtge Jul 5, 2026
82e1c18
refactor(tests): reorder imports and remove unused code in `Issue224T…
n1ckl0sk0rtge Jul 5, 2026
97b8890
Merge remote-tracking branch 'origin/main' into feature/crypto-behavi…
n1ckl0sk0rtge Jul 5, 2026
db1dc94
Merge branch 'main' into feature/crypto-behavior-taxonomy
n1ckl0sk0rtge Jul 13, 2026
cd4c4a1
Close AuthContext §8 test gaps: jjwt retighten regression and unteste…
n1ckl0sk0rtge Jul 13, 2026
3c639bf
Add behavior subsystem refactor design spec
n1ckl0sk0rtge Jul 13, 2026
1c50679
Add behavior subsystem refactor implementation plan
n1ckl0sk0rtge Jul 13, 2026
04447fb
Move crypto behavior taxonomy and mapper to com.ibm.output.behavior
n1ckl0sk0rtge Jul 13, 2026
823a1b1
Table-ize CryptoBehaviorMapper and stop deriving authenticates from c…
n1ckl0sk0rtge Jul 13, 2026
000fbd1
Add behavior signal model and inference rules
n1ckl0sk0rtge Jul 13, 2026
8294146
Add BehaviorCollector as the behavior subsystem entry point
n1ckl0sk0rtge Jul 13, 2026
002a426
Wire BehaviorCollector into CBOMOutputFile and delete BehaviorInferen…
n1ckl0sk0rtge Jul 13, 2026
40091e9
Apply formatting after behavior subsystem refactor
n1ckl0sk0rtge Jul 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,5 @@ build/
### Generated scan output ###
cbom.json

### Skills
.superpowers
18 changes: 17 additions & 1 deletion docs/TROUBLESHOOTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,23 @@ Click "Generate", then "Continue" (you don't have to save the value of your toke
For reference, at the time of writing this guide, we use Java 17.0.11 and Maven 3.9.7.

Copy this code snippet and open a terminal in the directory of the `client-encryption-java` project you just cloned.
Paste the code snippet in the terminal, but **replace the `verify` argument of the command by `package -DskipTests`** (we don't want to run the tests as they may fail in this case). In our case, the command is now:
Paste the code snippet in the terminal, but **replace the `verify` argument of the command by `package -DskipTests`** (we don't want to run the tests as they may fail in this case).

> [!IMPORTANT]
> Before running the command, raise the JVM heap, otherwise the scan can fail during rule construction with:
> ```
> java.lang.OutOfMemoryError: Java heap space
> at com.ibm.engine.detection.MethodMatcher.<init>(...)
> ```
> This happens because the BouncyCastle rule set expands into a large in-memory graph (~520k rule objects, ~200 MB) that is rebuilt once per registered check, so it needs headroom on top of the analyzed project's semantic model.
> **Set the heap on the right JVM.** As of SonarScanner for Maven **5.0+** (bundled with recent SonarQube), `mvn sonar:sonar` runs the analysis in a **forked Scanner Engine process** (`ScannerMain` in the stack trace), whose heap is controlled by `SONAR_SCANNER_JAVA_OPTS` — **not** `MAVEN_OPTS` (that only applies to scanner ≤ 4.x, where the engine ran in the Maven JVM):
> ```
> export SONAR_SCANNER_JAVA_OPTS="-Xmx2g" # scanner-for-maven 5.0+ (forked engine)
> # export MAVEN_OPTS="-Xmx2g" # only for scanner-for-maven <= 4.x
> ```
> A permanent fix that shrinks the rule graph is tracked in [#476](https://github.com/cbomkit/sonar-cryptography/issues/476).

In our case, the command is now:
```
mvn clean package -DskipTests sonar:sonar \
-Dsonar.projectKey=mastercard \
Expand Down
614 changes: 614 additions & 0 deletions docs/superpowers/plans/2026-07-03-crypto-behavior-taxonomy-part-b.md

Large diffs are not rendered by default.

740 changes: 740 additions & 0 deletions docs/superpowers/plans/2026-07-03-crypto-behavior-taxonomy.md

Large diffs are not rendered by default.

1,096 changes: 1,096 additions & 0 deletions docs/superpowers/plans/2026-07-04-crypto-behavior-context-layer.md

Large diffs are not rendered by default.

1,264 changes: 1,264 additions & 0 deletions docs/superpowers/plans/2026-07-05-authcontext-java-completion.md

Large diffs are not rendered by default.

538 changes: 538 additions & 0 deletions docs/superpowers/plans/2026-07-05-contextual-evidence-node.md

Large diffs are not rendered by default.

1,151 changes: 1,151 additions & 0 deletions docs/superpowers/plans/2026-07-13-behavior-subsystem-refactor.md

Large diffs are not rendered by default.

216 changes: 216 additions & 0 deletions docs/superpowers/specs/2026-07-03-crypto-behavior-taxonomy-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
# Crypto Behavior Taxonomy in CBOM — Design

**Date:** 2026-07-03
**Status:** Experimental feature — design approved, pending implementation plan
**Module ownership:** `output` (mapping + emission), `java` (curated new detection)

## 1. Summary

Attach CycloneDX 2.0-dev **cryptographic behavior** information to the generated CBOM. The
behaviors describe the **scanned software as a whole**: the CBOM already inventories all crypto
assets in the software, and the software *behaves* cryptographically (it encrypts data, signs data,
hashes passwords, …). We derive a behavior for each detected crypto asset where possible, then emit
the **union** of those behaviors once, as a property on the BOM's `metadata.component`.

This is **experimental**: the CycloneDX 2.0 threat-modeling taxonomy is still a draft. To stay
self-contained as the standard evolves, we bundle a **local copy** of the taxonomy (JSON resource)
and emit behaviors as a namespaced, non-standard property rather than as first-class schema fields.

### Reference

- Taxonomy source (draft): CycloneDX `2.0-dev-threatmodeling` branch,
`schema/behavior-taxonomy.schema.json`, the `security:cryptography:*` enum (50 values).
- Example values: `encryptsData`, `decryptsData`, `signsData`, `verifiesSignature`, `hashesData`,
`hashesPassword`, `generatesKey`, `generatesRandomValue`, `exchangesKey`, `wrapsKey`,
`ensuresConfidentiality`, `ensuresIntegrity`, `ensuresNonRepudiation`, `authenticates`.

## 2. Goals / Non-goals

**Goals**
- Derive a cryptographic behavior for each detected asset where a confident mapping exists.
- Aggregate all detected behaviors and emit them once on `bom.metadata.component.properties`.
- Bundle a local, verbatim snapshot of the draft taxonomy so the feature is self-contained.
- Add a small, high-confidence set of *new/rewired* detections to unlock two extra behaviors.
- Keep the feature additive and trivially removable (output-layer only, plus isolated detection).

**Non-goals (deferred, documented as future work)**
- KeyStore key-lifecycle behaviors (`storesKey`, `retrievesKey`, `destroysKey`, `rotatesKey`) —
require a new engine detection context, rules, model node, and mapper.
- Data-context behaviors (`encryptsDataAtRest` / `encryptsDataInTransit` / `encryptsDisk`, and the
`decrypts*` equivalents) — require data-flow / taint analysis the engine does not have.
- PKI / certificate behaviors (`validatesCertificate`, `checksRevocation`, `issuesCertificate`,
`revokesCertificate`, `presentsClientCertificate`, `presentsServerCertificate`).
- Per-asset behavior attribution in the output (we emit software-level aggregate only).

## 3. Design decisions (locked)

| Decision | Choice |
|---|---|
| Mapping source | **Operation-first, coarse**, maximizing precision from existing context (Functionality node + primitive kind + cipher opmode + mode). |
| Behavior categories | **Operational + security-goal** (both). |
| New-detection ambition | **Mapping + curated key-lifecycle-adjacent detections** (`wrapsKey`, `generatesRandomValue`); KeyStore deferred. |
| Output shape | **Single property, comma-separated list** of behavior identifiers. |
| Output location | **`bom.metadata.component.properties`** (software-level aggregate), *not* per-component. |
| Architecture | **Output-layer mapper** — no changes to the model/enricher pipeline for the mapping itself. |

## 4. Architecture & components

Data flow (additive to the existing pipeline):

```
detected asset (INode tree, post-enrich)
→ CryptoBehaviorMapper.map(asset) # per asset
→ Set<CryptoBehavior>
→ union into a scan-wide Set<CryptoBehavior> accumulator (CBOMOutputFile)
→ CBOMOutputFile.getBom(): create metadata.component, attach ONE aggregate property
```

### 4.1 `crypto-behavior-taxonomy.json` (resource, `output` module)

A verbatim local copy of the draft taxonomy under
`output/src/main/resources/`. Contains the `security:cryptography:*` entries with, per behavior:
`identifier` (full colon-delimited id), `name` (leaf), `category`, and `description` (copied from the
schema's `meta:enum`). This is the authoritative "standard snapshot" for the experiment.

### 4.2 `CryptoBehavior` enum (`output` module)

Typed handles for the identifiers we actually emit (a subset of the 50). Each value exposes
`fullId()` → `"security:cryptography:<name>"`. A unit test asserts every enum value's `fullId()` is
present in `crypto-behavior-taxonomy.json`, keeping code and snapshot in sync.

### 4.3 `CryptoBehaviorMapper` (`output` module)

Pure, total function:

```java
Set<CryptoBehavior> map(INode asset);
```

Reads only data already on the asset tree:
- `Functionality` children (`Encrypt, Decrypt, Sign, Verify, Digest, Tag, Generate, KeyGeneration,
KeyDerivation, Encapsulate, Decapsulate`),
- the asset's primitive `kind` (`BlockCipher, StreamCipher, Cipher, AuthenticatedEncryption, Mac,
MessageDigest, Signature, KeyAgreement, PublicKeyEncryption, KeyDerivationFunction,
PasswordBasedKeyDerivationFunction, PasswordBasedEncryption, KeyEncapsulationMechanism,
PseudorandomNumberGenerator, …`),
- cipher opmode / `CipherAction` (to disambiguate wrap/unwrap),
- mode where relevant.

Never throws. An asset it cannot map returns an empty set (no wrong behavior emitted).

### 4.4 Output integration (`CBOMOutputFile`, `output` module)

- Add a scan-wide accumulator field `Set<CryptoBehavior> aggregatedBehaviors`.
- In each `create*Component(...)` method (`createAlgorithmComponent`, `createKeyComponent`,
`createProtocolComponent`, `createCipherSuiteComponent`, `createRelatedCryptoMaterialComponent`),
call `CryptoBehaviorMapper.map(node)` and add the result to the accumulator.
- In `getBom()` (metadata-assembly choke point): the current code sets `metadata` (timestamp +
tool info) but **does not set `metadata.component`**. Create one:
- `Component softwareComponent = new Component();`
- `softwareComponent.setType(Component.Type.APPLICATION);`
- `softwareComponent.setName(<scanned software name if available, else "application">);`
- If `aggregatedBehaviors` is non-empty, attach exactly one property:
- `name = "cbomkit:crypto:behavior"`
- `value` = the accumulator mapped to `fullId()`, **deduped, sorted, joined with `,`**.
- `metadata.setComponent(softwareComponent);`
- Emit nothing when the accumulator is empty (no property, and no empty component solely for it).

Namespace rationale: `cbomkit:` marks the property as an experimental, tool-specific extension so no
consumer mistakes it for a ratified CycloneDX field.

### 4.5 Curated detection changes (`java` module)

Two behaviors need signal the mapper can read; both are cheap relative to KeyStore.

**`generatesRandomValue`** — the `java/.../rules/detection/random/` package (`SecureRandomGetInstance`)
exists but is **orphaned** (never aggregated in `JavaDetectionRules`) and covers only the seed
constructor / `setSeed`. Work:
- Wire the `random` bundle into `JavaDetectionRules.rules()`.
- Extend it to detect `SecureRandom.getInstance(...)` / `SecureRandom.getInstanceStrong()` (and
DRBG algorithm names) so a `PseudorandomNumberGenerator` asset with a `Generate` functionality is
produced, which the mapper maps to `generatesRandomValue`.

**`wrapsKey`** — `Cipher.wrap` is already detected (`CipherAction.WRAP`) and `WRAP_MODE(3)` /
`UNWRAP_MODE(4)` opmodes already produce signals (`JcaCipherOperationModeMapper` currently maps
`3→Encapsulate, 4→Decapsulate`). Work:
- Ensure `Cipher.unwrap` is also detected (add the rule if missing) so unwrap surfaces a signal.
- The mapper distinguishes `Encapsulate`/`Decapsulate` **on a `Cipher`** (→ `wrapsKey`) from
`Encapsulate`/`Decapsulate` **on a `KeyEncapsulationMechanism`** (→ `exchangesKey`) using the
primitive kind. No change to the existing `cryptoFunctions` output is required.

## 5. Mapping table

Operation-first; primitive kind disambiguates and adds security-goal behaviors. When an asset has
**no** `Functionality` child, fall back to the plausible operational set implied by its primitive.

| Detected signal | Emitted behavior(s) |
|---|---|
| `Encrypt` on cipher / PKE / AE | `encryptsData`, `ensuresConfidentiality` |
| `Decrypt` on cipher / PKE / AE | `decryptsData`, `ensuresConfidentiality` |
| `Encapsulate` / `Decapsulate` on **Cipher** (wrap/unwrap) | `wrapsKey` |
| `Encapsulate` / `Decapsulate` on **KEM** | `exchangesKey`, `ensuresConfidentiality` |
| `KeyAgreement` primitive | `exchangesKey` |
| `Sign` on Signature | `signsData`, `ensuresIntegrity`, `ensuresNonRepudiation` |
| `Verify` on Signature | `verifiesSignature`, `ensuresIntegrity` |
| `Digest` on MessageDigest | `hashesData`, `ensuresIntegrity` |
| `Tag` on Mac | `authenticates`, `ensuresIntegrity` |
| `Generate` on PRNG / DRBG | `generatesRandomValue` |
| `KeyGeneration` | `generatesKey` |
| `KeyDerivation` on password-based KDF / PBE | `hashesPassword` |
| `KeyDerivation` on generic KDF | `generatesKey` *(approximate — see gaps)* |

**Primitive-only fallback** (no `Functionality` child present):

| Primitive kind | Inferred behavior(s) |
|---|---|
| `BlockCipher` / `StreamCipher` / `Cipher` | `encryptsData`, `decryptsData`, `ensuresConfidentiality` |
| `AuthenticatedEncryption` | `encryptsData`, `decryptsData`, `ensuresConfidentiality`, `ensuresIntegrity` |
| `PublicKeyEncryption` | `encryptsData`, `decryptsData`, `ensuresConfidentiality` |
| `Signature` | `signsData`, `verifiesSignature`, `ensuresIntegrity`, `ensuresNonRepudiation` |
| `MessageDigest` | `hashesData`, `ensuresIntegrity` |
| `Mac` | `authenticates`, `ensuresIntegrity` |
| `KeyAgreement` | `exchangesKey` |
| `KeyEncapsulationMechanism` | `exchangesKey`, `ensuresConfidentiality` |
| `PasswordBasedKeyDerivationFunction` / `PasswordBasedEncryption` | `hashesPassword` |
| `KeyDerivationFunction` | `generatesKey` *(approximate)* |
| `PseudorandomNumberGenerator` | `generatesRandomValue` |

### 5.1 Known taxonomy gaps (documented, honest)

- **MAC** has no operational "computesMac"/"tagsData" verb in the taxonomy; we emit the goal-level
`authenticates` + `ensuresIntegrity` instead.
- **Generic KDF** (e.g. HKDF) has no "deriveKey" value; approximated as `generatesKey`. Flagged so a
future taxonomy revision can refine it.

These gaps are captured in the `CryptoBehaviorMapper` as comments referencing this section.

## 6. Error handling

- `CryptoBehaviorMapper` is total: unknown/unsupported primitive or functionality → empty set,
never an exception and never a guessed behavior.
- Empty scan-wide accumulator → no property emitted.
- Optional `DEBUG` log listing asset kinds that produced no behavior, to guide future mapping work.

## 7. Testing

- **`CryptoBehaviorMapper` unit tests** across representative assets: AES encrypt / decrypt / wrap,
RSA sign / verify / encrypt, SHA-256 digest, HMAC, ECDH, PBKDF2, ML-KEM, SecureRandom, plus a
primitive-only asset (no functionality) exercising the fallback table.
- **Enum ↔ JSON sync test**: every `CryptoBehavior.fullId()` exists in
`crypto-behavior-taxonomy.json`.
- **Detection tests** (`TestBase` + `CheckVerifier`) for the rewired random detection and the
wrap/unwrap detection.
- **CBOM integration test**: a source file using AES-encrypt + SHA-256 + HMAC produces a BOM whose
`metadata.component.properties` contains exactly one `cbomkit:crypto:behavior` property with value
`security:cryptography:authenticates,security:cryptography:encryptsData,security:cryptography:ensuresConfidentiality,security:cryptography:ensuresIntegrity,security:cryptography:hashesData`
(deduped, sorted). Assert the property is absent when no crypto is detected.

## 8. Future work

- KeyStore key-lifecycle behaviors via a new `KeyStore`/certificate detection context.
- Data-context behaviors (`*DataAtRest` / `*DataInTransit` / `*Disk`) via call-site heuristics
(`CipherInputStream`/`CipherOutputStream`, `KeyStore.load/store`, `SSLSocket` streams) — coarse
heuristic only; true provenance needs data-flow analysis.
- PKI / certificate behaviors (`validatesCertificate`, `checksRevocation`, etc.).
- Promote from an experimental namespaced property to first-class CycloneDX fields once the 2.0
taxonomy is ratified.
Loading
Loading