diff --git a/.kiro/specs/real-world-vfc-slice/brief.md b/.kiro/specs/real-world-vfc-slice/brief.md new file mode 100644 index 0000000..e963d3d --- /dev/null +++ b/.kiro/specs/real-world-vfc-slice/brief.md @@ -0,0 +1,54 @@ +# Brief: real-world-vfc-slice + +## Problem + +Operators care whether the harness fires on a real buggy snapshot and stays quiet after the patch — Firefox, Chromium, OpenSSL — not whether OWASP BenchmarkTest00074 is a TP. The labeled SAST slice is 11 textbook files. Overlay Youden there is **worse** than inventory (+9.09% → 0%). We cannot tell if the tool got better on messy product code. + +## Current State + +Slices today: `local` (CI 100%), `github` (6 vendored functions: SVEN, hutool, node-serialize), `sast` (OWASP/Juliet). `datasets.toml` already points at CVEfixes, MoreFixes, CWE-Bench-Java, Vul4J. Nothing is harvested from gecko-dev / Firefox. Whole mozilla-central is not in-tree (and should not be). FixFox (Zenodo) is embargoed until 2030. Firefox security commit messages are often scrubbed of “security” words, so grep-the-log is a bad miner. + +Measured on the current 11-pair **sast** slice (2026-09-04): + +| Scorer | pair_correct | vuln recall | silent-on-fix | Youden | +|--------|--------------|-------------|---------------|--------| +| Inventory (regex) | 2/11 (18%) | 54.5% | 54.5% | **+9.09%** | +| Overlay (current) | 2/11 (18%) | 45.5% | 54.5% | **0%** | + +The only overlay change vs inventory on that slice: `owasp-python-codeinj` went from LEAK (regex hit both sides) to MISS (ConfigParser heap → `flow_incomplete`, no promote). C/Java Juliet goodG2B still leak because those languages are unadjudicated and scoring falls back to inventory. + +## Desired Outcome + +A new pair slice (e.g. `vfc`) of **reviewed, isolated function pairs** from large projects, including Firefox/gecko-dev when a public fix commit exists in CVEfixes/MoreFixes. Offline CI. Honesty dashboard like `github`, not a 90% smoke gate. Overlay scoring once tree-sitter can parse C/JS/Java; inventory scoring until then. Provenance on every file (repo, commit, CVE, license). + +## Approach + +Do not clone Firefox. Filter public VFC databases for `gecko-dev` / `mozilla-firefox/firefox`, `chromium`, `openssl`, `curl`, plus existing CWE-Bench-Java. Extract the changed function before/after. Human-review labels (DiverseVul ~60% is not ground truth). Cap the runnable catalog (tens of pairs, not thousands). Prefer injection/XSS/path CWEs the overlay can talk about; keep UAF/buffer overflows as known inventory-only leaks until a later memory-safety spec. + +## Scope + +- **In**: harvest script or documented procedure; catalog slice; provenance headers; overlay-vs-inventory scoreboard on that slice; dataset.toml pointers for Firefox/Chromium. +- **Out**: Vendoring mozilla-central; live Bugzilla scraping; making Youden a merge gate; buffer-size semantics; tree-sitter packaging (owned by `tree-sitter-overlay-extra`). + +## Boundary Candidates + +- Catalog schema / slice name vs pair eval scoring +- Harvest tooling vs vendored excerpts + +## Out of Boundary + +- Parser extra, Joern, improve-loop auto-facts, `LANGUAGE_MANIFESTS` + +## Upstream / Downstream + +- **Upstream**: `pairs.py` catalog format; `propose-adjudicate-prove` overlay scoring +- **Downstream**: improve-loop signals from real misses; later memory-safety spec can reuse the same slice + +## Existing Spec Touchpoints + +- **Extends**: pair catalog only (new slice). Does not change smoke gate. +- **Adjacent**: `tree-sitter-overlay-extra` (C/Java overlay on this slice once the extra exists) + +## Constraints + +Isolated functions, same `relpath` vuln/fixed. License in the header. No 16 GB dumps in git. Firefox pairs only when a public git commit pair exists — MFSA text without a commit is not a pair. diff --git a/.kiro/specs/real-world-vfc-slice/design.md b/.kiro/specs/real-world-vfc-slice/design.md new file mode 100644 index 0000000..9792130 --- /dev/null +++ b/.kiro/specs/real-world-vfc-slice/design.md @@ -0,0 +1,376 @@ +# Design Document + +## Overview + +**Purpose.** This feature gives OpenUltraSAST a labeled vuln-versus-fix slice from real OpenSSL, Firefox, and Chromium functions so engineers can evolve the harness against product code instead of only OWASP/Juliet. + +**Users.** Maintainers grow and score the catalog. AppSec engineers read the honesty dashboard. CI proves the catalog loads and the slice command runs offline. + +**Impact.** A new `vfc` slice is concatenated into the pair catalog. Overlay and inventory scores are reported side by side for that slice. The local 100% pair gate and the stage-1 smoke gate do not change. + +### Goals + +- Seed at least one reviewed isolated function pair each from OpenSSL, Firefox, and Chromium, with provenance. +- Score `vfc` as an honesty dashboard with overlay versus inventory figures. +- Harvest one function from public parent/fix blobs without cloning megarepos. +- Keep CI extra-free and offline; vfc Youden is not a merge condition. + +### Non-Goals + +- Cloning mozilla-central, gecko-dev, or Chromium. +- FixFox, Bugzilla scraping, or vendoring VFC dumps. +- CWE-121 buffer-size semantics, inter-file taint, or parser extra packaging. +- Changing inventory rules so the seed pairs become pair_correct. +- Making overlay or vfc Youden fail CI. + +## Boundary Commitments + +### This Spec Owns + +- The `vfc` pair slice: catalog rows, vendored excerpts, provenance headers, recipes. +- Harvest procedure that extracts one function from public parent/fix snapshots. +- Dual overlay/inventory scoreboard fields for the vfc slice. +- CLI slice choice `vfc` and tests that the slice loads and runs. +- Dataset pointers for OpenSSL, Firefox/gecko-dev, and Chromium. + +### Out of Boundary + +- Overlay dispositions, taint, facts, FileIR (`propose-adjudicate-prove`). +- Tree-sitter extra packaging (`tree-sitter-overlay-extra`). +- Stage-1 `LANGUAGE_MANIFESTS` detection gate and local 100% pair gate fail condition. +- Pattern rule bodies; do not retune memcpy/eval to chase vfc Youden. +- Memory-safety / CWE-121 semantics (later spec may reuse these pairs). + +### Allowed Dependencies + +- Existing `PairCase` / `load_pair_catalog` / `evaluate_pair` / `result_payload`. +- Overlay pair path already used by `sast` (inventory fallback when unadjudicated). +- Stdlib HTTP client for harvest (maintainer-only, not CI). +- Public hosts: GitHub raw blobs, hg.mozilla.org / Phabricator raw diffs. + +### Revalidation Triggers + +- Changing `PairCase` required fields or catalog concatenation order. +- Failing CI on any slice other than `local`. +- Adding vfc names to `LANGUAGE_MANIFESTS`. +- Making harvest a network-using CI step. +- Importing parser wheels into harvest or pair eval. + +## Architecture + +### Existing Architecture Analysis + +Pair eval materializes each side of a pair into an isolated temp tree and scans it. `local` and `github` use inventory (`quick_scan`). `sast` uses overlay, falling back to inventory when no promote/demote/coverage occurred. Catalog load already concatenates a second file. The pair gate prints every slice but fails only when `local` pair_pass_rate is below 100%. + +### Architecture Pattern and Boundary Map + +Selected: **concatenated honesty slice + dual scoreboard**. Same catalog schema. Overlay eval generalized from `sast` to `{sast, vfc}`. Inventory sidecar computed only for vfc. + +```mermaid +flowchart TD + cli[ousast pairs slice vfc] + load[load_pair_catalog] + mainCat[pairs catalog] + sastCat[sast catalog] + vfcCat[vfc catalog] + eval[evaluate_pair] + overlay[overlay with inventory fallback] + inventory[inventory only] + board[result payload] + gate[pair_gate local only] + cli --> load + load --> mainCat + load --> sastCat + load --> vfcCat + load --> eval + eval --> overlay + eval --> inventory + overlay --> board + inventory --> board + load --> gate +``` + +**Key decisions** + +- Primary `per_slice.vfc` metrics come from overlay-with-fallback (same as sast). +- `scorers.vfc.overlay` and `scorers.vfc.inventory` are explicit so operators can compare. +- Harvest never runs in pytest. Seed excerpts are committed. +- Dependency direction: recipes/excerpts → vfc catalog → pair loader → eval → CLI payload. Harvest writes excerpts; it does not import overlay. + +### Technology Stack + +| Layer | Choice / Version | Role in Feature | Notes | +|-------|------------------|-----------------|-------| +| CLI | existing `ousast pairs --slice` | Operator entry | Add `vfc` to choices | +| Catalog | TOML `[[pair]]` | Same schema as github/sast | New file, concatenated | +| Scoring | existing overlay + inventory | Dual scoreboard | No new taint engine | +| Harvest | Python stdlib urllib | Maintainer fetch | Not a core package dep | +| Tests | pytest extra-free | Offline existence + CLI | No network | + +## File Structure Plan + +``` +benchmarks/pairs/ +├── catalog.toml # unchanged rows; still the default path +├── datasets.toml # add OpenSSL, Firefox, Chromium pointers +├── README.md # document vfc slice +├── sast/catalog.toml # unchanged +└── vfc/ + ├── catalog.toml # slice = vfc rows + ├── recipes.toml # harvest inputs for seed and later pairs + ├── harvest.py # extract one function from parent/fix URLs + ├── openssl-cve-2014-0160/ + │ ├── vuln.c + │ └── fixed.c + ├── firefox-cve-2020-15667/ + │ ├── vuln.c + │ └── fixed.c + └── chromium-cve-2019-5786/ + ├── vuln.cc + └── fixed.cc +``` + +### Modified Files + +- `src/openultrasast/pairs.py` — concatenate vfc catalog; overlay path for `vfc`; `scorers` on the eval result; `DEFAULT_VFC_CATALOG`. +- `src/openultrasast/cli.py` — `--slice` choice `vfc`. +- `src/openultrasast/pair_gate.py` — comment that vfc is honesty-only; fail condition stays local. +- `tests/test_pair_corpus.py` — vfc load, provenance, CLI, not in `LANGUAGE_MANIFESTS`, pair_gate still passes. +- `benchmarks/pairs/datasets.toml` — project pointers. +- `benchmarks/pairs/README.md` — slice list and harvest pointer. + +## System Flows + +```mermaid +sequenceDiagram + participant Op as Operator + participant CLI as pairs command + participant Cat as vfc catalog + participant Eval as pair eval + participant Inv as inventory scan + participant Ov as overlay adjudicate + Op->>CLI: pairs slice vfc + CLI->>Cat: load concatenated catalogs + Cat->>Eval: each vfc pair + Eval->>Inv: vuln tree and fix tree + Eval->>Ov: same trees + Ov-->>Eval: promote or fallback + Inv-->>Eval: inventory sidecar + Eval-->>CLI: outcomes plus scorers + CLI-->>Op: JSON or text scoreboard +``` + +Harvest (maintainer, not CI): recipe → fetch parent blob and fix blob → extract named function → write provenance header → write vuln/fixed files. Catalog rows stay hand-reviewed. + +## Requirements Traceability + +| Requirement | Summary | Components | Interfaces | Flows | +|-------------|---------|------------|------------|-------| +| 1.1, 1.2, 1.3 | vfc slice with three projects | VfcCatalog | catalog load | pairs command | +| 1.4 | reject advisory-only | HarvestTool, VfcCatalog | recipe validation | harvest | +| 2.1–2.4 | provenance and same relpath | ProvenanceHeader, VfcCatalog | catalog fields + file header | harvest | +| 3.1–3.4 | honesty not merge gate | PairGatePolicy, DualScorer | pair_gate, payload | gate | +| 4.1–4.4 | overlay vs inventory | DualScorer | scorers map | pairs command | +| 5.1–5.5 | harvest without clones | HarvestTool | recipes + harvest script | harvest | +| 6.1–6.4 | isolated reviewed functions | VfcCatalog, SeedExcerpts | expected CWE/sink | pair eval | +| 7.1–7.4 | offline testability | VfcTestMatrix | pytest + CLI | extra-free CI | + +## Components and Interfaces + +| Component | Domain/Layer | Intent | Req Coverage | Key Dependencies | Contracts | +|-----------|--------------|--------|--------------|------------------|-----------| +| VfcCatalog | Catalog | Reviewed vfc rows | 1.1, 1.2, 1.3, 2.3, 6.4 | Pair loader P0 | State | +| ProvenanceHeader | Catalog | Auditable origin on disk | 2.1, 2.2, 2.4 | VfcCatalog P0 | State | +| HarvestTool | Maintainer | Extract one function from public blobs | 1.4, 5.1, 5.2, 5.3, 5.4 | urllib P1 | Batch | +| DualScorer | Eval | Overlay primary + inventory sidecar | 4.1, 4.2, 4.3, 4.4, 3.3 | overlay eval P0 | State | +| PairGatePolicy | Eval | Local-only fail | 3.1, 3.2, 3.4, 7.4 | pair_gate P0 | State | +| SeedExcerpts | Catalog | Three isolated functions | 1.2, 6.1, 6.2, 6.3 | VfcCatalog P0 | State | +| VfcTestMatrix | Tests | Offline load and CLI | 7.1, 7.2, 7.3, 5.5 | pytest P0 | State | + +### Catalog + +#### VfcCatalog + +| Field | Detail | +|-------|--------| +| Intent | Concatenated `slice = "vfc"` rows with OpenSSL, Firefox, Chromium seeds | +| Requirements | 1.1, 1.2, 1.3, 2.3, 6.4 | + +**Responsibilities & Constraints** +- Same `[[pair]]` / `[[pair.expected]]` schema as github/sast. +- `load_pair_catalog` appends `benchmarks/pairs/vfc/catalog.toml` when loading the default catalog. +- Names stay out of `LANGUAGE_MANIFESTS`. +- Runnable set stays small; recipes may list more than CI runs. + +**Dependencies** +- Inbound: pair loader — concatenate file (P0) +- Outbound: evaluate_pair — cases (P0) + +**Contracts**: State [x] + +##### State Management +- `DEFAULT_VFC_CATALOG` next to `DEFAULT_SAST_CATALOG`. +- Missing vfc file: do not crash default load if we require the seed to exist; the seed is committed so the file is present. Tests assert it exists. + +#### ProvenanceHeader + +| Field | Detail | +|-------|--------| +| Intent | Human-readable origin on every vendored excerpt | +| Requirements | 2.1, 2.2, 2.4 | + +**Responsibilities & Constraints** +- Header comments include repo, commit, parent, commit URL, CVE, license, function name. +- Catalog row repeats repo, commit, commit_url, cve, license. +- License must be stated (OpenSSL License, MPL-2.0, BSD-3-Clause for the seeds). + +#### SeedExcerpts + +| Field | Detail | +|-------|--------| +| Intent | Isolated functions, same relpath, reviewed labels | +| Requirements | 1.2, 6.1, 6.2, 6.3 | + +Seed pairs (reviewed): + +| Name | Project | CVE | Function | Expected class | Honesty note | +|------|---------|-----|----------|----------------|--------------| +| openssl-cve-2014-0160 | OpenSSL | CVE-2014-0160 | `tls1_process_heartbeat` | CWE-126 / memcpy | memcpy remains after fix → likely LEAK | +| firefox-cve-2020-15667 | Firefox libmar | CVE-2020-15667 | `mar_insert_item` | CWE-119 / memcpy | namelen signedness fix; memcpy remains → likely LEAK | +| chromium-cve-2019-5786 | Chromium Blink | CVE-2019-5786 | `FileReaderLoader::ArrayBufferResult` | CWE-416 UAF | no inventory sink → likely MISS | + +Stubs (SSL types, MarItem, DOMArrayBuffer) are allowed only to keep the changed function intact. + +### Eval + +#### DualScorer + +| Field | Detail | +|-------|--------| +| Intent | Overlay-with-fallback as primary vfc metrics; inventory sidecar | +| Requirements | 4.1, 4.2, 4.3, 4.4, 3.3 | + +**Responsibilities & Constraints** +- `evaluate_pair` uses overlay when `slice in {"sast", "vfc"}`. +- Inventory-only evaluation of vfc cases fills `PairEvalResult.scorers["vfc"]["inventory"]`. +- Overlay metrics also appear as `scorers["vfc"]["overlay"]` (same numbers as `per_slice["vfc"]`). +- `result_payload` includes `scorers`. +- Do not use these figures as a gate. + +**Contracts**: State [x] + +```python +class PairEvalResult: + outcomes: tuple[PairOutcome, ...] + overall: PairCorpusMetrics + per_slice: dict[str, PairCorpusMetrics] + signals: tuple[dict[str, object], ...] + scorers: dict[str, dict[str, PairCorpusMetrics]] +``` + +##### Service Interface +- `evaluate_catalog(cases) -> PairEvalResult` +- Preconditions: each case has existing vuln and fixed files. +- Postconditions: if any case has `slice == "vfc"`, `scorers["vfc"]` has `overlay` and `inventory`. +- Invariants: pair_gate fail reasons mention only local. + +#### PairGatePolicy + +| Field | Detail | +|-------|--------| +| Intent | Keep merge fail on local 100% only | +| Requirements | 3.1, 3.2, 3.4, 7.4 | + +`pair_gate` may still *evaluate* the full catalog for the printed dashboard. It must not add vfc pair_correct to `reasons`. + +### Maintainer + +#### HarvestTool + +| Field | Detail | +|-------|--------| +| Intent | Fetch parent/fix blobs and extract one function | +| Requirements | 1.4, 5.1, 5.2, 5.3, 5.4 | + +**Contracts**: Batch [x] + +##### Batch / Job Contract +- Trigger: maintainer runs harvest with a recipe name. CI does not. +- Input: `recipes.toml` row: name, host, repo, parent, commit, path, function, cve, license, relpath. +- Validation: parent and commit required; reject recipes that have only an advisory URL. +- Output: vuln/fixed files with provenance headers. Catalog row is still a human edit. +- Idempotency: overwrite excerpts for that recipe name; do not fetch in tests. + +Function extract: start at the named declarator, copy through balanced braces. Do not clone a repo; HTTP GET of a raw blob or a raw diff. + +Hosts: `raw.githubusercontent.com`, Phabricator `?diff=1`. Not FixFox. + +### Tests + +#### VfcTestMatrix + +| Field | Detail | +|-------|--------| +| Intent | Offline proof the corpus exists and the slice runs | +| Requirements | 7.1, 7.2, 7.3, 5.5 | + +- Catalog load includes `vfc`; files exist; names include openssl, firefox, chromium. +- Provenance headers contain commit URL, CVE, license. +- `ousast pairs --slice vfc --json` exits 0; payload has those names and `scorers.vfc`. +- Pair gate still passes; vfc names not in `LANGUAGE_MANIFESTS`. +- Harvest extract is unit-tested on a local string, not the network. +- Do not assert 100% pair_correct or a Youden floor. + +## Data Models + +### Domain Model + +- **Pair**: isolated vuln snapshot + fixed snapshot + expected CWE/sink + provenance. +- **Slice**: `vfc` honesty set. Not a gate. +- **Scorer**: `overlay` or `inventory`. +- **Recipe**: harvest input, not ground truth until reviewed into the catalog. + +### Logical Data Model + +Catalog row (existing fields plus required provenance for vfc): + +- `name`, `slice = "vfc"`, `language`, `origin`, `license`, `repo`, `commit`, `parent`, `commit_url`, `cve`, `vuln`, `fixed`, `relpath`, `min_recall`, `fix_policy = "silent"` +- `[[pair.expected]]`: `cwe`, `class`, `path`, `rule_id`, `sink`, `evidence` + +`scorers` payload: + +```json +{ + "scorers": { + "vfc": { + "overlay": { "pairs": 3, "pair_correct": 0, "youden": 0.0 }, + "inventory": { "pairs": 3, "pair_correct": 0, "youden": 0.0 } + } + } +} +``` + +Exact counts are not a contract; presence of both objects is. + +## Error Handling + +- Missing vfc catalog file when loading the default catalog: fail tests (seed is required). Loading an explicit `--catalog` path does not auto-append vfc. +- Harvest HTTP failure: non-zero exit, no partial file without a provenance header. +- Advisory-only recipe: reject before fetch. +- Overlay parse_failed / language_unsupported: inventory fallback (existing sast behavior). + +## Testing Strategy + +- Unit: harvest brace-extract on a fixture string; catalog load sees three project names; provenance fields non-empty. +- Integration: `evaluate_catalog(select_slice(..., "vfc"))` returns three outcomes and both scorers; pair_gate still passed. +- CLI: `main(["pairs", "--slice", "vfc", "--json"])` == 0. +- Regression: `LANGUAGE_MANIFESTS` leak check includes vfc names; extra-free suite still green. + +## Security Considerations + +- Vendored excerpts are public historical vuln code with license headers. Do not vendor exploit PoCs (Chromium FileReader exploit HTML is out of scope; only the C++ function). +- Harvest talks only to listed public hosts. No Bugzilla credentials. No FixFox. + +## Supporting References + +Seed commit identifiers are recorded in `research.md` and must appear in the vendored headers at implementation time. diff --git a/.kiro/specs/real-world-vfc-slice/requirements.md b/.kiro/specs/real-world-vfc-slice/requirements.md new file mode 100644 index 0000000..2473083 --- /dev/null +++ b/.kiro/specs/real-world-vfc-slice/requirements.md @@ -0,0 +1,91 @@ +# Requirements Document + +## Introduction + +AppSec engineers cannot tell whether OpenUltraSAST improved on real product code. The labeled pair slices today are in-tree fixtures (`local`), small GitHub/SVEN functions (`github`), and textbook OWASP/Juliet files (`sast`). Operators care whether the harness fires on a real buggy snapshot of OpenSSL, Firefox, or Chromium and stays quiet after the patch. This spec adds a reviewed, isolated-function **vfc** slice drawn from public vulnerability-fixing commits in those projects, scored as an honesty dashboard (not a merge gate), so the tool can be evolved against labeled product code instead of cheat-sheet recall. + +## Boundary Context + +- **In scope**: A new pair slice of reviewed isolated function pairs from OpenSSL, Firefox (gecko-dev / mozilla-central / mozilla-firefox/firefox), and Chromium; provenance on every vendored file; overlay-versus-inventory scoreboard on that slice; a harvest procedure that does not clone megarepos; offline runnable catalog; testability of catalog load and slice evaluation. +- **Out of scope**: Cloning mozilla-central or Chromium into the repository or CI; FixFox (embargoed until 2030); live Bugzilla scraping; making overlay or vfc Youden a merge or smoke gate; buffer-size / CWE-121 semantics; inter-file taint; parser packaging; changing pattern inventory rules so the seed pairs pass. +- **Adjacent expectations**: Existing pair evaluation still scores `local` as the 100% CI gate and `github` / `sast` as honesty dashboards. Overlay dispositions, taint, and the stage-1 detection gate stay owned by their current specs. Dataset pointers may list Firefox/Chromium/OpenSSL sources; the dumps themselves are not vendored. + +## Requirements + +### Requirement 1: Seed vfc slice from OpenSSL, Firefox, and Chromium + +**Objective:** As an AppSec engineer, I want a labeled vuln-versus-fix slice from OpenSSL, Firefox, and Chromium, so that I can measure the harness on real product functions instead of only textbook files. + +#### Acceptance Criteria + +1. When an operator requests the vfc pair slice, OpenUltraSAST shall evaluate a catalog of isolated vuln-versus-fix pairs whose slice name is `vfc`. +2. The vfc slice shall include at least one reviewed pair whose origin project is OpenSSL, at least one whose origin project is Firefox, and at least one whose origin project is Chromium. +3. When the default pair catalog is loaded, the system shall include the vfc pairs together with the existing local, github, and sast pairs. +4. If a candidate has only an advisory write-up and no public version-control commit for both the vulnerable and fixed snapshots, then the system shall not accept that candidate as a vfc pair. + +### Requirement 2: Provenance on every vendored pair + +**Objective:** As a maintainer, I want every vfc file to carry repo, commit, identifier, and license, so that labels can be audited and redistributed legally. + +#### Acceptance Criteria + +1. When a vfc pair is vendored, the system shall record the source repository, the fixing commit identifier, a public commit URL, the CVE or equivalent public identifier when one exists, and the license of the original file. +2. When a vfc source file is stored in the catalog, the file shall contain a human-readable provenance header with those same fields. +3. The system shall use the same relative path on the vulnerable snapshot and the fixed snapshot of a pair. +4. If license information cannot be stated for a candidate, then the system shall not vendor that candidate. + +### Requirement 3: Honesty dashboard, not a merge gate + +**Objective:** As a developer merging changes, I want vfc misses and leaks to be visible without failing CI, so that real-project honesty cannot be gamed by blocking the merge. + +#### Acceptance Criteria + +1. When the pair efficiency gate runs, the system shall not fail because a vfc pair is a miss or a leak. +2. The system shall not add vfc pair names to the stage-1 detection smoke-gate fixture list. +3. When an operator evaluates the vfc slice, the system shall report pair-correct, vuln-side detection, silent-on-fix, and Youden for that slice. +4. The system shall not require the vfc slice to reach a 100% pair-correct rate, and shall not treat overlay or vfc Youden as a merge condition. + +### Requirement 4: Overlay versus inventory scoreboard + +**Objective:** As an engineer evolving adjudication, I want inventory and overlay scores side by side on the vfc slice, so that I can see whether the overlay helped or hurt on real product functions. + +#### Acceptance Criteria + +1. When an operator evaluates the vfc slice, the system shall report inventory scoring and overlay scoring for that slice as separate scoreboard figures. +2. Where overlay cannot adjudicate a vfc file, the overlay scoreboard shall fall back to inventory for that pair rather than recording silence as safety. +3. The system shall not replace the local-slice pair gate with overlay or vfc Youden. +4. When the vfc scoreboard is emitted as machine-readable output, both scorers shall be present so a later run can be compared without re-deriving the split. + +### Requirement 5: Harvest without megarepos or embargoed dumps + +**Objective:** As a maintainer, I want a repeatable way to add reviewed pairs from public commits, so that the catalog can grow without vendoring Firefox, Chromium, or 16 GB VFC dumps. + +#### Acceptance Criteria + +1. The system shall provide a harvest procedure that fetches a named file at a parent commit and a fixing commit from a public host and extracts one function into the vuln and fixed snapshots. +2. When harvest runs, the system shall not require a full clone of mozilla-central, gecko-dev, or Chromium to produce a pair. +3. The system shall not vendor FixFox or other embargoed datasets. +4. DiverseVul-style automatic vulnerable labels shall not be treated as ground truth unless a human review step has accepted the pair. +5. The runnable catalog that CI evaluates shall remain a small reviewed set (on the order of tens of pairs, not thousands). + +### Requirement 6: Isolated, reviewed functions the overlay can be honest about + +**Objective:** As an operator, I want each pair to be a single isolated function with a reviewed label, so that a miss or leak is attributable to the harness rather than to an unlabeled megatree. + +#### Acceptance Criteria + +1. When a vfc pair is evaluated, the scanner shall see only the vulnerable file or only the fixed file, never both in the same tree. +2. Each vfc pair shall isolate the changed function (plus the minimum types or stubs needed to keep that function intact), not an entire project tree. +3. The catalog shall prefer injection, XSS, or path-traversal pairs when a public commit exists, and may include memory-safety pairs as known inventory-only leaks until a later memory-safety spec. +4. A maintainer shall be able to read the expected CWE, sink, and evidence for each seed pair. + +### Requirement 7: Slice is testable offline + +**Objective:** As a maintainer, I want CI to prove the vfc catalog loads and the slice command runs without network access, so that the labeled corpus cannot rot unnoticed. + +#### Acceptance Criteria + +1. When the test suite loads the default pair catalog, it shall observe vfc among the slice names and shall observe that every vfc vuln file and fixed file exists on disk. +2. When an operator runs the pairs command for slice `vfc`, the command shall complete and emit a scoreboard that includes the OpenSSL, Firefox, and Chromium seed pair names. +3. If the semantic extra is absent, then vfc evaluation shall still complete (via inventory fallback) rather than fail the extra-free suite. +4. The extra-free detection smoke gate shall still ignore vfc pair names and vfc Youden. diff --git a/.kiro/specs/real-world-vfc-slice/research.md b/.kiro/specs/real-world-vfc-slice/research.md new file mode 100644 index 0000000..eee30e3 --- /dev/null +++ b/.kiro/specs/real-world-vfc-slice/research.md @@ -0,0 +1,106 @@ +# Research & Design Decisions + +## Summary + +- **Feature**: `real-world-vfc-slice` +- **Discovery Scope**: Extension of the existing pair catalog and pair eval CLI +- **Key Findings**: + - Pair eval already concatenates `benchmarks/pairs/catalog.toml` with `sast/catalog.toml`. A third file `vfc/catalog.toml` is the smallest seam. + - CLI `--slice` choices are a closed set (`all`, `local`, `github`, `sast`). `vfc` must be added there and in tests that assert slice names. + - `sast` already scores overlay with inventory fallback when nothing is promoted or demoted. `vfc` should use that path as the primary scorer and add a second inventory-only figure for the honesty dashboard. + - `pair_gate` evaluates the full catalog but fails CI only on `local` 100%. Adding vfc pairs does not change the fail condition if names stay out of `LANGUAGE_MANIFESTS`. + - Seed commits with public VCS snapshots exist: OpenSSL Heartbleed (`tls1_process_heartbeat`), Firefox libmar (`mar_insert_item`, CVE-2020-15667), Chromium FileReader (`ArrayBufferResult`, CVE-2019-5786). All three keep a sink-shaped call after the fix, so overlay/inventory may LEAK — that is the dashboard, not a 100% gate. + - mozilla-central / gecko-dev must not be cloned. Phabricator and GitHub raw blobs are enough to extract one function. FixFox stays embargoed. + +## Research Log + +### Existing pair catalog and scoring + +- **Context**: Brownfield extension; must not invent a second eval engine. +- **Sources Consulted**: `src/openultrasast/pairs.py`, `cli.py`, `pair_gate.py`, `tests/test_pair_corpus.py`, `benchmarks/pairs/catalog.toml`, `benchmarks/pairs/sast/catalog.toml`, `benchmarks/pairs/README.md` +- **Findings**: + - `PairCase.slice` is a free string in the catalog loader; the closed set lives only in argparse and tests. + - Overlay pair eval is gated on `case.slice == "sast"`. + - GitHub pairs already use provenance comments plus catalog fields (`repo`, `commit`, `commit_url`, `cve`, `license`). + - Pair names must not appear in `LANGUAGE_MANIFESTS`. +- **Implications**: Add `vfc` as a concatenated catalog; extend the overlay branch to `sast` **or** `vfc`; keep the gate local-only. + +### Harvestable public commits (OpenSSL, Firefox, Chromium) + +- **Context**: User asked for those three projects and a labeled corpus that can actually be tested. +- **Sources Consulted**: + - OpenSSL `96db9023b881d7cd9f379b0c154650d6c108e9a3` (parent `0d7717fc9c83dafab8153cbd5e2180e6e04cc802`), `ssl/t1_lib.c` `tls1_process_heartbeat`, CVE-2014-0160 + - Firefox hg `b79b6cc78248eea7fda10bfb76aa273c19c9fa65` (parent `0c0f777161a9499dd149853ff62d356f75d16c2a`), `modules/libmar/src/mar_read.c` `mar_insert_item`, CVE-2020-15667 / Bug 1653371; Phabricator raw diff + - Chromium `ba9748e78ec7e9c0d594e7edf7b2c07ea2a90449` (parent `9f3fccdba567f30ea39b08f57d8d5b49cd832b4a`), `FileReaderLoader::ArrayBufferResult`, CVE-2019-5786 + - Rejected: CVE-2019-11730 (SOP/file URI policy, not a sink pair); FixFox (embargoed to 2030); MFSA text without a commit +- **Findings**: + - Heartbleed fix adds a record-length check; `memcpy(bp, pl, payload)` remains. Inventory `c-unsafe-memory-copy` will fire on both sides (LEAK) until CWE-121 semantics exist. + - Firefox fix is `int namelen` → `uint32_t namelen`; `memcpy(item->name, name, namelen + 1)` remains. Same LEAK class. + - Chromium fix copies the ArrayBuffer on partial results (UAF). No memcpy/eval sink; expected MISS on inventory and overlay. Still a labeled pair. + - GitHub raw and Phabricator `?diff=1` return the function text without cloning. +- **Implications**: Seed three reviewed pairs. Tests assert presence and that the slice **runs**, not that pair_correct is 100%. Memory-safety pairs are allowed as known leaks (Req 6.3). + +### Dataset pointers versus vendored dumps + +- **Context**: `datasets.toml` already lists CVEfixes, MoreFixes, SVEN, CWE-Bench-Java. Roadmap asked for Firefox/Chromium/OpenSSL pointers. +- **Findings**: Pointers are metadata only. CI must stay offline on vendored excerpts. +- **Implications**: Add dataset rows for OpenSSL, gecko-dev / mozilla-firefox/firefox, and Chromium. Do not fetch dumps in tests. + +## Architecture Pattern Evaluation + +| Option | Description | Strengths | Risks / Limitations | Notes | +|--------|-------------|-----------|---------------------|-------| +| Concatenate a `vfc` catalog like `sast` | Third TOML file, same `[[pair]]` schema | Matches existing loader; no new types | CLI choices and tests must be updated | **Selected** | +| Stuff vfc rows into `catalog.toml` | One file | Fewer paths | Mixes local/github with large-project VFCs | Rejected; sast already split | +| New eval package | Separate scorer | Clean isolation | Duplicates pair eval | Rejected | +| Clone megarepos in CI | Scan real trees | Maximum fidelity | Multi-GB, scrubbed commit messages, not isolated | Explicitly out of scope | + +## Design Decisions + +### Decision: Concatenated `vfc` catalog, overlay primary, inventory sidecar + +- **Context**: Need a labeled corpus that is offline, isolated, and honest about overlay versus regex. +- **Alternatives Considered**: + 1. Inventory-only like `github` — misses the overlay question the user is evolving. + 2. Overlay-only like `sast` without a sidecar — cannot see whether overlay helped or hurt. + 3. Dual scoreboard with overlay primary and inventory sidecar — **selected**. +- **Selected Approach**: `slice = "vfc"` uses the overlay pair path (inventory fallback when unadjudicated). `PairEvalResult.scorers["vfc"]` holds both `overlay` and `inventory` metrics. Pair gate still fails only on `local`. +- **Rationale**: Reuses `sast` overlay machinery; satisfies Req 4 without making Youden a merge gate. +- **Trade-offs**: Pair gate runtime grows by three small overlay scans. Acceptable. +- **Follow-up**: Do not retune memcpy rules to force these pairs to PASS. + +### Decision: Maintainer harvest script, vendored seed, no CI fetch + +- **Context**: Grow the catalog later without cloning mozilla-central. +- **Selected Approach**: `benchmarks/pairs/vfc/harvest.py` plus `recipes.toml`. CI never runs harvest. Seed files are committed excerpts with provenance headers. +- **Rationale**: Req 5 and Req 7 (offline testability). +- **Trade-offs**: Harvest needs network when a maintainer grows the set; tests mock extraction locally. + +### Decision: Public hg counts as a version-control commit + +- **Context**: Firefox canonical history is hg.mozilla.org; gecko-dev git SHAs are not the hg SHAs; GitHub 422s on hg identifiers. +- **Selected Approach**: Record the hg revision and Phabricator/hg URL. Dataset pointers still list gecko-dev and mozilla-firefox/firefox. +- **Rationale**: Brief forbids MFSA-without-commit, not hg. The MAR fix is a public VCS snapshot. +- **Follow-up**: If a git SHA is later mapped, add it as an extra catalog field without changing the excerpt. + +## Synthesis + +- **Generalization**: `vfc` is another honesty slice, not a new product. Overlay-versus-inventory is a report field, not a new engine. +- **Build vs adopt**: Adopt pair catalog schema, overlay eval, provenance comment style. Build only harvest extract + dual scoreboard payload. +- **Simplification**: No Joern, no megarepo, no 90% gate, no rule changes to chase Youden on three memory/UAF pairs. + +## Risks & Mitigations + +- Overlay/inventory LEAK on Heartbleed and MAR memcpy-after-fix — document as known; tests must not assert PASS. +- Chromium UAF is a MISS — still required so the corpus is not only memcpy. +- `pair_gate` currently scans the full catalog; three extra pairs are small. If the catalog grows, gate should keep evaluating local-only for the fail condition (already true) and may later skip overlay slices for speed. +- License: OpenSSL (OpenSSL License / SSLeay), Firefox MPL-2.0, Chromium BSD-3-Clause — headers must state them. +- gecko-dev is archived; harvest should accept hg.mozilla.org and github.com/chromium/chromium / openssl/openssl as hosts. + +## References + +- [OpenSSL Heartbleed fix](https://github.com/openssl/openssl/commit/96db9023b881d7cd9f379b0c154650d6c108e9a3) — CVE-2014-0160 +- [Firefox MAR heap overflow](https://bugzilla.mozilla.org/show_bug.cgi?id=1653371) — CVE-2020-15667, hg `b79b6cc78248` +- [Chromium FileReader UAF](https://github.com/chromium/chromium/commit/ba9748e78ec7e9c0d594e7edf7b2c07ea2a90449) — CVE-2019-5786 +- `.kiro/specs/real-world-vfc-slice/brief.md` +- `.kiro/steering/roadmap.md` diff --git a/.kiro/specs/real-world-vfc-slice/spec.json b/.kiro/specs/real-world-vfc-slice/spec.json new file mode 100644 index 0000000..778338e --- /dev/null +++ b/.kiro/specs/real-world-vfc-slice/spec.json @@ -0,0 +1,22 @@ +{ + "feature_name": "real-world-vfc-slice", + "created_at": "2026-09-04T13:19:17Z", + "updated_at": "2026-09-04T13:40:00Z", + "language": "en", + "phase": "implementation", + "approvals": { + "requirements": { + "generated": true, + "approved": true + }, + "design": { + "generated": true, + "approved": true + }, + "tasks": { + "generated": true, + "approved": true + } + }, + "ready_for_implementation": true +} diff --git a/.kiro/specs/real-world-vfc-slice/tasks.md b/.kiro/specs/real-world-vfc-slice/tasks.md new file mode 100644 index 0000000..e7820cd --- /dev/null +++ b/.kiro/specs/real-world-vfc-slice/tasks.md @@ -0,0 +1,79 @@ +# Implementation Plan + +- [x] 1. Foundation: vfc catalog load and slice command +- [x] 1.1 Load a vfc catalog and accept slice vfc on the pairs command + - Default pair catalog load includes a vfc catalog file the same way it already includes the sast catalog. + - The pairs command accepts slice `vfc` in addition to all, local, github, and sast. + - Dataset pointers name OpenSSL, Firefox/gecko-dev, and Chromium without vendoring those trees. + - An empty or seed-ready vfc catalog file exists so load does not skip the slice by omission. + - Observable: `ousast pairs --slice vfc --json` exits 0 and the loaded slice set can contain `vfc`. + - _Requirements: 1.1, 1.3, 7.2_ + - _Boundary: VfcCatalog_ + +- [x] 2. Core: reviewed seed pairs +- [x] 2.1 Vendor the OpenSSL Heartbleed function pair + - Isolated `tls1_process_heartbeat` before and after the public Heartbleed fix, same relative path. + - Provenance header and catalog row include repo, commit, parent, public commit URL, CVE-2014-0160, and license. + - Expected CWE/sink/evidence are stated; memcpy remaining after the fix is an accepted honesty leak, not a reason to change inventory rules. + - Observable: catalog load yields a vfc pair whose name identifies OpenSSL and whose vuln and fixed files exist. + - _Requirements: 1.2, 1.4, 2.1, 2.2, 2.3, 2.4, 6.1, 6.2, 6.3, 6.4_ + - _Boundary: SeedExcerpts_ + - _Depends: 1.1_ + +- [x] 2.2 Vendor the Firefox libmar function pair + - Isolated `mar_insert_item` before and after the public CVE-2020-15667 commit, same relative path. + - Provenance records the mozilla-central revision and public commit URL (hg or Phabricator is acceptable; MFSA-only is not). + - License is MPL-2.0; expected CWE/sink/evidence are stated. + - Observable: catalog load yields a vfc pair whose name identifies Firefox and whose files exist. + - _Requirements: 1.2, 1.4, 2.1, 2.2, 2.3, 2.4, 6.1, 6.2, 6.3, 6.4_ + - _Boundary: SeedExcerpts_ + - _Depends: 1.1_ + +- [x] 2.3 Vendor the Chromium FileReader function pair + - Isolated `ArrayBufferResult` before and after the public CVE-2019-5786 commit, same relative path. + - Provenance header and catalog row include chromium repo, commit, parent, commit URL, CVE, and BSD-3-Clause. + - UAF-without-inventory-sink is an accepted honesty miss; do not vendor exploit HTML. + - Observable: catalog load yields a vfc pair whose name identifies Chromium and whose files exist. + - _Requirements: 1.2, 1.4, 2.1, 2.2, 2.3, 2.4, 6.1, 6.2, 6.3, 6.4_ + - _Boundary: SeedExcerpts_ + - _Depends: 1.1_ + +- [x] 3. Harvest without megarepos +- [x] 3.1 (P) Add a maintainer harvest procedure that extracts one function + - A recipe names parent commit, fix commit, path, function, CVE, and license; advisory-only recipes are rejected. + - Harvest fetches blobs over HTTP and writes provenance-headed excerpts; it does not clone mozilla-central, gecko-dev, or Chromium. + - FixFox and other embargoed dumps are not referenced as fetch sources. + - Function extract is unit-tested on a local string so CI stays offline. + - Observable: harvest extract on a fixture function round-trips the function body; pytest does not perform a live fetch. + - _Requirements: 1.4, 5.1, 5.2, 5.3, 5.4, 5.5, 7.3_ + - _Boundary: HarvestTool_ + - _Depends: 1.1_ + +- [x] 4. Integration: overlay versus inventory scoreboard +- [x] 4.1 Score vfc with overlay primary and inventory sidecar + - vfc pairs use the overlay pair path with inventory fallback when overlay does not adjudicate. + - Machine-readable pairs output includes `scorers.vfc.overlay` and `scorers.vfc.inventory`. + - Primary `per_slice.vfc` matches the overlay scorer. + - Pair gate fail reasons stay local-only; vfc Youden is not a merge condition. + - Observable: `ousast pairs --slice vfc --json` contains both scorer objects and the OpenSSL, Firefox, and Chromium pair names. + - _Requirements: 3.3, 3.4, 4.1, 4.2, 4.3, 4.4, 7.2_ + - _Boundary: DualScorer_ + - _Depends: 1.1, 2.1, 2.2, 2.3_ + +- [x] 5. Validation: honesty gates and offline tests +- [x] 5.1 Prove vfc is testable and is not a smoke or merge gate + - Default catalog load sees slice `vfc` and every vfc file on disk. + - vfc pair names are absent from the stage-1 detection fixture list. + - Pair efficiency gate still passes on local 100% with vfc present. + - Tests do not require 100% vfc pair_correct or a Youden floor. + - Extra-free evaluation still completes. + - Observable: extra-free pytest covering catalog load, gate pass, and vfc JSON is green. + - _Requirements: 3.1, 3.2, 3.4, 5.5, 7.1, 7.3, 7.4_ + - _Boundary: VfcTestMatrix, PairGatePolicy_ + - _Depends: 4.1_ + +## Implementation Notes + +- Seed commits: OpenSSL `96db9023b881d7cd9f379b0c154650d6c108e9a3` (parent `0d7717fc9c83dafab8153cbd5e2180e6e04cc802`); Firefox hg `b79b6cc78248eea7fda10bfb76aa273c19c9fa65` (parent `0c0f777161a9499dd149853ff62d356f75d16c2a`); Chromium `ba9748e78ec7e9c0d594e7edf7b2c07ea2a90449` (parent `9f3fccdba567f30ea39b08f57d8d5b49cd832b4a`). +- Do not retune `c-unsafe-memory-copy` to make Heartbleed or MAR pair_correct. +- Do not clone mozilla-central; do not vendor FixFox. diff --git a/.kiro/steering/roadmap.md b/.kiro/steering/roadmap.md index ce657d9..62639df 100644 --- a/.kiro/steering/roadmap.md +++ b/.kiro/steering/roadmap.md @@ -39,9 +39,9 @@ OpenUltraSAST can propose sinks with regex and prove a few of them in a sandbox, ## Direct Implementation Candidates - [ ] Record inventory vs overlay Youden side-by-side in `ousast pairs --slice sast` JSON (small report field, not a new spec). -- [ ] Add Firefox/gecko-dev, Chromium, OpenSSL pointers to `benchmarks/pairs/datasets.toml`. +- [x] Add Firefox/gecko-dev, Chromium, OpenSSL pointers to `benchmarks/pairs/datasets.toml`. ## Specs (dependency order) -- [ ] tree-sitter-overlay-extra -- Optional extra: tree-sitter + grammars, one CST walker, `quick` stays zero-dep. Dependencies: none -- [ ] real-world-vfc-slice -- Harvest reviewed function-level vuln/fix pairs from large projects (Firefox/gecko-dev, Chromium, OpenSSL, …) as an honesty slice. Dependencies: none +- [x] tree-sitter-overlay-extra -- Optional extra: tree-sitter + grammars, one CST walker, `quick` stays zero-dep. Dependencies: none +- [x] real-world-vfc-slice -- Harvest reviewed function-level vuln/fix pairs from large projects (Firefox/gecko-dev, Chromium, OpenSSL, …) as an honesty slice. Seed is testable (`ousast pairs --slice vfc`). Dependencies: none diff --git a/benchmarks/pairs/README.md b/benchmarks/pairs/README.md index 348159d..2b20eb6 100644 --- a/benchmarks/pairs/README.md +++ b/benchmarks/pairs/README.md @@ -34,12 +34,19 @@ Pairs in this directory **must not** join `LANGUAGE_MANIFESTS`. - **sast** — OWASP Benchmark Java/Python true-vs-false files and Juliet bad-vs-good sinks (`benchmarks/pairs/sast/`). Score is Youden (TPR − FPR). Honesty dashboard, not a CI fail. +- **vfc** — reviewed isolated functions from OpenSSL, Firefox, Chromium, and + curl (`benchmarks/pairs/vfc/`). Overlay vs inventory scoreboard. Honesty + dashboard, not a CI fail. Training labels (vuln vs fixed) are + `vfc/training/manifest.jsonl` (vuln vs fixed, one snapshot per line). + Grow with a blobless `git log --grep=CVE-202` mine plus `vfc/harvest.py`, + then `vfc/generate_catalog.py` (maintainer, not CI). ## Commands ```bash uv run ousast pairs uv run ousast pairs --slice github --json +uv run ousast pairs --slice vfc --json uv run python -m openultrasast.pair_gate ``` diff --git a/benchmarks/pairs/datasets.toml b/benchmarks/pairs/datasets.toml index dacec5d..7bbb9e8 100644 --- a/benchmarks/pairs/datasets.toml +++ b/benchmarks/pairs/datasets.toml @@ -122,3 +122,32 @@ url = "https://github.com/tqrg/security-patches-dataset" level = "commit" languages = ["multi"] notes = "Ground-truth security patches mined from NVD, CVE Details, OSV." + +[[dataset]] +name = "OpenSSL" +url = "https://github.com/openssl/openssl" +level = "commit/function" +languages = ["C"] +notes = "Public git. Seed: CVE-2014-0160 tls1_process_heartbeat. Do not vendor the whole tree; harvest isolated functions." + +[[dataset]] +name = "Firefox mozilla-central" +url = "https://hg.mozilla.org/mozilla-central" +data = "https://github.com/mozilla-firefox/firefox" +level = "commit/function" +languages = ["C/C++", "JavaScript"] +notes = "Canonical VCS is hg.mozilla.org; git mirrors are gecko-dev (archived) and mozilla-firefox/firefox. Filter CVEfixes/MoreFixes for gecko-dev. Do not clone mozilla-central. FixFox is embargoed until 2030. Seed: CVE-2020-15667 mar_insert_item." + +[[dataset]] +name = "Chromium" +url = "https://github.com/chromium/chromium" +level = "commit/function" +languages = ["C/C++", "JavaScript"] +notes = "Public git mirror of chromium/src. Seed: CVE-2019-5786 FileReaderLoader::ArrayBufferResult. Do not vendor the whole tree." + +[[dataset]] +name = "curl" +url = "https://github.com/curl/curl" +level = "commit/function" +languages = ["C"] +notes = "Public git. Seed: CVE-2023-38545 do_SOCKS5. Isolated functions only; do not vendor the tree." diff --git a/benchmarks/pairs/vfc/catalog.toml b/benchmarks/pairs/vfc/catalog.toml new file mode 100644 index 0000000..bf2e782 --- /dev/null +++ b/benchmarks/pairs/vfc/catalog.toml @@ -0,0 +1,4408 @@ +# Real-world VFC slice. Reviewed isolated functions. +# Honesty dashboard — not the local 100% CI gate. +# Do not add these names to LANGUAGE_MANIFESTS. +# Regenerated by generate_catalog.py from recipes.toml. + +[[pair]] +name = "openssl-cve-2014-0160" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2014-0160" +cwe = "CWE-126" +commit = "96db9023b881d7cd9f379b0c154650d6c108e9a3" +parent = "0d7717fc9c83dafab8153cbd5e2180e6e04cc802" +commit_url = "https://github.com/openssl/openssl/commit/96db9023b881d7cd9f379b0c154650d6c108e9a3" +vuln = "openssl-cve-2014-0160/vuln.c" +fixed = "openssl-cve-2014-0160/fixed.c" +relpath = "ssl/t1_lib.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-126" +class = "buffer over-read" +path = "ssl/t1_lib.c" +rule_id = "c-unsafe-memory-copy" +sink = "memcpy" +evidence = "memcpy copies heartbeat payload using an attacker-controlled length" + +[[pair]] +name = "firefox-cve-2020-15667" +slice = "vfc" +language = "c_cpp" +origin = "mozilla-central" +license = "MPL-2.0" +repo = "mozilla-central" +cve = "CVE-2020-15667" +cwe = "CWE-119" +commit = "b79b6cc78248eea7fda10bfb76aa273c19c9fa65" +parent = "0c0f777161a9499dd149853ff62d356f75d16c2a" +commit_url = "https://hg.mozilla.org/mozilla-central/rev/b79b6cc78248eea7fda10bfb76aa273c19c9fa65" +vuln = "firefox-cve-2020-15667/vuln.c" +fixed = "firefox-cve-2020-15667/fixed.c" +relpath = "modules/libmar/src/mar_read.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "buffer overflow" +path = "modules/libmar/src/mar_read.c" +rule_id = "c-unsafe-memory-copy" +sink = "memcpy" +evidence = "memcpy copies a MAR index name using a signed namelen that can wrap" + +[[pair]] +name = "chromium-cve-2019-5786" +slice = "vfc" +language = "c_cpp" +origin = "chromium" +license = "BSD-3-Clause" +repo = "chromium/chromium" +cve = "CVE-2019-5786" +cwe = "CWE-416" +commit = "ba9748e78ec7e9c0d594e7edf7b2c07ea2a90449" +parent = "9f3fccdba567f30ea39b08f57d8d5b49cd832b4a" +commit_url = "https://github.com/chromium/chromium/commit/ba9748e78ec7e9c0d594e7edf7b2c07ea2a90449" +vuln = "chromium-cve-2019-5786/vuln.cc" +fixed = "chromium-cve-2019-5786/fixed.cc" +relpath = "third_party/blink/renderer/core/fileapi/file_reader_loader.cc" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-416" +class = "use after free" +path = "third_party/blink/renderer/core/fileapi/file_reader_loader.cc" +rule_id = "c-unsafe-memory-copy" +sink = "ToArrayBuffer" +evidence = "ArrayBufferResult can return two references to the same underlying ArrayBuffer" + +[[pair]] +name = "openssl-cve-2020-1967" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2020-1967" +cwe = "CWE-476" +commit = "a87f3fe01a5a894aa27ccd6a239155fd129988e4" +parent = "3656c08ab4b1b892730cb5e808b6f4298b08a2e6" +commit_url = "https://github.com/openssl/openssl/commit/a87f3fe01a5a894aa27ccd6a239155fd129988e4" +vuln = "openssl-cve-2020-1967/vuln.c" +fixed = "openssl-cve-2020-1967/fixed.c" +relpath = "ssl/t1_lib.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-476" +class = "null pointer dereference" +path = "ssl/t1_lib.c" +sink = "tls1_check_sig_alg" +evidence = "SSL_check_chain / tls1_check_sig_alg can dereference NULL in TLS 1.3" + +[[pair]] +name = "openssl-cve-2020-1971" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2020-1971" +cwe = "CWE-476" +commit = "b33c48b75aaf33c93aeda42d7138616b9e6a64cb" +parent = "198b11683568452282bd48828fcf60d4835bf327" +commit_url = "https://github.com/openssl/openssl/commit/b33c48b75aaf33c93aeda42d7138616b9e6a64cb" +vuln = "openssl-cve-2020-1971/vuln.c" +fixed = "openssl-cve-2020-1971/fixed.c" +relpath = "crypto/x509/v3_genn.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-476" +class = "null pointer dereference" +path = "crypto/x509/v3_genn.c" +sink = "GENERAL_NAME_cmp" +evidence = "GENERAL_NAME_cmp mishandles EdiPartyName comparison" + +[[pair]] +name = "openssl-cve-2021-23840" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2021-23840" +cwe = "CWE-190" +commit = "c9fb704cf3af5524eb8e79961e31b60eee8c3c47" +parent = "c1ddd392cf9737c09c1f9bf690adfbe596403c5e" +commit_url = "https://github.com/openssl/openssl/commit/c9fb704cf3af5524eb8e79961e31b60eee8c3c47" +vuln = "openssl-cve-2021-23840/vuln.c" +fixed = "openssl-cve-2021-23840/fixed.c" +relpath = "crypto/evp/evp_enc.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-190" +class = "integer overflow" +path = "crypto/evp/evp_enc.c" +sink = "EVP_CipherUpdate" +evidence = "EVP_CipherUpdate output length can overflow" + +[[pair]] +name = "openssl-cve-2021-3711" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2021-3711" +cwe = "CWE-120" +commit = "59f5e75f3bced8fc0e130d72a3f582cf7b480b46" +parent = "8c74c9d1ade0fbdab5b815ddb747351b8b839641" +commit_url = "https://github.com/openssl/openssl/commit/59f5e75f3bced8fc0e130d72a3f582cf7b480b46" +vuln = "openssl-cve-2021-3711/vuln.c" +fixed = "openssl-cve-2021-3711/fixed.c" +relpath = "crypto/sm2/sm2_crypt.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-120" +class = "buffer overflow" +path = "crypto/sm2/sm2_crypt.c" +sink = "sm2_decrypt" +evidence = "SM2 plaintext size is underestimated so the second EVP_PKEY_decrypt overflows" + +[[pair]] +name = "openssl-cve-2021-3712" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2021-3712" +cwe = "CWE-125" +commit = "98624776c4d501c8badd6f772ab7048ac9191cb9" +parent = "1f365708a3318a5f1a395f90c38b584a58d37fb9" +commit_url = "https://github.com/openssl/openssl/commit/98624776c4d501c8badd6f772ab7048ac9191cb9" +vuln = "openssl-cve-2021-3712/vuln.c" +fixed = "openssl-cve-2021-3712/fixed.c" +relpath = "crypto/x509/v3_utl.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-125" +class = "buffer over-read" +path = "crypto/x509/v3_utl.c" +sink = "append_ia5" +evidence = "append_ia5 assumes NUL-terminated ASN.1 strings" + +[[pair]] +name = "openssl-cve-2022-0778" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2022-0778" +cwe = "CWE-835" +commit = "9eafb53614bf65797db25f467946e735e1b43dc9" +parent = "1832bb0f02e519a48f06a10467c7ce5f7f3feeeb" +commit_url = "https://github.com/openssl/openssl/commit/9eafb53614bf65797db25f467946e735e1b43dc9" +vuln = "openssl-cve-2022-0778/vuln.c" +fixed = "openssl-cve-2022-0778/fixed.c" +relpath = "crypto/bn/bn_sqrt.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-835" +class = "infinite loop" +path = "crypto/bn/bn_sqrt.c" +sink = "BN_mod_sqrt" +evidence = "BN_mod_sqrt can loop forever on crafted moduli" + +[[pair]] +name = "openssl-cve-2022-1292" +slice = "vfc" +language = "unknown" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2022-1292" +cwe = "CWE-78" +commit = "1ad73b4d27bd8c1b369a3cd453681d3a4f1bb9b2" +parent = "7d56a74a96828985db7354a55227a511615f732b" +commit_url = "https://github.com/openssl/openssl/commit/1ad73b4d27bd8c1b369a3cd453681d3a4f1bb9b2" +vuln = "openssl-cve-2022-1292/vuln.in" +fixed = "openssl-cve-2022-1292/fixed.in" +relpath = "tools/c_rehash.in" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-78" +class = "command injection" +path = "tools/c_rehash.in" +sink = "backtick" +evidence = "c_rehash interpolates certificate filenames into a shell backtick command" + +[[pair]] +name = "openssl-cve-2022-3602" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2022-3602" +cwe = "CWE-787" +commit = "3b421ebc64c7b52f1b9feb3812bdc7781c784332" +parent = "89d72311327735ef15c804d2adea84a0fb1bfa0a" +commit_url = "https://github.com/openssl/openssl/commit/3b421ebc64c7b52f1b9feb3812bdc7781c784332" +vuln = "openssl-cve-2022-3602/vuln.c" +fixed = "openssl-cve-2022-3602/fixed.c" +relpath = "crypto/punycode.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-787" +class = "buffer overflow" +path = "crypto/punycode.c" +sink = "ossl_punycode_decode" +evidence = "punycode decoder can write past the output buffer" + +[[pair]] +name = "openssl-cve-2022-3786" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2022-3786" +cwe = "CWE-787" +commit = "680e65b94c916af259bfdc2e25f1ab6e0c7a97d6" +parent = "3b421ebc64c7b52f1b9feb3812bdc7781c784332" +commit_url = "https://github.com/openssl/openssl/commit/680e65b94c916af259bfdc2e25f1ab6e0c7a97d6" +vuln = "openssl-cve-2022-3786/vuln.c" +fixed = "openssl-cve-2022-3786/fixed.c" +relpath = "crypto/punycode.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-787" +class = "buffer overflow" +path = "crypto/punycode.c" +sink = "ossl_punycode_decode" +evidence = "punycode decoder can overflow a stack buffer via a crafted email name" + +[[pair]] +name = "openssl-cve-2023-0286" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2023-0286" +cwe = "CWE-843" +commit = "7880536fe17c2b5450e279155bedd51771d28c9f" +parent = "adf77d6657e836fc87391fad53d857927a764297" +commit_url = "https://github.com/openssl/openssl/commit/7880536fe17c2b5450e279155bedd51771d28c9f" +vuln = "openssl-cve-2023-0286/vuln.c" +fixed = "openssl-cve-2023-0286/fixed.c" +relpath = "crypto/x509/v3_genn.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-843" +class = "type confusion" +path = "crypto/x509/v3_genn.c" +sink = "GENERAL_NAME_cmp" +evidence = "GENERAL_NAME_cmp type-confuses x400Address" + +[[pair]] +name = "curl-cve-2023-38545" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2023-38545" +cwe = "CWE-122" +commit = "fb4415d8aee6c1045be932a34fe6107c2f5ed147" +parent = "09e25b9d94f4106eac8ca3a43b221bdc66f405e4" +commit_url = "https://github.com/curl/curl/commit/fb4415d8aee6c1045be932a34fe6107c2f5ed147" +vuln = "curl-cve-2023-38545/vuln.c" +fixed = "curl-cve-2023-38545/fixed.c" +relpath = "lib/socks.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-122" +class = "heap buffer overflow" +path = "lib/socks.c" +rule_id = "c-unsafe-memory-copy" +sink = "memcpy" +evidence = "SOCKS5 remote-resolve copies a hostname that can exceed the local buffer" + +[[pair]] +name = "chromium-cve-2022-2162" +slice = "vfc" +language = "c_cpp" +origin = "chromium" +license = "BSD-3-Clause" +repo = "chromium/chromium" +cve = "CVE-2022-2162" +cwe = "CWE-20" +commit = "22c61cfae5d1b37c773e638d342488ae11118b51" +parent = "a07d0ae0a7dc68686adca10dcf11138cb2f4ab6d" +commit_url = "https://github.com/chromium/chromium/commit/22c61cfae5d1b37c773e638d342488ae11118b51" +vuln = "chromium-cve-2022-2162/vuln.cc" +fixed = "chromium-cve-2022-2162/fixed.cc" +relpath = "content/browser/file_system_access/file_system_chooser.cc" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-20" +class = "insufficient input validation" +path = "content/browser/file_system_access/file_system_chooser.cc" +sink = "IsShellIntegratedExtension" +evidence = "File System Access suggested names did not sanitize Windows .url shell extensions" + +[[pair]] +name = "openssl-cve-2025-69421" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2025-69421" +cwe = "CWE-476" +commit = "2c13bf15286328641a805eb3b7c97e27d42881fb" +parent = "ea8fc4c345fbd749048809c9f7c881ea656b0b94" +commit_url = "https://github.com/openssl/openssl/commit/2c13bf15286328641a805eb3b7c97e27d42881fb" +vuln = "openssl-cve-2025-69421/vuln.c" +fixed = "openssl-cve-2025-69421/fixed.c" +relpath = "crypto/pkcs12/p12_decr.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-476" +class = "null pointer dereference" +path = "crypto/pkcs12/p12_decr.c" +sink = "PKCS12_item_decrypt_d2i_ex" +evidence = "PKCS12_item_decrypt_d2i_ex did not check a NULL oct argument" + +[[pair]] +name = "openssl-cve-2025-66199" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2025-66199" +cwe = "CWE-770" +commit = "84f73f79af9f69c1527a9a372b7a9e771a394c2a" +parent = "b21663c35a6f0ed4c8de06855bdc7a6a21f00c2f" +commit_url = "https://github.com/openssl/openssl/commit/84f73f79af9f69c1527a9a372b7a9e771a394c2a" +vuln = "openssl-cve-2025-66199/vuln.c" +fixed = "openssl-cve-2025-66199/fixed.c" +relpath = "ssl/statem/statem_lib.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-770" +class = "uncontrolled allocation" +path = "ssl/statem/statem_lib.c" +sink = "tls13_process_compressed_certificate" +evidence = "TLS 1.3 compressed certificate length was trusted before allocation" + +[[pair]] +name = "firefox-bug-2058173" +slice = "vfc" +language = "c_cpp" +origin = "mozilla-firefox/firefox" +license = "MPL-2.0" +repo = "mozilla-firefox/firefox" +cve = "BUG-2058173" +cwe = "CWE-770" +commit = "e46f28da1cd3a5d46a2680b3d87361e9e8de4ae6" +parent = "eed0931f85474d0db6e2326dfd9718c6bf1cd418" +commit_url = "https://github.com/mozilla-firefox/firefox/commit/e46f28da1cd3a5d46a2680b3d87361e9e8de4ae6" +vuln = "firefox-bug-2058173/vuln.c" +fixed = "firefox-bug-2058173/fixed.c" +relpath = "modules/libmar/src/mar_read.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-770" +class = "uncontrolled allocation" +path = "modules/libmar/src/mar_read.c" +sink = "malloc" +evidence = "mar_read_index malloc'd an untrusted MAR index size with no upper bound" + +[[pair]] +name = "openssl-cve-2026-18798" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-18798" +cwe = "CWE-119" +commit = "70cebd74d3592f5272945501b58a60374c4e13af" +parent = "48f5785425ee6b5316f8e5f921978397ba632cc6" +commit_url = "https://github.com/openssl/openssl/commit/70cebd74d3592f5272945501b58a60374c4e13af" +vuln = "openssl-cve-2026-18798/vuln.c" +fixed = "openssl-cve-2026-18798/fixed.c" +relpath = "ssl/quic/quic_port.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/quic/quic_port.c" +sink = "unknown" +evidence = "Avoid double free of qrx in port_default_packet_handler()" + +[[pair]] +name = "openssl-cve-2026-54874" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-54874" +cwe = "CWE-119" +commit = "1ca5a124b48f1ffe6980ad33724b452fbd62da1e" +parent = "a0c8ec557d9cac078f032d76cdf684fe743eb382" +commit_url = "https://github.com/openssl/openssl/commit/1ca5a124b48f1ffe6980ad33724b452fbd62da1e" +vuln = "openssl-cve-2026-54874/vuln.c" +fixed = "openssl-cve-2026-54874/fixed.c" +relpath = "ssl/record/rec_layer_d1.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/record/rec_layer_d1.c" +sink = "unknown" +evidence = "Avoid full read buffer allocation when buffering DTLS records" + +[[pair]] +name = "openssl-cve-2026-54874-dtls1_process_record" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-54874" +cwe = "CWE-119" +commit = "1ca5a124b48f1ffe6980ad33724b452fbd62da1e" +parent = "a0c8ec557d9cac078f032d76cdf684fe743eb382" +commit_url = "https://github.com/openssl/openssl/commit/1ca5a124b48f1ffe6980ad33724b452fbd62da1e" +vuln = "openssl-cve-2026-54874-dtls1_process_record/vuln.c" +fixed = "openssl-cve-2026-54874-dtls1_process_record/fixed.c" +relpath = "ssl/record/ssl3_record.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/record/ssl3_record.c" +sink = "unknown" +evidence = "Avoid full read buffer allocation when buffering DTLS records" + +[[pair]] +name = "openssl-cve-2026-54874-dtls_rlayer_buffer_recor" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-54874" +cwe = "CWE-119" +commit = "7110cb2f75806d0bf809eb2f90790d477900be40" +parent = "9ec2f6d2ae2bcad907cf7ee38584855bafe4979a" +commit_url = "https://github.com/openssl/openssl/commit/7110cb2f75806d0bf809eb2f90790d477900be40" +vuln = "openssl-cve-2026-54874-dtls_rlayer_buffer_recor/vuln.c" +fixed = "openssl-cve-2026-54874-dtls_rlayer_buffer_recor/fixed.c" +relpath = "ssl/record/methods/dtls_meth.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/record/methods/dtls_meth.c" +sink = "unknown" +evidence = "Avoid full read buffer allocation when buffering DTLS next-epoch records" + +[[pair]] +name = "openssl-cve-2026-63072" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-63072" +cwe = "CWE-119" +commit = "a0c8ec557d9cac078f032d76cdf684fe743eb382" +parent = "d307f61f1b341b6eb7d5d07bd6902a939c709bc6" +commit_url = "https://github.com/openssl/openssl/commit/a0c8ec557d9cac078f032d76cdf684fe743eb382" +vuln = "openssl-cve-2026-63072/vuln.c" +fixed = "openssl-cve-2026-63072/fixed.c" +relpath = "crypto/cms/cms_kari.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "buffer overflow" +path = "crypto/cms/cms_kari.c" +sink = "memcpy" +evidence = "Fix heap buffer overflow (8-byte OOB write) in AES-WRAP-PAD unwrap" + +[[pair]] +name = "openssl-cve-2026-63072-cms_kek_cipher" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-63072" +cwe = "CWE-119" +commit = "2a3dac874c8057c1f0186849bf1ede1ae7b6b756" +parent = "1951c3cbd9d5101e027a1eb126f26c3c758f6cc0" +commit_url = "https://github.com/openssl/openssl/commit/2a3dac874c8057c1f0186849bf1ede1ae7b6b756" +vuln = "openssl-cve-2026-63072-cms_kek_cipher/vuln.c" +fixed = "openssl-cve-2026-63072-cms_kek_cipher/fixed.c" +relpath = "crypto/cms/cms_kemri.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "buffer overflow" +path = "crypto/cms/cms_kemri.c" +sink = "memcpy" +evidence = "Fix heap buffer overflow (8-byte OOB write) in AES-WRAP-PAD unwrap" + +[[pair]] +name = "openssl-cve-2026-63073" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-63073" +cwe = "CWE-119" +commit = "a7e5a6eea8fd3ccca6b6fbba031a5fbf8a3d93b4" +parent = "1e8c398db67404babd3e5af999bb6bd86f720c76" +commit_url = "https://github.com/openssl/openssl/commit/a7e5a6eea8fd3ccca6b6fbba031a5fbf8a3d93b4" +vuln = "openssl-cve-2026-63073/vuln.c" +fixed = "openssl-cve-2026-63073/fixed.c" +relpath = "crypto/cmp/cmp_vfy.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/cmp/cmp_vfy.c" +sink = "unknown" +evidence = "CMP unexpected sender DN used as format string in ERR_raise_data()" + +[[pair]] +name = "openssl-cve-2026-14457" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-14457" +cwe = "CWE-119" +commit = "1e8c398db67404babd3e5af999bb6bd86f720c76" +parent = "f636f9ca0fa1bae5b42f9e787f025c96fb09c43a" +commit_url = "https://github.com/openssl/openssl/commit/1e8c398db67404babd3e5af999bb6bd86f720c76" +vuln = "openssl-cve-2026-14457/vuln.c" +fixed = "openssl-cve-2026-14457/fixed.c" +relpath = "ssl/t1_lib.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/t1_lib.c" +sink = "unknown" +evidence = "Handle signature_algorithms_cert extension in key-only context" + +[[pair]] +name = "openssl-cve-2026-63074" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-63074" +cwe = "CWE-119" +commit = "21a5d9658b0c66daace60e10ea18ff32a448de9f" +parent = "9f2b8522d39ff869fac2ff7c3f20609b54843188" +commit_url = "https://github.com/openssl/openssl/commit/21a5d9658b0c66daace60e10ea18ff32a448de9f" +vuln = "openssl-cve-2026-63074/vuln.c" +fixed = "openssl-cve-2026-63074/fixed.c" +relpath = "crypto/cmp/cmp_vfy.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/cmp/cmp_vfy.c" +sink = "unknown" +evidence = "Fix unbounded cert cache growth in cmp" + +[[pair]] +name = "openssl-cve-2026-63075-txp_pkt_commit" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-63075" +cwe = "CWE-119" +commit = "c902e5f16d6a9e130e96d3ca6d8f64d71652e393" +parent = "a1f348ccb328c3afbd4ba6883f9b7c813c043259" +commit_url = "https://github.com/openssl/openssl/commit/c902e5f16d6a9e130e96d3ca6d8f64d71652e393" +vuln = "openssl-cve-2026-63075-txp_pkt_commit/vuln.c" +fixed = "openssl-cve-2026-63075-txp_pkt_commit/fixed.c" +relpath = "ssl/quic/quic_txp.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/quic/quic_txp.c" +sink = "unknown" +evidence = "Don't store ACK-only frames in TX history for QUIC." + +[[pair]] +name = "openssl-cve-2026-75803" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-75803" +cwe = "CWE-119" +commit = "119ab9555dc62275bbd71f6f49529b1a44feba42" +parent = "39488cb863074d5b8ece833905f7ad2b357d44fe" +commit_url = "https://github.com/openssl/openssl/commit/119ab9555dc62275bbd71f6f49529b1a44feba42" +vuln = "openssl-cve-2026-75803/vuln.c" +fixed = "openssl-cve-2026-75803/fixed.c" +relpath = "providers/implementations/ciphers/cipher_aes_ocb.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "providers/implementations/ciphers/cipher_aes_ocb.c" +sink = "unknown" +evidence = "Check the tag on EVP_Cipher() finalize: Poly1305 and OCB AEADs" + +[[pair]] +name = "openssl-cve-2026-75803-chacha20_poly1305_cipher" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-75803" +cwe = "CWE-119" +commit = "119ab9555dc62275bbd71f6f49529b1a44feba42" +parent = "39488cb863074d5b8ece833905f7ad2b357d44fe" +commit_url = "https://github.com/openssl/openssl/commit/119ab9555dc62275bbd71f6f49529b1a44feba42" +vuln = "openssl-cve-2026-75803-chacha20_poly1305_cipher/vuln.c" +fixed = "openssl-cve-2026-75803-chacha20_poly1305_cipher/fixed.c" +relpath = "providers/implementations/ciphers/cipher_chacha20_poly1305.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "providers/implementations/ciphers/cipher_chacha20_poly1305.c" +sink = "unknown" +evidence = "Check the tag on EVP_Cipher() finalize: Poly1305 and OCB AEADs" + +[[pair]] +name = "openssl-cve-2026-75803-aes_gcm_siv_finish" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-75803" +cwe = "CWE-119" +commit = "bf95f5f772e9362f87b25cfa2f8cb15d984865b9" +parent = "de7d1871087fc1fa3e2c1db4b11275b68d72f416" +commit_url = "https://github.com/openssl/openssl/commit/bf95f5f772e9362f87b25cfa2f8cb15d984865b9" +vuln = "openssl-cve-2026-75803-aes_gcm_siv_finish/vuln.c" +fixed = "openssl-cve-2026-75803-aes_gcm_siv_finish/fixed.c" +relpath = "providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c" +sink = "unknown" +evidence = "Check the tag on EVP_Cipher() finalize: Poly1305 and OCB AEADs" + +[[pair]] +name = "openssl-cve-2026-14456-port_default_packet_hand" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-14456" +cwe = "CWE-119" +commit = "08e7756c3900bcfd77a720e7b74e27d6e4ed01a9" +parent = "2dacccc943b47b8dc1ce8f7109c9852391b5a0d8" +commit_url = "https://github.com/openssl/openssl/commit/08e7756c3900bcfd77a720e7b74e27d6e4ed01a9" +vuln = "openssl-cve-2026-14456-port_default_packet_hand/vuln.c" +fixed = "openssl-cve-2026-14456-port_default_packet_hand/fixed.c" +relpath = "ssl/quic/quic_port.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/quic/quic_port.c" +sink = "unknown" +evidence = "QUIC server: limit number of pending QUIC channels/connections" + +[[pair]] +name = "openssl-cve-2026-14456-expect_quic_for_value" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-14456" +cwe = "CWE-119" +commit = "9416706d408bb84deb7cee4647bff3045d2dc7ba" +parent = "2c9a078b6030444ed868a3943991f42b35cd49dc" +commit_url = "https://github.com/openssl/openssl/commit/9416706d408bb84deb7cee4647bff3045d2dc7ba" +vuln = "openssl-cve-2026-14456-expect_quic_for_value/vuln.c" +fixed = "openssl-cve-2026-14456-expect_quic_for_value/fixed.c" +relpath = "ssl/quic/quic_impl.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/quic/quic_impl.c" +sink = "unknown" +evidence = "QUIC server: limit number of pending QUIC channels/connections" + +[[pair]] +name = "openssl-cve-2026-45447" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-45447" +cwe = "CWE-416" +commit = "f4129fbe3cde786d363510069fe297234f99be8f" +parent = "609bcb24866d64f1fc49d38b852edbb39057d721" +commit_url = "https://github.com/openssl/openssl/commit/f4129fbe3cde786d363510069fe297234f99be8f" +vuln = "openssl-cve-2026-45447/vuln.c" +fixed = "openssl-cve-2026-45447/fixed.c" +relpath = "crypto/pkcs7/pk7_smime.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-416" +class = "use after free" +path = "crypto/pkcs7/pk7_smime.c" +sink = "free" +evidence = "Fix possible use-after-free in OpenSSL PKCS7_verify()" + +[[pair]] +name = "openssl-cve-2026-45446" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-45446" +cwe = "CWE-119" +commit = "609bcb24866d64f1fc49d38b852edbb39057d721" +parent = "f87f0b6a8e04bcdeb98afc82b0da06a2d537f399" +commit_url = "https://github.com/openssl/openssl/commit/609bcb24866d64f1fc49d38b852edbb39057d721" +vuln = "openssl-cve-2026-45446/vuln.c" +fixed = "openssl-cve-2026-45446/fixed.c" +relpath = "providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c" +sink = "unknown" +evidence = "Fix handling of empty-ciphertext messages in AES-GCM-SIV and AES-SIV" + +[[pair]] +name = "openssl-cve-2026-45446-aes_siv_set_ctx_params" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-45446" +cwe = "CWE-119" +commit = "609bcb24866d64f1fc49d38b852edbb39057d721" +parent = "f87f0b6a8e04bcdeb98afc82b0da06a2d537f399" +commit_url = "https://github.com/openssl/openssl/commit/609bcb24866d64f1fc49d38b852edbb39057d721" +vuln = "openssl-cve-2026-45446-aes_siv_set_ctx_params/vuln.c" +fixed = "openssl-cve-2026-45446-aes_siv_set_ctx_params/fixed.c" +relpath = "providers/implementations/ciphers/cipher_aes_siv.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "providers/implementations/ciphers/cipher_aes_siv.c" +sink = "unknown" +evidence = "Fix handling of empty-ciphertext messages in AES-GCM-SIV and AES-SIV" + +[[pair]] +name = "openssl-cve-2026-45445" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-45445" +cwe = "CWE-119" +commit = "f87f0b6a8e04bcdeb98afc82b0da06a2d537f399" +parent = "5f489043b662fed32fbf7eb7442c479568eb43fd" +commit_url = "https://github.com/openssl/openssl/commit/f87f0b6a8e04bcdeb98afc82b0da06a2d537f399" +vuln = "openssl-cve-2026-45445/vuln.c" +fixed = "openssl-cve-2026-45445/fixed.c" +relpath = "providers/implementations/ciphers/cipher_aes_ocb.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "providers/implementations/ciphers/cipher_aes_ocb.c" +sink = "unknown" +evidence = "Apply the buffered IV on the AES-OCB EVP_Cipher() path" + +[[pair]] +name = "openssl-cve-2026-42771" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-42771" +cwe = "CWE-119" +commit = "b3a555a0a7aa0028887149f6f973af89a4937bea" +parent = "0f3fab2eccc7c3417093a8243dd15d95b6cb472d" +commit_url = "https://github.com/openssl/openssl/commit/b3a555a0a7aa0028887149f6f973af89a4937bea" +vuln = "openssl-cve-2026-42771/vuln.c" +fixed = "openssl-cve-2026-42771/fixed.c" +relpath = "crypto/x509/x509_vpm.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/x509/x509_vpm.c" +sink = "unknown" +evidence = "Fix length miscalculation in validate_email" + +[[pair]] +name = "openssl-cve-2026-42769" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-42769" +cwe = "CWE-476" +commit = "c2765d53c2649b56bc1ca1bb799e42002953056a" +parent = "d5030cdf32d6cd27bd964a0cb7aed2b7cb713369" +commit_url = "https://github.com/openssl/openssl/commit/c2765d53c2649b56bc1ca1bb799e42002953056a" +vuln = "openssl-cve-2026-42769/vuln.c" +fixed = "openssl-cve-2026-42769/fixed.c" +relpath = "crypto/cmp/cmp_genm.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-476" +class = "null pointer dereference" +path = "crypto/cmp/cmp_genm.c" +sink = "NULL" +evidence = "Use the correct issuer when validating rootCAKeyUpdate" + +[[pair]] +name = "openssl-cve-2026-42768" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-42768" +cwe = "CWE-119" +commit = "d5030cdf32d6cd27bd964a0cb7aed2b7cb713369" +parent = "f04d65692dd8109be9f387ce2ddd9fb1ab612b6b" +commit_url = "https://github.com/openssl/openssl/commit/d5030cdf32d6cd27bd964a0cb7aed2b7cb713369" +vuln = "openssl-cve-2026-42768/vuln.c" +fixed = "openssl-cve-2026-42768/fixed.c" +relpath = "crypto/cms/cms_env.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/cms/cms_env.c" +sink = "unknown" +evidence = "Enforce implicit rejection for CMS/PKCS#7 decryption" + +[[pair]] +name = "openssl-cve-2026-42768-pkcs7_decrypt_rinfo" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-42768" +cwe = "CWE-119" +commit = "d5030cdf32d6cd27bd964a0cb7aed2b7cb713369" +parent = "f04d65692dd8109be9f387ce2ddd9fb1ab612b6b" +commit_url = "https://github.com/openssl/openssl/commit/d5030cdf32d6cd27bd964a0cb7aed2b7cb713369" +vuln = "openssl-cve-2026-42768-pkcs7_decrypt_rinfo/vuln.c" +fixed = "openssl-cve-2026-42768-pkcs7_decrypt_rinfo/fixed.c" +relpath = "crypto/pkcs7/pk7_doit.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/pkcs7/pk7_doit.c" +sink = "unknown" +evidence = "Enforce implicit rejection for CMS/PKCS#7 decryption" + +[[pair]] +name = "openssl-cve-2026-42766" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-42766" +cwe = "CWE-476" +commit = "74245170b5a64b234ac4af27c86a25ec251c8b2a" +parent = "a9af3442290e8a04706a3cd5f284ffd5b486e3f6" +commit_url = "https://github.com/openssl/openssl/commit/74245170b5a64b234ac4af27c86a25ec251c8b2a" +vuln = "openssl-cve-2026-42766/vuln.c" +fixed = "openssl-cve-2026-42766/fixed.c" +relpath = "crypto/cms/cms_pwri.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-476" +class = "null pointer dereference" +path = "crypto/cms/cms_pwri.c" +sink = "NULL" +evidence = "Fix potential NULL dereference processing CMS PasswordRecipientInfo" + +[[pair]] +name = "openssl-cve-2026-42765" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-42765" +cwe = "CWE-476" +commit = "a9af3442290e8a04706a3cd5f284ffd5b486e3f6" +parent = "5097ec4dae239112498abb722e255ea60ef7ac48" +commit_url = "https://github.com/openssl/openssl/commit/a9af3442290e8a04706a3cd5f284ffd5b486e3f6" +vuln = "openssl-cve-2026-42765/vuln.c" +fixed = "openssl-cve-2026-42765/fixed.c" +relpath = "crypto/x509/x509_vfy.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-476" +class = "null pointer dereference" +path = "crypto/x509/x509_vfy.c" +sink = "NULL" +evidence = "Fix NULL Dereference in Certificate Verification with OCSP Checking" + +[[pair]] +name = "openssl-cve-2026-42764" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-42764" +cwe = "CWE-476" +commit = "5097ec4dae239112498abb722e255ea60ef7ac48" +parent = "58633b658fe74095c8cdde191e4ce1bf94f8c5f9" +commit_url = "https://github.com/openssl/openssl/commit/5097ec4dae239112498abb722e255ea60ef7ac48" +vuln = "openssl-cve-2026-42764/vuln.c" +fixed = "openssl-cve-2026-42764/fixed.c" +relpath = "ssl/quic/quic_port.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-476" +class = "null pointer dereference" +path = "ssl/quic/quic_port.c" +sink = "NULL" +evidence = "Fix NULL dereference in QUIC address validation" + +[[pair]] +name = "openssl-cve-2026-35188" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-35188" +cwe = "CWE-119" +commit = "58633b658fe74095c8cdde191e4ce1bf94f8c5f9" +parent = "68ef88913e321bdb47eee88118ceba18ed2388cd" +commit_url = "https://github.com/openssl/openssl/commit/58633b658fe74095c8cdde191e4ce1bf94f8c5f9" +vuln = "openssl-cve-2026-35188/vuln.c" +fixed = "openssl-cve-2026-35188/fixed.c" +relpath = "crypto/x509/x509_vfy.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/x509/x509_vfy.c" +sink = "unknown" +evidence = "Fix Double-free When Checking OCSP Stapled Response" + +[[pair]] +name = "openssl-cve-2026-34181" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-34181" +cwe = "CWE-119" +commit = "5a0230b6cc95a576b0c2b7b5b2ba7c74232e7b7c" +parent = "fcb23806047f5afbe55d5d601a527fc24bf7ca2c" +commit_url = "https://github.com/openssl/openssl/commit/5a0230b6cc95a576b0c2b7b5b2ba7c74232e7b7c" +vuln = "openssl-cve-2026-34181/vuln.c" +fixed = "openssl-cve-2026-34181/fixed.c" +relpath = "crypto/pkcs12/p12_mutl.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/pkcs12/p12_mutl.c" +sink = "unknown" +evidence = "pkcs12: verify that the pbmac1 key length is safe" + +[[pair]] +name = "openssl-cve-2026-9076" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-9076" +cwe = "CWE-119" +commit = "51d1800e95283a8beec85152e35e3634dab8dd82" +parent = "97f6b621f7af2c4c4e162c75045a6e12a8fdf8d9" +commit_url = "https://github.com/openssl/openssl/commit/51d1800e95283a8beec85152e35e3634dab8dd82" +vuln = "openssl-cve-2026-9076/vuln.c" +fixed = "openssl-cve-2026-9076/fixed.c" +relpath = "crypto/cms/cms_pwri.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "buffer overflow" +path = "crypto/cms/cms_pwri.c" +sink = "memcpy" +evidence = "cms: kek_unwrap_key: Fix out-of-bounds read in check-byte validation" + +[[pair]] +name = "openssl-cve-2026-7383" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-7383" +cwe = "CWE-119" +commit = "97f6b621f7af2c4c4e162c75045a6e12a8fdf8d9" +parent = "cb005ceaaf1fb50722e0101762a3e266338c5bf9" +commit_url = "https://github.com/openssl/openssl/commit/97f6b621f7af2c4c4e162c75045a6e12a8fdf8d9" +vuln = "openssl-cve-2026-7383/vuln.c" +fixed = "openssl-cve-2026-7383/fixed.c" +relpath = "crypto/asn1/a_mbstr.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/asn1/a_mbstr.c" +sink = "unknown" +evidence = "Reject oversized inputs in ASN1_mbstring_ncopy()" + +[[pair]] +name = "openssl-cve-2026-31790" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-31790" +cwe = "CWE-119" +commit = "eed200f58cd8645ed77e46b7e9f764e284df379e" +parent = "a91e537d16d74050dbde50bb0dfb1fe9930f0521" +commit_url = "https://github.com/openssl/openssl/commit/eed200f58cd8645ed77e46b7e9f764e284df379e" +vuln = "openssl-cve-2026-31790/vuln.c" +fixed = "openssl-cve-2026-31790/fixed.c" +relpath = "providers/implementations/kem/rsa_kem.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "providers/implementations/kem/rsa_kem.c" +sink = "unknown" +evidence = "rsa_kem: validate RSA_public_encrypt() result in RSASVE" + +[[pair]] +name = "openssl-cve-2026-31790-rsasve_generate" +slice = "vfc" +language = "unknown" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-31790" +cwe = "CWE-119" +commit = "abd8b2eec7e3f3fda60ecfb68498b246b52af482" +parent = "a24216018e1ede8ff01a4ff5afff7dfbd443e2f9" +commit_url = "https://github.com/openssl/openssl/commit/abd8b2eec7e3f3fda60ecfb68498b246b52af482" +vuln = "openssl-cve-2026-31790-rsasve_generate/vuln.in" +fixed = "openssl-cve-2026-31790-rsasve_generate/fixed.in" +relpath = "providers/implementations/kem/rsa_kem.c.in" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "providers/implementations/kem/rsa_kem.c.in" +sink = "unknown" +evidence = "rsa_kem: validate RSA_public_encrypt() result in RSASVE" + +[[pair]] +name = "openssl-cve-2026-31789" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-31789" +cwe = "CWE-119" +commit = "a91e537d16d74050dbde50bb0dfb1fe9930f0521" +parent = "b7ae7a093997b5cd549bc21cccd715510fef86c0" +commit_url = "https://github.com/openssl/openssl/commit/a91e537d16d74050dbde50bb0dfb1fe9930f0521" +vuln = "openssl-cve-2026-31789/vuln.c" +fixed = "openssl-cve-2026-31789/fixed.c" +relpath = "crypto/o_str.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "buffer overflow" +path = "crypto/o_str.c" +sink = "memcpy" +evidence = "Avoid possible buffer overflow in buf2hex conversion" + +[[pair]] +name = "openssl-cve-2026-28388" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-28388" +cwe = "CWE-476" +commit = "59c3b3158553ab53275bbbccca5cb305d591cf2e" +parent = "d044f9252fe9a54001986fb4eb4e32076a056527" +commit_url = "https://github.com/openssl/openssl/commit/59c3b3158553ab53275bbbccca5cb305d591cf2e" +vuln = "openssl-cve-2026-28388/vuln.c" +fixed = "openssl-cve-2026-28388/fixed.c" +relpath = "crypto/x509/x509_vfy.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-476" +class = "null pointer dereference" +path = "crypto/x509/x509_vfy.c" +sink = "NULL" +evidence = "Fix NULL Dereference When Delta CRL Lacks CRL Number Extension" + +[[pair]] +name = "openssl-cve-2026-28389" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-28389" +cwe = "CWE-476" +commit = "af2a5fecd3e71a29e7568f9c1453dec5cebbaff4" +parent = "6e74b1275cbc1fd1cf7ba32f662602d68501f6ca" +commit_url = "https://github.com/openssl/openssl/commit/af2a5fecd3e71a29e7568f9c1453dec5cebbaff4" +vuln = "openssl-cve-2026-28389/vuln.c" +fixed = "openssl-cve-2026-28389/fixed.c" +relpath = "crypto/cms/cms_rsa.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-476" +class = "null pointer dereference" +path = "crypto/cms/cms_rsa.c" +sink = "NULL" +evidence = "Fix NULL deref in rsa_cms_decrypt" + +[[pair]] +name = "openssl-cve-2026-28389-dh_cms_set_shared_info" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-28389" +cwe = "CWE-476" +commit = "7b5274e812400cacb6f3be4c2df5340923fa807f" +parent = "72ec3e38c87f71f5c50ae3b16cc34d8371c71bb9" +commit_url = "https://github.com/openssl/openssl/commit/7b5274e812400cacb6f3be4c2df5340923fa807f" +vuln = "openssl-cve-2026-28389-dh_cms_set_shared_info/vuln.c" +fixed = "openssl-cve-2026-28389-dh_cms_set_shared_info/fixed.c" +relpath = "crypto/cms/cms_dh.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-476" +class = "null pointer dereference" +path = "crypto/cms/cms_dh.c" +sink = "NULL" +evidence = "Fix NULL deref in [ec]dh_cms_set_shared_info" + +[[pair]] +name = "openssl-cve-2026-28389-ecdh_cms_set_shared_info" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-28389" +cwe = "CWE-476" +commit = "7b5274e812400cacb6f3be4c2df5340923fa807f" +parent = "72ec3e38c87f71f5c50ae3b16cc34d8371c71bb9" +commit_url = "https://github.com/openssl/openssl/commit/7b5274e812400cacb6f3be4c2df5340923fa807f" +vuln = "openssl-cve-2026-28389-ecdh_cms_set_shared_info/vuln.c" +fixed = "openssl-cve-2026-28389-ecdh_cms_set_shared_info/fixed.c" +relpath = "crypto/cms/cms_ec.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-476" +class = "null pointer dereference" +path = "crypto/cms/cms_ec.c" +sink = "NULL" +evidence = "Fix NULL deref in [ec]dh_cms_set_shared_info" + +[[pair]] +name = "openssl-cve-2026-2673" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2026-2673" +cwe = "CWE-119" +commit = "85977e013f32ceb96aa034c0e741adddc1a05e34" +parent = "21d525dc846aed171fc886f3da614a6645948f13" +commit_url = "https://github.com/openssl/openssl/commit/85977e013f32ceb96aa034c0e741adddc1a05e34" +vuln = "openssl-cve-2026-2673/vuln.c" +fixed = "openssl-cve-2026-2673/fixed.c" +relpath = "ssl/t1_lib.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/t1_lib.c" +sink = "unknown" +evidence = "Fix group tuple handling in DEFAULT expansion" + +[[pair]] +name = "openssl-cve-2025-69419" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2025-69419" +cwe = "CWE-119" +commit = "4191043c36f1a50c717a2d0075fc6f3b9bc0afc5" +parent = "7565bb46fa2979511cb27aad1c2bd6b80adf7352" +commit_url = "https://github.com/openssl/openssl/commit/4191043c36f1a50c717a2d0075fc6f3b9bc0afc5" +vuln = "openssl-cve-2025-69419/vuln.c" +fixed = "openssl-cve-2025-69419/fixed.c" +relpath = "crypto/pkcs12/p12_utl.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "buffer overflow" +path = "crypto/pkcs12/p12_utl.c" +sink = "memcpy" +evidence = "Alternate fix for CVE-2025-69419" + +[[pair]] +name = "openssl-cve-2025-69418" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2025-69418" +cwe = "CWE-119" +commit = "52d23c86a54adab5ee9f80e48b242b52c4cc2347" +parent = "475c466ef2fbd8fc1df6fae1c3eed9c813fc8ff6" +commit_url = "https://github.com/openssl/openssl/commit/52d23c86a54adab5ee9f80e48b242b52c4cc2347" +vuln = "openssl-cve-2025-69418/vuln.c" +fixed = "openssl-cve-2025-69418/fixed.c" +relpath = "crypto/modes/ocb128.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/modes/ocb128.c" +sink = "unknown" +evidence = "Fix OCB AES-NI/HW stream path unauthenticated/unencrypted trailing bytes" + +[[pair]] +name = "openssl-cve-2025-66199-tls13_process_compressed" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2025-66199" +cwe = "CWE-119" +commit = "3ed1f75249932b155eef993a8e66a99cb98bfef4" +parent = "384011202af92605d926fafe4a0bcd6b65d162ad" +commit_url = "https://github.com/openssl/openssl/commit/3ed1f75249932b155eef993a8e66a99cb98bfef4" +vuln = "openssl-cve-2025-66199-tls13_process_compressed/vuln.c" +fixed = "openssl-cve-2025-66199-tls13_process_compressed/fixed.c" +relpath = "ssl/statem/statem_lib.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/statem/statem_lib.c" +sink = "unknown" +evidence = "Check the received uncompressed certificate length to prevent excessive pre-decompression allocation." + +[[pair]] +name = "openssl-cve-2025-68160" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2025-68160" +cwe = "CWE-119" +commit = "475c466ef2fbd8fc1df6fae1c3eed9c813fc8ff6" +parent = "e0666f72294691a808443970b654412a6d92fa0f" +commit_url = "https://github.com/openssl/openssl/commit/475c466ef2fbd8fc1df6fae1c3eed9c813fc8ff6" +vuln = "openssl-cve-2025-68160/vuln.c" +fixed = "openssl-cve-2025-68160/fixed.c" +relpath = "crypto/bio/bf_lbuf.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "buffer overflow" +path = "crypto/bio/bf_lbuf.c" +sink = "memcpy" +evidence = "Fix heap buffer overflow in BIO_f_linebuffer" + +[[pair]] +name = "openssl-cve-2025-15469" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2025-15469" +cwe = "CWE-119" +commit = "a7936fa4bd23c906e1955a16a0a0ab39a4953a61" +parent = "1f08e54bad32843044fe8a675948d65e3b4ece65" +commit_url = "https://github.com/openssl/openssl/commit/a7936fa4bd23c906e1955a16a0a0ab39a4953a61" +vuln = "openssl-cve-2025-15469/vuln.c" +fixed = "openssl-cve-2025-15469/fixed.c" +relpath = "apps/dgst.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "apps/dgst.c" +sink = "unknown" +evidence = "Report truncation in oneshot `openssl dgst -sign`" + +[[pair]] +name = "openssl-cve-2025-15467" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2025-15467" +cwe = "CWE-119" +commit = "ce39170276daec87f55c39dad1f629b56344429e" +parent = "3250efdfe99d2d7fe4fb05231add7fba864b7653" +commit_url = "https://github.com/openssl/openssl/commit/ce39170276daec87f55c39dad1f629b56344429e" +vuln = "openssl-cve-2025-15467/vuln.c" +fixed = "openssl-cve-2025-15467/fixed.c" +relpath = "crypto/evp/evp_lib.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/evp/evp_lib.c" +sink = "unknown" +evidence = "Correct handling of AEAD-encrypted CMS with inadmissibly long IV" + +[[pair]] +name = "openssl-cve-2025-11187" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2025-11187" +cwe = "CWE-119" +commit = "205e3a55e16e4bd08c12fdbd3416ab829c0f6206" +parent = "b8654779e3b3b4eb0bda7623c0891d394e068187" +commit_url = "https://github.com/openssl/openssl/commit/205e3a55e16e4bd08c12fdbd3416ab829c0f6206" +vuln = "openssl-cve-2025-11187/vuln.c" +fixed = "openssl-cve-2025-11187/fixed.c" +relpath = "crypto/pkcs12/p12_mutl.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/pkcs12/p12_mutl.c" +sink = "unknown" +evidence = "pkcs12: Validate salt and keylength in PBMAC1" + +[[pair]] +name = "openssl-cve-2025-9232" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2025-9232" +cwe = "CWE-119" +commit = "654dc11d23468a74fc8ea4672b702dd3feb7be4b" +parent = "a79c4ce559c6a3a8fd4109e9f33c1185d5bf2def" +commit_url = "https://github.com/openssl/openssl/commit/654dc11d23468a74fc8ea4672b702dd3feb7be4b" +vuln = "openssl-cve-2025-9232/vuln.c" +fixed = "openssl-cve-2025-9232/fixed.c" +relpath = "crypto/http/http_lib.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/http/http_lib.c" +sink = "unknown" +evidence = "use_proxy(): Add missing terminating NUL byte" + +[[pair]] +name = "openssl-cve-2025-9230" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2025-9230" +cwe = "CWE-119" +commit = "a79c4ce559c6a3a8fd4109e9f33c1185d5bf2def" +parent = "7e0fc054a08706d194d3355aba4a06003cadfb29" +commit_url = "https://github.com/openssl/openssl/commit/a79c4ce559c6a3a8fd4109e9f33c1185d5bf2def" +vuln = "openssl-cve-2025-9230/vuln.c" +fixed = "openssl-cve-2025-9230/fixed.c" +relpath = "crypto/cms/cms_pwri.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "buffer overflow" +path = "crypto/cms/cms_pwri.c" +sink = "memcpy" +evidence = "kek_unwrap_key(): Fix incorrect check of unwrapped key size" + +[[pair]] +name = "openssl-cve-2024-12797" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2024-12797" +cwe = "CWE-119" +commit = "798779d43494549b611233f92652f0da5328fbe7" +parent = "0db27ec7f8abd258d2e8849ac555ca26ba0cd8d6" +commit_url = "https://github.com/openssl/openssl/commit/798779d43494549b611233f92652f0da5328fbe7" +vuln = "openssl-cve-2024-12797/vuln.c" +fixed = "openssl-cve-2024-12797/fixed.c" +relpath = "ssl/statem/statem_clnt.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/statem/statem_clnt.c" +sink = "unknown" +evidence = "With SSL_VERIFY_PEER client RPK should abort on X509 error" + +[[pair]] +name = "openssl-cve-2024-13176-ec_field_inverse_mod_ord" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2024-13176" +cwe = "CWE-119" +commit = "07272b05b04836a762b4baa874958af51d513844" +parent = "643de602771f6b38ad7823e26d5a63c669eb185b" +commit_url = "https://github.com/openssl/openssl/commit/07272b05b04836a762b4baa874958af51d513844" +vuln = "openssl-cve-2024-13176-ec_field_inverse_mod_ord/vuln.c" +fixed = "openssl-cve-2024-13176-ec_field_inverse_mod_ord/fixed.c" +relpath = "crypto/ec/ec_lib.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/ec/ec_lib.c" +sink = "unknown" +evidence = "Fix timing side-channel in ECDSA signature computation" + +[[pair]] +name = "openssl-cve-2024-6119" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2024-6119" +cwe = "CWE-119" +commit = "06d1dc3fa96a2ba5a3e22735a033012aadc9f0d6" +parent = "9aae56395aa8e77c44a9df83fd395a644d016635" +commit_url = "https://github.com/openssl/openssl/commit/06d1dc3fa96a2ba5a3e22735a033012aadc9f0d6" +vuln = "openssl-cve-2024-6119/vuln.c" +fixed = "openssl-cve-2024-6119/fixed.c" +relpath = "crypto/x509/v3_utl.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/x509/v3_utl.c" +sink = "unknown" +evidence = "Avoid type errors in EAI-related name check logic." + +[[pair]] +name = "openssl-cve-2024-5535" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2024-5535" +cwe = "CWE-119" +commit = "4b375b998798dd516d367036773073e1b88e6433" +parent = "189a7ed3e380e34ea38fe4190a7c9396bace0fb7" +commit_url = "https://github.com/openssl/openssl/commit/4b375b998798dd516d367036773073e1b88e6433" +vuln = "openssl-cve-2024-5535/vuln.c" +fixed = "openssl-cve-2024-5535/fixed.c" +relpath = "ssl/statem/extensions_clnt.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/statem/extensions_clnt.c" +sink = "unknown" +evidence = "Add ALPN validation in the client" + +[[pair]] +name = "openssl-cve-2024-5535-tls_construct_stoc_next_" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2024-5535" +cwe = "CWE-119" +commit = "189a7ed3e380e34ea38fe4190a7c9396bace0fb7" +parent = "72394c9a1a6a6b07edf43eb2ad7e95e1093ada1b" +commit_url = "https://github.com/openssl/openssl/commit/189a7ed3e380e34ea38fe4190a7c9396bace0fb7" +vuln = "openssl-cve-2024-5535-tls_construct_stoc_next_/vuln.c" +fixed = "openssl-cve-2024-5535-tls_construct_stoc_next_/fixed.c" +relpath = "ssl/statem/extensions_srvr.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/statem/extensions_srvr.c" +sink = "unknown" +evidence = "Correct return values for tls_construct_stoc_next_proto_neg" + +[[pair]] +name = "openssl-cve-2024-5535-tls_parse_stoc_npn" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2024-5535" +cwe = "CWE-119" +commit = "159921152fd4aa91e4c849fd281ad93ac0d0d0ba" +parent = "cf6f91f6121f4db167405db2f0de410a456f260c" +commit_url = "https://github.com/openssl/openssl/commit/159921152fd4aa91e4c849fd281ad93ac0d0d0ba" +vuln = "openssl-cve-2024-5535-tls_parse_stoc_npn/vuln.c" +fixed = "openssl-cve-2024-5535-tls_parse_stoc_npn/fixed.c" +relpath = "ssl/statem/extensions_clnt.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/statem/extensions_clnt.c" +sink = "unknown" +evidence = "More correctly handle a selected_len of 0 when processing NPN" + +[[pair]] +name = "openssl-cve-2024-5535-ssl_select_next_proto" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2024-5535" +cwe = "CWE-119" +commit = "cf6f91f6121f4db167405db2f0de410a456f260c" +parent = "a6facb1042adda2394dc5c98fbceb7625eef141a" +commit_url = "https://github.com/openssl/openssl/commit/cf6f91f6121f4db167405db2f0de410a456f260c" +vuln = "openssl-cve-2024-5535-ssl_select_next_proto/vuln.c" +fixed = "openssl-cve-2024-5535-ssl_select_next_proto/fixed.c" +relpath = "ssl/ssl_lib.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/ssl_lib.c" +sink = "unknown" +evidence = "Fix SSL_select_next_proto" + +[[pair]] +name = "openssl-cve-2024-5535-alpn_select_cb" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2024-5535" +cwe = "CWE-119" +commit = "6cc511826f09e513b4ec066d9b95acaf4f86d991" +parent = "015255851371757d54c2560643eb3b3a88123cf1" +commit_url = "https://github.com/openssl/openssl/commit/6cc511826f09e513b4ec066d9b95acaf4f86d991" +vuln = "openssl-cve-2024-5535-alpn_select_cb/vuln.c" +fixed = "openssl-cve-2024-5535-alpn_select_cb/fixed.c" +relpath = "ssl/quic/quic_tserver.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/quic/quic_tserver.c" +sink = "unknown" +evidence = "Use correctly formatted ALPN data in tserver" + +[[pair]] +name = "openssl-cve-2024-4741" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2024-4741" +cwe = "CWE-416" +commit = "2d05959073c4bf8803401668b9df85931a08e020" +parent = "b3f0eb0a295f58f16ba43ba99dad70d4ee5c437d" +commit_url = "https://github.com/openssl/openssl/commit/2d05959073c4bf8803401668b9df85931a08e020" +vuln = "openssl-cve-2024-4741/vuln.c" +fixed = "openssl-cve-2024-4741/fixed.c" +relpath = "ssl/record/rec_layer_s3.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-416" +class = "use after free" +path = "ssl/record/rec_layer_s3.c" +sink = "free" +evidence = "Set rlayer.packet to NULL after we've finished using it" + +[[pair]] +name = "openssl-cve-2024-4741-ssl3_release_read_buffer" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2024-4741" +cwe = "CWE-416" +commit = "2d05959073c4bf8803401668b9df85931a08e020" +parent = "b3f0eb0a295f58f16ba43ba99dad70d4ee5c437d" +commit_url = "https://github.com/openssl/openssl/commit/2d05959073c4bf8803401668b9df85931a08e020" +vuln = "openssl-cve-2024-4741-ssl3_release_read_buffer/vuln.c" +fixed = "openssl-cve-2024-4741-ssl3_release_read_buffer/fixed.c" +relpath = "ssl/record/ssl3_buffer.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-416" +class = "use after free" +path = "ssl/record/ssl3_buffer.c" +sink = "free" +evidence = "Set rlayer.packet to NULL after we've finished using it" + +[[pair]] +name = "openssl-cve-2024-4741-ssl_free_buffers" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2024-4741" +cwe = "CWE-119" +commit = "b3f0eb0a295f58f16ba43ba99dad70d4ee5c437d" +parent = "ec559c2a6cca3fd4cedae5c47f2dfa38e5e24865" +commit_url = "https://github.com/openssl/openssl/commit/b3f0eb0a295f58f16ba43ba99dad70d4ee5c437d" +vuln = "openssl-cve-2024-4741-ssl_free_buffers/vuln.c" +fixed = "openssl-cve-2024-4741-ssl_free_buffers/fixed.c" +relpath = "ssl/ssl_lib.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/ssl_lib.c" +sink = "unknown" +evidence = "Only free the read buffers if we're not using them" + +[[pair]] +name = "openssl-cve-2024-4741-tls_release_read_buffer" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2024-4741" +cwe = "CWE-416" +commit = "10171e5b511b700c5ecd4fd3e1086b19c34b1ae3" +parent = "c88c3de51020c37e8706bf7a682a162593053aac" +commit_url = "https://github.com/openssl/openssl/commit/10171e5b511b700c5ecd4fd3e1086b19c34b1ae3" +vuln = "openssl-cve-2024-4741-tls_release_read_buffer/vuln.c" +fixed = "openssl-cve-2024-4741-tls_release_read_buffer/fixed.c" +relpath = "ssl/record/methods/tls_common.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-416" +class = "use after free" +path = "ssl/record/methods/tls_common.c" +sink = "free" +evidence = "Set rl->packet to NULL after we've finished using it" + +[[pair]] +name = "openssl-cve-2024-4741-tls_free_buffers" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2024-4741" +cwe = "CWE-119" +commit = "c88c3de51020c37e8706bf7a682a162593053aac" +parent = "17765d9cefed8b4ada6548719beb98e22672a9bd" +commit_url = "https://github.com/openssl/openssl/commit/c88c3de51020c37e8706bf7a682a162593053aac" +vuln = "openssl-cve-2024-4741-tls_free_buffers/vuln.c" +fixed = "openssl-cve-2024-4741-tls_free_buffers/fixed.c" +relpath = "ssl/record/methods/tls_common.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/record/methods/tls_common.c" +sink = "unknown" +evidence = "Only free the read buffers if we're not using them" + +[[pair]] +name = "openssl-cve-2024-4603" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2024-4603" +cwe = "CWE-119" +commit = "3559e868e58005d15c6013a0c1fd832e51c73397" +parent = "d4b119c567cb5dcaf83add7ca2ea1d646eb3ef9f" +commit_url = "https://github.com/openssl/openssl/commit/3559e868e58005d15c6013a0c1fd832e51c73397" +vuln = "openssl-cve-2024-4603/vuln.c" +fixed = "openssl-cve-2024-4603/fixed.c" +relpath = "crypto/dsa/dsa_check.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/dsa/dsa_check.c" +sink = "unknown" +evidence = "Check DSA parameters for excessive sizes before validating" + +[[pair]] +name = "openssl-cve-2024-2511" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2024-2511" +cwe = "CWE-119" +commit = "b52867a9f618bb955bed2a3ce3db4d4f97ed8e5d" +parent = "c1e462ee4bd61867ee391fc13110ca41e4889535" +commit_url = "https://github.com/openssl/openssl/commit/b52867a9f618bb955bed2a3ce3db4d4f97ed8e5d" +vuln = "openssl-cve-2024-2511/vuln.c" +fixed = "openssl-cve-2024-2511/fixed.c" +relpath = "ssl/ssl_lib.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/ssl_lib.c" +sink = "unknown" +evidence = "Fix unconstrained session cache growth in TLSv1.3" + +[[pair]] +name = "openssl-cve-2024-2511-tls_construct_server_hel" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2024-2511" +cwe = "CWE-119" +commit = "b52867a9f618bb955bed2a3ce3db4d4f97ed8e5d" +parent = "c1e462ee4bd61867ee391fc13110ca41e4889535" +commit_url = "https://github.com/openssl/openssl/commit/b52867a9f618bb955bed2a3ce3db4d4f97ed8e5d" +vuln = "openssl-cve-2024-2511-tls_construct_server_hel/vuln.c" +fixed = "openssl-cve-2024-2511-tls_construct_server_hel/fixed.c" +relpath = "ssl/statem/statem_srvr.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/statem/statem_srvr.c" +sink = "unknown" +evidence = "Fix unconstrained session cache growth in TLSv1.3" + +[[pair]] +name = "openssl-cve-2024-0727" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2024-0727" +cwe = "CWE-476" +commit = "09df4395b5071217b76dc7d3d2e630eb8c5a79c2" +parent = "6c70934a46eaa1734c2efbe9d7baac51c607062e" +commit_url = "https://github.com/openssl/openssl/commit/09df4395b5071217b76dc7d3d2e630eb8c5a79c2" +vuln = "openssl-cve-2024-0727/vuln.c" +fixed = "openssl-cve-2024-0727/fixed.c" +relpath = "crypto/pkcs12/p12_mutl.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-476" +class = "null pointer dereference" +path = "crypto/pkcs12/p12_mutl.c" +sink = "NULL" +evidence = "Add NULL checks where ContentInfo data can be NULL" + +[[pair]] +name = "openssl-cve-2024-0727-smime_write_pkcs7" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2024-0727" +cwe = "CWE-476" +commit = "09df4395b5071217b76dc7d3d2e630eb8c5a79c2" +parent = "6c70934a46eaa1734c2efbe9d7baac51c607062e" +commit_url = "https://github.com/openssl/openssl/commit/09df4395b5071217b76dc7d3d2e630eb8c5a79c2" +vuln = "openssl-cve-2024-0727-smime_write_pkcs7/vuln.c" +fixed = "openssl-cve-2024-0727-smime_write_pkcs7/fixed.c" +relpath = "crypto/pkcs7/pk7_mime.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-476" +class = "null pointer dereference" +path = "crypto/pkcs7/pk7_mime.c" +sink = "NULL" +evidence = "Add NULL checks where ContentInfo data can be NULL" + +[[pair]] +name = "openssl-cve-2023-5363" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2023-5363" +cwe = "CWE-119" +commit = "0df40630850fb2740e6be6890bb905d3fc623b2d" +parent = "23d21359e35536a4ee8f7be0b245ddbfac909bff" +commit_url = "https://github.com/openssl/openssl/commit/0df40630850fb2740e6be6890bb905d3fc623b2d" +vuln = "openssl-cve-2023-5363/vuln.c" +fixed = "openssl-cve-2023-5363/fixed.c" +relpath = "crypto/evp/evp_enc.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/evp/evp_enc.c" +sink = "unknown" +evidence = "evp: process key length and iv length early if present" + +[[pair]] +name = "openssl-cve-2023-3817-dh_check" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2023-3817" +cwe = "CWE-119" +commit = "9002fd07327a91f35ba6c1307e71fa6fd4409b7f" +parent = "e648db50d9a63f71cab5cb78424c2932d019a744" +commit_url = "https://github.com/openssl/openssl/commit/9002fd07327a91f35ba6c1307e71fa6fd4409b7f" +vuln = "openssl-cve-2023-3817-dh_check/vuln.c" +fixed = "openssl-cve-2023-3817-dh_check/fixed.c" +relpath = "crypto/dh/dh_check.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/dh/dh_check.c" +sink = "unknown" +evidence = "DH_check(): Do not try checking q properties if it is obviously invalid" + +[[pair]] +name = "openssl-cve-2023-3446" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2023-3446" +cwe = "CWE-119" +commit = "8780a896543a654e757db1b9396383f9d8095528" +parent = "fe824ce0c5d51e7e7cf36c31db6c49c1c0c04a25" +commit_url = "https://github.com/openssl/openssl/commit/8780a896543a654e757db1b9396383f9d8095528" +vuln = "openssl-cve-2023-3446/vuln.c" +fixed = "openssl-cve-2023-3446/fixed.c" +relpath = "crypto/dh/dh_check.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/dh/dh_check.c" +sink = "unknown" +evidence = "Fix DH_check() excessive time with over sized modulus" + +[[pair]] +name = "openssl-cve-2023-2975" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2023-2975" +cwe = "CWE-119" +commit = "00e2f5eea29994d19293ec4e8c8775ba73678598" +parent = "175fa8469fc78f6cf35dfb87d26899e60e9ff1d4" +commit_url = "https://github.com/openssl/openssl/commit/00e2f5eea29994d19293ec4e8c8775ba73678598" +vuln = "openssl-cve-2023-2975/vuln.c" +fixed = "openssl-cve-2023-2975/fixed.c" +relpath = "providers/implementations/ciphers/cipher_aes_siv.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "providers/implementations/ciphers/cipher_aes_siv.c" +sink = "unknown" +evidence = "Do not ignore empty associated data with AES-SIV mode" + +[[pair]] +name = "openssl-cve-2023-2650" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2023-2650" +cwe = "CWE-119" +commit = "d63b3e7959e79f98d60760a739f7876dc5adc838" +parent = "3ca28c9e81fae36b0b44dc39beecd2b5a7561975" +commit_url = "https://github.com/openssl/openssl/commit/d63b3e7959e79f98d60760a739f7876dc5adc838" +vuln = "openssl-cve-2023-2650/vuln.c" +fixed = "openssl-cve-2023-2650/fixed.c" +relpath = "crypto/objects/obj_dat.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/objects/obj_dat.c" +sink = "unknown" +evidence = "Restrict the size of OBJECT IDENTIFIERs that OBJ_obj2txt will translate" + +[[pair]] +name = "openssl-cve-2022-37454" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2022-37454" +cwe = "CWE-119" +commit = "d12cde7fc5561d463badcd8a73079cf92864c31e" +parent = "5d6f13d90d5c4212737002bcd54871cf236a1220" +commit_url = "https://github.com/openssl/openssl/commit/d12cde7fc5561d463badcd8a73079cf92864c31e" +vuln = "openssl-cve-2022-37454/vuln.c" +fixed = "openssl-cve-2022-37454/fixed.c" +relpath = "providers/implementations/kdfs/hkdf.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "buffer overflow" +path = "providers/implementations/kdfs/hkdf.c" +sink = "memcpy" +evidence = "Update hkdf.c to avoid potentially vulnerable code pattern" + +[[pair]] +name = "openssl-cve-2022-4304" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2022-4304" +cwe = "CWE-119" +commit = "a00d757d9ca212994625d1a02c81cc5edd27e13b" +parent = "908eaceb62624f5b5c505b286d904bd3a4e8a64a" +commit_url = "https://github.com/openssl/openssl/commit/a00d757d9ca212994625d1a02c81cc5edd27e13b" +vuln = "openssl-cve-2022-4304/vuln.c" +fixed = "openssl-cve-2022-4304/fixed.c" +relpath = "crypto/bn/bn_asm.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/bn/bn_asm.c" +sink = "unknown" +evidence = "Alternative fix for CVE-2022-4304" + +[[pair]] +name = "openssl-cve-2022-4304-bn_blinding_invert_ex" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2022-4304" +cwe = "CWE-119" +commit = "a00d757d9ca212994625d1a02c81cc5edd27e13b" +parent = "908eaceb62624f5b5c505b286d904bd3a4e8a64a" +commit_url = "https://github.com/openssl/openssl/commit/a00d757d9ca212994625d1a02c81cc5edd27e13b" +vuln = "openssl-cve-2022-4304-bn_blinding_invert_ex/vuln.c" +fixed = "openssl-cve-2022-4304-bn_blinding_invert_ex/fixed.c" +relpath = "crypto/bn/bn_blind.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/bn/bn_blind.c" +sink = "unknown" +evidence = "Alternative fix for CVE-2022-4304" + +[[pair]] +name = "openssl-cve-2022-4304-rsa_blinding_invert" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2022-4304" +cwe = "CWE-119" +commit = "a00d757d9ca212994625d1a02c81cc5edd27e13b" +parent = "908eaceb62624f5b5c505b286d904bd3a4e8a64a" +commit_url = "https://github.com/openssl/openssl/commit/a00d757d9ca212994625d1a02c81cc5edd27e13b" +vuln = "openssl-cve-2022-4304-rsa_blinding_invert/vuln.c" +fixed = "openssl-cve-2022-4304-rsa_blinding_invert/fixed.c" +relpath = "crypto/rsa/rsa_ossl.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/rsa/rsa_ossl.c" +sink = "unknown" +evidence = "Alternative fix for CVE-2022-4304" + +[[pair]] +name = "openssl-cve-2023-0465" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2023-0465" +cwe = "CWE-119" +commit = "b013765abfa80036dc779dd0e50602c57bb3bf95" +parent = "f675d164e5d9648c3537a0f5efe1cc2fd232b4a9" +commit_url = "https://github.com/openssl/openssl/commit/b013765abfa80036dc779dd0e50602c57bb3bf95" +vuln = "openssl-cve-2023-0465/vuln.c" +fixed = "openssl-cve-2023-0465/fixed.c" +relpath = "crypto/x509/x509_vfy.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/x509/x509_vfy.c" +sink = "unknown" +evidence = "Ensure that EXFLAG_INVALID_POLICY is checked even in leaf certs" + +[[pair]] +name = "openssl-cve-2023-0464" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2023-0464" +cwe = "CWE-119" +commit = "879f7080d7e141f415c79eaa3a8ac4a3dad0348b" +parent = "969327390220aee7515a4054d5189186402d6687" +commit_url = "https://github.com/openssl/openssl/commit/879f7080d7e141f415c79eaa3a8ac4a3dad0348b" +vuln = "openssl-cve-2023-0464/vuln.c" +fixed = "openssl-cve-2023-0464/fixed.c" +relpath = "crypto/x509v3/pcy_tree.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/x509v3/pcy_tree.c" +sink = "unknown" +evidence = "x509: excessive resource use verifying policy constraints" + +[[pair]] +name = "openssl-cve-2023-0464-tree_init" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2023-0464" +cwe = "CWE-119" +commit = "959c59c7a0164117e7f8366466a32bb1f8d77ff1" +parent = "c309c4dce742c3eeb393a0f03f9c567d0e368ccc" +commit_url = "https://github.com/openssl/openssl/commit/959c59c7a0164117e7f8366466a32bb1f8d77ff1" +vuln = "openssl-cve-2023-0464-tree_init/vuln.c" +fixed = "openssl-cve-2023-0464-tree_init/fixed.c" +relpath = "crypto/x509/pcy_tree.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/x509/pcy_tree.c" +sink = "unknown" +evidence = "x509: excessive resource use verifying policy constraints" + +[[pair]] +name = "openssl-cve-2021-3449" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2021-3449" +cwe = "CWE-119" +commit = "2b9e2afc382490592078cdb69d06f54f0fefd4c6" +parent = "7b2625274f5d5ec90aee522ec4e4f3aa08fa5b70" +commit_url = "https://github.com/openssl/openssl/commit/2b9e2afc382490592078cdb69d06f54f0fefd4c6" +vuln = "openssl-cve-2021-3449/vuln.c" +fixed = "openssl-cve-2021-3449/fixed.c" +relpath = "ssl/record/methods/tls_common.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/record/methods/tls_common.c" +sink = "unknown" +evidence = "fuzz: make post handshake reachable" + +[[pair]] +name = "openssl-cve-2021-3449-def_generate_session_id" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2021-3449" +cwe = "CWE-119" +commit = "2b9e2afc382490592078cdb69d06f54f0fefd4c6" +parent = "7b2625274f5d5ec90aee522ec4e4f3aa08fa5b70" +commit_url = "https://github.com/openssl/openssl/commit/2b9e2afc382490592078cdb69d06f54f0fefd4c6" +vuln = "openssl-cve-2021-3449-def_generate_session_id/vuln.c" +fixed = "openssl-cve-2021-3449-def_generate_session_id/fixed.c" +relpath = "ssl/ssl_sess.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/ssl_sess.c" +sink = "unknown" +evidence = "fuzz: make post handshake reachable" + +[[pair]] +name = "openssl-cve-2021-3449-tls_parse_ctos_renegotia" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2021-3449" +cwe = "CWE-119" +commit = "2b9e2afc382490592078cdb69d06f54f0fefd4c6" +parent = "7b2625274f5d5ec90aee522ec4e4f3aa08fa5b70" +commit_url = "https://github.com/openssl/openssl/commit/2b9e2afc382490592078cdb69d06f54f0fefd4c6" +vuln = "openssl-cve-2021-3449-tls_parse_ctos_renegotia/vuln.c" +fixed = "openssl-cve-2021-3449-tls_parse_ctos_renegotia/fixed.c" +relpath = "ssl/statem/extensions_srvr.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/statem/extensions_srvr.c" +sink = "unknown" +evidence = "fuzz: make post handshake reachable" + +[[pair]] +name = "openssl-cve-2021-3449-tls_process_finished" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2021-3449" +cwe = "CWE-119" +commit = "2b9e2afc382490592078cdb69d06f54f0fefd4c6" +parent = "7b2625274f5d5ec90aee522ec4e4f3aa08fa5b70" +commit_url = "https://github.com/openssl/openssl/commit/2b9e2afc382490592078cdb69d06f54f0fefd4c6" +vuln = "openssl-cve-2021-3449-tls_process_finished/vuln.c" +fixed = "openssl-cve-2021-3449-tls_process_finished/fixed.c" +relpath = "ssl/statem/statem_lib.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/statem/statem_lib.c" +sink = "unknown" +evidence = "fuzz: make post handshake reachable" + +[[pair]] +name = "openssl-cve-2023-0401" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2023-0401" +cwe = "CWE-119" +commit = "6eebe6c0238178356114a96a7858f36b24172847" +parent = "7880536fe17c2b5450e279155bedd51771d28c9f" +commit_url = "https://github.com/openssl/openssl/commit/6eebe6c0238178356114a96a7858f36b24172847" +vuln = "openssl-cve-2023-0401/vuln.c" +fixed = "openssl-cve-2023-0401/fixed.c" +relpath = "crypto/pkcs7/pk7_doit.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/pkcs7/pk7_doit.c" +sink = "unknown" +evidence = "pk7_doit.c: Check return of BIO_set_md() calls" + +[[pair]] +name = "openssl-cve-2023-0286-general_name_cmp" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2023-0286" +cwe = "CWE-119" +commit = "7880536fe17c2b5450e279155bedd51771d28c9f" +parent = "adf77d6657e836fc87391fad53d857927a764297" +commit_url = "https://github.com/openssl/openssl/commit/7880536fe17c2b5450e279155bedd51771d28c9f" +vuln = "openssl-cve-2023-0286-general_name_cmp/vuln.c" +fixed = "openssl-cve-2023-0286-general_name_cmp/fixed.c" +relpath = "crypto/x509/v3_genn.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/x509/v3_genn.c" +sink = "unknown" +evidence = "Fix GENERAL_NAME_cmp for x400Address (master)" + +[[pair]] +name = "openssl-cve-2023-0217" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2023-0217" +cwe = "CWE-119" +commit = "bcec03c33cc00a7b5eb89ebeeee59e604570a86a" +parent = "3436f9c24ab90c1661e4798e7944f028d5d251ce" +commit_url = "https://github.com/openssl/openssl/commit/bcec03c33cc00a7b5eb89ebeeee59e604570a86a" +vuln = "openssl-cve-2023-0217/vuln.c" +fixed = "openssl-cve-2023-0217/fixed.c" +relpath = "crypto/ffc/ffc_key_validate.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/ffc/ffc_key_validate.c" +sink = "unknown" +evidence = "Fix NULL deference when validating FFC public key." + +[[pair]] +name = "openssl-cve-2023-0216" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2023-0216" +cwe = "CWE-119" +commit = "80253dbdc92bec584f4a9866b43f8674156d838a" +parent = "625faca931957719c76fb16094cf5b6e0debe23f" +commit_url = "https://github.com/openssl/openssl/commit/80253dbdc92bec584f4a9866b43f8674156d838a" +vuln = "openssl-cve-2023-0216/vuln.c" +fixed = "openssl-cve-2023-0216/fixed.c" +relpath = "crypto/pkcs7/pk7_lib.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/pkcs7/pk7_lib.c" +sink = "unknown" +evidence = "Do not dereference PKCS7 object data if not set" + +[[pair]] +name = "openssl-cve-2022-4304-rsa_ossl_private_decrypt" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2022-4304" +cwe = "CWE-119" +commit = "8022a4799fe884b3bf8d538e2b4c4ec323663118" +parent = "e2d0a3b5f559e23f11e4d4687b2889b483afb22a" +commit_url = "https://github.com/openssl/openssl/commit/8022a4799fe884b3bf8d538e2b4c4ec323663118" +vuln = "openssl-cve-2022-4304-rsa_ossl_private_decrypt/vuln.c" +fixed = "openssl-cve-2022-4304-rsa_ossl_private_decrypt/fixed.c" +relpath = "crypto/rsa/rsa_ossl.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/rsa/rsa_ossl.c" +sink = "unknown" +evidence = "Fix Timing Oracle in RSA decryption" + +[[pair]] +name = "openssl-cve-2020-25659" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2020-25659" +cwe = "CWE-119" +commit = "7fc67e0a33102aa47bbaa56533eeecb98c0450f7" +parent = "1ca61aa56090356bbdbb16cf48916fbd9886c78d" +commit_url = "https://github.com/openssl/openssl/commit/7fc67e0a33102aa47bbaa56533eeecb98c0450f7" +vuln = "openssl-cve-2020-25659/vuln.c" +fixed = "openssl-cve-2020-25659/fixed.c" +relpath = "crypto/rsa/rsa_ossl.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/rsa/rsa_ossl.c" +sink = "unknown" +evidence = "rsa: add implicit rejection in PKCS#1 v1.5" + +[[pair]] +name = "openssl-cve-2022-3996" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2022-3996" +cwe = "CWE-119" +commit = "7725e7bfe6f2ce8146b6552b44e0d226be7638e7" +parent = "9a5c884999a55595e376083b3a165515c8123049" +commit_url = "https://github.com/openssl/openssl/commit/7725e7bfe6f2ce8146b6552b44e0d226be7638e7" +vuln = "openssl-cve-2022-3996/vuln.c" +fixed = "openssl-cve-2022-3996/fixed.c" +relpath = "crypto/x509/pcy_map.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/x509/pcy_map.c" +sink = "unknown" +evidence = "x509: fix double locking problem" + +[[pair]] +name = "openssl-cve-2022-3786-ossl_punycode_decode" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2022-3786" +cwe = "CWE-119" +commit = "680e65b94c916af259bfdc2e25f1ab6e0c7a97d6" +parent = "3b421ebc64c7b52f1b9feb3812bdc7781c784332" +commit_url = "https://github.com/openssl/openssl/commit/680e65b94c916af259bfdc2e25f1ab6e0c7a97d6" +vuln = "openssl-cve-2022-3786-ossl_punycode_decode/vuln.c" +fixed = "openssl-cve-2022-3786-ossl_punycode_decode/fixed.c" +relpath = "crypto/punycode.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "buffer overflow" +path = "crypto/punycode.c" +sink = "memcpy" +evidence = "Fix CVE-2022-3786 in punycode decoder." + +[[pair]] +name = "openssl-cve-2022-3602-ossl_punycode_decode" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2022-3602" +cwe = "CWE-119" +commit = "3b421ebc64c7b52f1b9feb3812bdc7781c784332" +parent = "89d72311327735ef15c804d2adea84a0fb1bfa0a" +commit_url = "https://github.com/openssl/openssl/commit/3b421ebc64c7b52f1b9feb3812bdc7781c784332" +vuln = "openssl-cve-2022-3602-ossl_punycode_decode/vuln.c" +fixed = "openssl-cve-2022-3602-ossl_punycode_decode/fixed.c" +relpath = "crypto/punycode.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/punycode.c" +sink = "unknown" +evidence = "Fix CVE-2022-3602 in punycode decoder." + +[[pair]] +name = "openssl-cve-2022-3358" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2022-3358" +cwe = "CWE-476" +commit = "5485c56679d7c49b96e8fc8ca708b0b7e7c03c4b" +parent = "9f0867da4cbf77ed642717b5e703e09ab2c087a0" +commit_url = "https://github.com/openssl/openssl/commit/5485c56679d7c49b96e8fc8ca708b0b7e7c03c4b" +vuln = "openssl-cve-2022-3358/vuln.c" +fixed = "openssl-cve-2022-3358/fixed.c" +relpath = "crypto/evp/digest.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-476" +class = "null pointer dereference" +path = "crypto/evp/digest.c" +sink = "NULL" +evidence = "Fix usage of custom EVP_CIPHER objects" + +[[pair]] +name = "openssl-cve-2022-3358-evp_cipher_init_internal" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2022-3358" +cwe = "CWE-476" +commit = "5485c56679d7c49b96e8fc8ca708b0b7e7c03c4b" +parent = "9f0867da4cbf77ed642717b5e703e09ab2c087a0" +commit_url = "https://github.com/openssl/openssl/commit/5485c56679d7c49b96e8fc8ca708b0b7e7c03c4b" +vuln = "openssl-cve-2022-3358-evp_cipher_init_internal/vuln.c" +fixed = "openssl-cve-2022-3358-evp_cipher_init_internal/fixed.c" +relpath = "crypto/evp/evp_enc.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-476" +class = "null pointer dereference" +path = "crypto/evp/evp_enc.c" +sink = "NULL" +evidence = "Fix usage of custom EVP_CIPHER objects" + +[[pair]] +name = "openssl-cve-2022-2068-hash_dir" +slice = "vfc" +language = "unknown" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2022-2068" +cwe = "CWE-119" +commit = "2c9c35870601b4a44d86ddbf512b38df38285cfa" +parent = "abebcec7b1a30fbb1fd5c5cbbe8817690c139163" +commit_url = "https://github.com/openssl/openssl/commit/2c9c35870601b4a44d86ddbf512b38df38285cfa" +vuln = "openssl-cve-2022-2068-hash_dir/vuln.in" +fixed = "openssl-cve-2022-2068-hash_dir/fixed.in" +relpath = "tools/c_rehash.in" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "tools/c_rehash.in" +sink = "unknown" +evidence = "Fix file operations in c_rehash." + +[[pair]] +name = "openssl-cve-2022-29242" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2022-29242" +cwe = "CWE-119" +commit = "373de40f3f76c63e4f2684abd86706f3863347ca" +parent = "3be529cd2eb4eb3eaaa7913af619fb9c918d4581" +commit_url = "https://github.com/openssl/openssl/commit/373de40f3f76c63e4f2684abd86706f3863347ca" +vuln = "openssl-cve-2022-29242/vuln.c" +fixed = "openssl-cve-2022-29242/fixed.c" +relpath = "ssl/statem/statem_clnt.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/statem/statem_clnt.c" +sink = "unknown" +evidence = "Use safe pattern for buffer size determining in case of GOST key exchange" + +[[pair]] +name = "openssl-cve-2022-1434" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2022-1434" +cwe = "CWE-119" +commit = "7d56a74a96828985db7354a55227a511615f732b" +parent = "55c80c222293a972587004c185dc5653ae207a0e" +commit_url = "https://github.com/openssl/openssl/commit/7d56a74a96828985db7354a55227a511615f732b" +vuln = "openssl-cve-2022-1434/vuln.c" +fixed = "openssl-cve-2022-1434/fixed.c" +relpath = "providers/implementations/ciphers/cipher_rc4_hmac_md5.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "providers/implementations/ciphers/cipher_rc4_hmac_md5.c" +sink = "unknown" +evidence = "Fix the RC4-MD5 cipher" + +[[pair]] +name = "openssl-cve-2022-1343" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "Apache-2.0" +repo = "openssl/openssl" +cve = "CVE-2022-1343" +cwe = "CWE-119" +commit = "2eda98790c5c2741d76d23cc1e74b0dc4f4b391a" +parent = "ae3ece03a61e8822fd7ea58f44812871efba82d1" +commit_url = "https://github.com/openssl/openssl/commit/2eda98790c5c2741d76d23cc1e74b0dc4f4b391a" +vuln = "openssl-cve-2022-1343/vuln.c" +fixed = "openssl-cve-2022-1343/fixed.c" +relpath = "crypto/ocsp/ocsp_vfy.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/ocsp/ocsp_vfy.c" +sink = "unknown" +evidence = "Fix OCSP_basic_verify signer certificate validation" + +[[pair]] +name = "openssl-cve-2021-4044" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2021-4044" +cwe = "CWE-119" +commit = "d69ae8a93bfc0f2489c008fcf303a98d77a6df4d" +parent = "758754966791c537ea95241438454aa86f91f256" +commit_url = "https://github.com/openssl/openssl/commit/d69ae8a93bfc0f2489c008fcf303a98d77a6df4d" +vuln = "openssl-cve-2021-4044/vuln.c" +fixed = "openssl-cve-2021-4044/fixed.c" +relpath = "crypto/x509/x509_vfy.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/x509/x509_vfy.c" +sink = "unknown" +evidence = "Fix infinite verification loops due to has_san_id" + +[[pair]] +name = "openssl-cve-2021-4044-tls_post_process_server_" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2021-4044" +cwe = "CWE-119" +commit = "758754966791c537ea95241438454aa86f91f256" +parent = "8e78289c4e6f4c9f2fec073b78443736e689854d" +commit_url = "https://github.com/openssl/openssl/commit/758754966791c537ea95241438454aa86f91f256" +vuln = "openssl-cve-2021-4044-tls_post_process_server_/vuln.c" +fixed = "openssl-cve-2021-4044-tls_post_process_server_/fixed.c" +relpath = "ssl/statem/statem_clnt.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/statem/statem_clnt.c" +sink = "unknown" +evidence = "Fix invalid handling of verify errors in libssl" + +[[pair]] +name = "openssl-cve-2021-3711-sm2_asym_decrypt" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2021-3711" +cwe = "CWE-119" +commit = "36cf45ef3ba71e44a8be06ee81cb31aa02cb0010" +parent = "4b8a8bb75229b64d1c7598d845fdc3c7e7d7eee2" +commit_url = "https://github.com/openssl/openssl/commit/36cf45ef3ba71e44a8be06ee81cb31aa02cb0010" +vuln = "openssl-cve-2021-3711-sm2_asym_decrypt/vuln.c" +fixed = "openssl-cve-2021-3711-sm2_asym_decrypt/fixed.c" +relpath = "providers/implementations/asymciphers/sm2_enc.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "providers/implementations/asymciphers/sm2_enc.c" +sink = "unknown" +evidence = "Correctly calculate the length of SM2 plaintext given the ciphertext" + +[[pair]] +name = "openssl-cve-2021-3712-netscape_spki_print" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2021-3712" +cwe = "CWE-119" +commit = "7c038a6bcd98d4bbfd2c2892a87a1138d2f7c5f3" +parent = "98624776c4d501c8badd6f772ab7048ac9191cb9" +commit_url = "https://github.com/openssl/openssl/commit/7c038a6bcd98d4bbfd2c2892a87a1138d2f7c5f3" +vuln = "openssl-cve-2021-3712-netscape_spki_print/vuln.c" +fixed = "openssl-cve-2021-3712-netscape_spki_print/fixed.c" +relpath = "crypto/asn1/t_spki.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/asn1/t_spki.c" +sink = "unknown" +evidence = "Fix NETSCAPE_SPKI_print function to not assume NUL terminated strings" + +[[pair]] +name = "openssl-cve-2021-3712-append_ia5" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2021-3712" +cwe = "CWE-119" +commit = "98624776c4d501c8badd6f772ab7048ac9191cb9" +parent = "1f365708a3318a5f1a395f90c38b584a58d37fb9" +commit_url = "https://github.com/openssl/openssl/commit/98624776c4d501c8badd6f772ab7048ac9191cb9" +vuln = "openssl-cve-2021-3712-append_ia5/vuln.c" +fixed = "openssl-cve-2021-3712-append_ia5/fixed.c" +relpath = "crypto/x509/v3_utl.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/x509/v3_utl.c" +sink = "unknown" +evidence = "Fix append_ia5 function to not assume NUL terminated strings" + +[[pair]] +name = "openssl-cve-2021-3712-ossl_cmp_hdr_push1_freet" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2021-3712" +cwe = "CWE-119" +commit = "95f8c1e142df835d03b5b62521383a462fc5470d" +parent = "d2015a783e64613d8e4a142fa05048d1863df944" +commit_url = "https://github.com/openssl/openssl/commit/95f8c1e142df835d03b5b62521383a462fc5470d" +vuln = "openssl-cve-2021-3712-ossl_cmp_hdr_push1_freet/vuln.c" +fixed = "openssl-cve-2021-3712-ossl_cmp_hdr_push1_freet/fixed.c" +relpath = "crypto/cmp/cmp_hdr.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/cmp/cmp_hdr.c" +sink = "unknown" +evidence = "Fix CMP code to not assume NUL terminated strings" + +[[pair]] +name = "openssl-cve-2021-3712-ia5ncasecmp" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2021-3712" +cwe = "CWE-119" +commit = "d2015a783e64613d8e4a142fa05048d1863df944" +parent = "918430ba80d94ec8f05383b43b1872b1ebb13e1a" +commit_url = "https://github.com/openssl/openssl/commit/d2015a783e64613d8e4a142fa05048d1863df944" +vuln = "openssl-cve-2021-3712-ia5ncasecmp/vuln.c" +fixed = "openssl-cve-2021-3712-ia5ncasecmp/fixed.c" +relpath = "crypto/x509/v3_ncons.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/x509/v3_ncons.c" +sink = "unknown" +evidence = "Fix the name constraints code to not assume NUL terminated strings" + +[[pair]] +name = "openssl-cve-2021-3712-i2r_pci" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2021-3712" +cwe = "CWE-119" +commit = "918430ba80d94ec8f05383b43b1872b1ebb13e1a" +parent = "b2b3b9c9936b91315adc0f3254879cb2fd5ca2bd" +commit_url = "https://github.com/openssl/openssl/commit/918430ba80d94ec8f05383b43b1872b1ebb13e1a" +vuln = "openssl-cve-2021-3712-i2r_pci/vuln.c" +fixed = "openssl-cve-2021-3712-i2r_pci/fixed.c" +relpath = "crypto/x509/v3_pci.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/x509/v3_pci.c" +sink = "unknown" +evidence = "Fix printing of PROXY_CERT_INFO_EXTENSION to not assume NUL terminated strings" + +[[pair]] +name = "openssl-cve-2021-3712-general_name_print" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2021-3712" +cwe = "CWE-119" +commit = "b2b3b9c9936b91315adc0f3254879cb2fd5ca2bd" +parent = "1747d4658b3830951068a6a6c1fa2b45c4731fb3" +commit_url = "https://github.com/openssl/openssl/commit/b2b3b9c9936b91315adc0f3254879cb2fd5ca2bd" +vuln = "openssl-cve-2021-3712-general_name_print/vuln.c" +fixed = "openssl-cve-2021-3712-general_name_print/fixed.c" +relpath = "crypto/x509/v3_san.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/x509/v3_san.c" +sink = "unknown" +evidence = "Fix GENERAL_NAME_print to not assume NUL terminated strings" + +[[pair]] +name = "openssl-cve-2021-3712-print_qualifiers" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2021-3712" +cwe = "CWE-119" +commit = "1747d4658b3830951068a6a6c1fa2b45c4731fb3" +parent = "ad6ac17489241574136b7d035f01f6175dd9c941" +commit_url = "https://github.com/openssl/openssl/commit/1747d4658b3830951068a6a6c1fa2b45c4731fb3" +vuln = "openssl-cve-2021-3712-print_qualifiers/vuln.c" +fixed = "openssl-cve-2021-3712-print_qualifiers/fixed.c" +relpath = "crypto/x509/v3_cpols.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/x509/v3_cpols.c" +sink = "unknown" +evidence = "Fix POLICYINFO printing to not assume NUL terminated strings" + +[[pair]] +name = "openssl-cve-2021-3711-pkey_sm2_decrypt" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2021-3711" +cwe = "CWE-119" +commit = "59f5e75f3bced8fc0e130d72a3f582cf7b480b46" +parent = "8c74c9d1ade0fbdab5b815ddb747351b8b839641" +commit_url = "https://github.com/openssl/openssl/commit/59f5e75f3bced8fc0e130d72a3f582cf7b480b46" +vuln = "openssl-cve-2021-3711-pkey_sm2_decrypt/vuln.c" +fixed = "openssl-cve-2021-3711-pkey_sm2_decrypt/fixed.c" +relpath = "crypto/sm2/sm2_pmeth.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/sm2/sm2_pmeth.c" +sink = "unknown" +evidence = "Correctly calculate the length of SM2 plaintext given the ciphertext" + +[[pair]] +name = "openssl-cve-2021-3449-ssl_generate_master_secr" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2021-3449" +cwe = "CWE-119" +commit = "39a140597d874e554b736885ac4dea16ac40a87a" +parent = "02b1636fe3db274497304a3e95a4e32ced7e841b" +commit_url = "https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a" +vuln = "openssl-cve-2021-3449-ssl_generate_master_secr/vuln.c" +fixed = "openssl-cve-2021-3449-ssl_generate_master_secr/fixed.c" +relpath = "ssl/s3_lib.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/s3_lib.c" +sink = "unknown" +evidence = "Ensure buffer/length pairs are always in sync" + +[[pair]] +name = "openssl-cve-2021-3449-ssl_ctx_set_alpn_protos" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2021-3449" +cwe = "CWE-119" +commit = "39a140597d874e554b736885ac4dea16ac40a87a" +parent = "02b1636fe3db274497304a3e95a4e32ced7e841b" +commit_url = "https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a" +vuln = "openssl-cve-2021-3449-ssl_ctx_set_alpn_protos/vuln.c" +fixed = "openssl-cve-2021-3449-ssl_ctx_set_alpn_protos/fixed.c" +relpath = "ssl/ssl_lib.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/ssl_lib.c" +sink = "unknown" +evidence = "Ensure buffer/length pairs are always in sync" + +[[pair]] +name = "openssl-cve-2021-3449-init_sig_algs_cert" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2021-3449" +cwe = "CWE-119" +commit = "39a140597d874e554b736885ac4dea16ac40a87a" +parent = "02b1636fe3db274497304a3e95a4e32ced7e841b" +commit_url = "https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a" +vuln = "openssl-cve-2021-3449-init_sig_algs_cert/vuln.c" +fixed = "openssl-cve-2021-3449-init_sig_algs_cert/fixed.c" +relpath = "ssl/statem/extensions.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/statem/extensions.c" +sink = "unknown" +evidence = "Ensure buffer/length pairs are always in sync" + +[[pair]] +name = "openssl-cve-2021-3449-tls_construct_ctos_early" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2021-3449" +cwe = "CWE-119" +commit = "39a140597d874e554b736885ac4dea16ac40a87a" +parent = "02b1636fe3db274497304a3e95a4e32ced7e841b" +commit_url = "https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a" +vuln = "openssl-cve-2021-3449-tls_construct_ctos_early/vuln.c" +fixed = "openssl-cve-2021-3449-tls_construct_ctos_early/fixed.c" +relpath = "ssl/statem/extensions_clnt.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/statem/extensions_clnt.c" +sink = "unknown" +evidence = "Ensure buffer/length pairs are always in sync" + +[[pair]] +name = "openssl-cve-2021-3449-tls_process_certificate_" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2021-3449" +cwe = "CWE-119" +commit = "39a140597d874e554b736885ac4dea16ac40a87a" +parent = "02b1636fe3db274497304a3e95a4e32ced7e841b" +commit_url = "https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a" +vuln = "openssl-cve-2021-3449-tls_process_certificate_/vuln.c" +fixed = "openssl-cve-2021-3449-tls_process_certificate_/fixed.c" +relpath = "ssl/statem/statem_clnt.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/statem/statem_clnt.c" +sink = "unknown" +evidence = "Ensure buffer/length pairs are always in sync" + +[[pair]] +name = "openssl-cve-2021-3449-tls_handle_alpn" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2021-3449" +cwe = "CWE-119" +commit = "39a140597d874e554b736885ac4dea16ac40a87a" +parent = "02b1636fe3db274497304a3e95a4e32ced7e841b" +commit_url = "https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a" +vuln = "openssl-cve-2021-3449-tls_handle_alpn/vuln.c" +fixed = "openssl-cve-2021-3449-tls_handle_alpn/fixed.c" +relpath = "ssl/statem/statem_srvr.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "ssl/statem/statem_srvr.c" +sink = "unknown" +evidence = "Ensure buffer/length pairs are always in sync" + +[[pair]] +name = "openssl-cve-2021-3449-init_sig_algs" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2021-3449" +cwe = "CWE-476" +commit = "02b1636fe3db274497304a3e95a4e32ced7e841b" +parent = "112580c27b829b0ac0874d5c5787195f27c7952c" +commit_url = "https://github.com/openssl/openssl/commit/02b1636fe3db274497304a3e95a4e32ced7e841b" +vuln = "openssl-cve-2021-3449-init_sig_algs/vuln.c" +fixed = "openssl-cve-2021-3449-init_sig_algs/fixed.c" +relpath = "ssl/statem/extensions.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-476" +class = "null pointer dereference" +path = "ssl/statem/extensions.c" +sink = "NULL" +evidence = "ssl sigalg extension: fix NULL pointer dereference" + +[[pair]] +name = "openssl-cve-2021-3450" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2021-3450" +cwe = "CWE-119" +commit = "2a40b7bc7b94dd7de897a74571e7024f0cf0d63b" +parent = "cfd74383d9b06f85cb1e166180346115a3f9a452" +commit_url = "https://github.com/openssl/openssl/commit/2a40b7bc7b94dd7de897a74571e7024f0cf0d63b" +vuln = "openssl-cve-2021-3450/vuln.c" +fixed = "openssl-cve-2021-3450/fixed.c" +relpath = "crypto/x509/x509_vfy.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/x509/x509_vfy.c" +sink = "unknown" +evidence = "check_chain_extensions: Do not override error return value by check_curve" + +[[pair]] +name = "openssl-cve-2021-23840-evp_encryptdecryptupdate" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2021-23840" +cwe = "CWE-119" +commit = "6a51b9e1d0cf0bf8515f7201b68fb0a3482b3dc1" +parent = "481a88f13c44996a008195791ea0dc076b968774" +commit_url = "https://github.com/openssl/openssl/commit/6a51b9e1d0cf0bf8515f7201b68fb0a3482b3dc1" +vuln = "openssl-cve-2021-23840-evp_encryptdecryptupdate/vuln.c" +fixed = "openssl-cve-2021-23840-evp_encryptdecryptupdate/fixed.c" +relpath = "crypto/evp/evp_enc.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "buffer overflow" +path = "crypto/evp/evp_enc.c" +sink = "memcpy" +evidence = "Don't overflow the output length in EVP_CipherUpdate calls" + +[[pair]] +name = "openssl-cve-2021-23841" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2021-23841" +cwe = "CWE-476" +commit = "122a19ab48091c657f7cb1fb3af9fc07bd557bbf" +parent = "c8c6e7438c03b2fc24e7ead460feeaef04911fb4" +commit_url = "https://github.com/openssl/openssl/commit/122a19ab48091c657f7cb1fb3af9fc07bd557bbf" +vuln = "openssl-cve-2021-23841/vuln.c" +fixed = "openssl-cve-2021-23841/fixed.c" +relpath = "crypto/x509/x509_cmp.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-476" +class = "null pointer dereference" +path = "crypto/x509/x509_cmp.c" +sink = "NULL" +evidence = "Fix Null pointer deref in X509_issuer_and_serial_hash()" + +[[pair]] +name = "openssl-cve-2020-1971-general_name_cmp" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2020-1971" +cwe = "CWE-119" +commit = "f960d81215ebf3f65e03d4d5d857fb9b666d6920" +parent = "aa0ad2011d3e7ad8a611da274ef7d9c7706e289b" +commit_url = "https://github.com/openssl/openssl/commit/f960d81215ebf3f65e03d4d5d857fb9b666d6920" +vuln = "openssl-cve-2020-1971-general_name_cmp/vuln.c" +fixed = "openssl-cve-2020-1971-general_name_cmp/fixed.c" +relpath = "crypto/x509v3/v3_genn.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "crypto/x509v3/v3_genn.c" +sink = "unknown" +evidence = "Correctly compare EdiPartyName in GENERAL_NAME_cmp()" + +[[pair]] +name = "openssl-cve-2020-1967-tls1_check_sig_alg" +slice = "vfc" +language = "c_cpp" +origin = "openssl" +license = "OpenSSL License" +repo = "openssl/openssl" +cve = "CVE-2020-1967" +cwe = "CWE-476" +commit = "a87f3fe01a5a894aa27ccd6a239155fd129988e4" +parent = "3656c08ab4b1b892730cb5e808b6f4298b08a2e6" +commit_url = "https://github.com/openssl/openssl/commit/a87f3fe01a5a894aa27ccd6a239155fd129988e4" +vuln = "openssl-cve-2020-1967-tls1_check_sig_alg/vuln.c" +fixed = "openssl-cve-2020-1967-tls1_check_sig_alg/fixed.c" +relpath = "ssl/t1_lib.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-476" +class = "null pointer dereference" +path = "ssl/t1_lib.c" +sink = "NULL" +evidence = "Fix NULL dereference in SSL_check_chain() for TLS 1.3" + +[[pair]] +name = "curl-cve-2026-9080" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2026-9080" +cwe = "CWE-119" +commit = "e9a2b0dc72dd3a9aa3a5210e89079a3b719475dc" +parent = "f746780a1e548b4b93790b58d70c3b22fde5360d" +commit_url = "https://github.com/curl/curl/commit/e9a2b0dc72dd3a9aa3a5210e89079a3b719475dc" +vuln = "curl-cve-2026-9080/vuln.c" +fixed = "curl-cve-2026-9080/fixed.c" +relpath = "lib/multi_ev.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/multi_ev.c" +sink = "unknown" +evidence = "multi_ev: refresh sock entry after remove callback" + +[[pair]] +name = "curl-cve-2023-38545-do_socks5" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2023-38545" +cwe = "CWE-119" +commit = "fb4415d8aee6c1045be932a34fe6107c2f5ed147" +parent = "09e25b9d94f4106eac8ca3a43b221bdc66f405e4" +commit_url = "https://github.com/curl/curl/commit/fb4415d8aee6c1045be932a34fe6107c2f5ed147" +vuln = "curl-cve-2023-38545-do_socks5/vuln.c" +fixed = "curl-cve-2023-38545-do_socks5/fixed.c" +relpath = "lib/socks.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/socks.c" +sink = "unknown" +evidence = "socks: return error if hostname too long for remote resolve" + +[[pair]] +name = "curl-cve-2022-32207" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2022-32207" +cwe = "CWE-119" +commit = "20f9dd6bae50b7223171b17ba7798946e74f877f" +parent = "46f8911d3942dc06fdd67e9f6f3908982e5d2fb4" +commit_url = "https://github.com/curl/curl/commit/20f9dd6bae50b7223171b17ba7798946e74f877f" +vuln = "curl-cve-2022-32207/vuln.c" +fixed = "curl-cve-2022-32207/fixed.c" +relpath = "lib/cookie.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/cookie.c" +sink = "unknown" +evidence = "fopen: add Curl_fopen() for better overwriting of files" + +[[pair]] +name = "curl-cve-2022-32206" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2022-32206" +cwe = "CWE-119" +commit = "3a09fbb7f264c67c438d01a30669ce325aa508e2" +parent = "6ecdf5136b52af747e7bda08db9a748256b1cd09" +commit_url = "https://github.com/curl/curl/commit/3a09fbb7f264c67c438d01a30669ce325aa508e2" +vuln = "curl-cve-2022-32206/vuln.c" +fixed = "curl-cve-2022-32206/fixed.c" +relpath = "lib/content_encoding.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/content_encoding.c" +sink = "unknown" +evidence = "content_encoding: return error on too many compression steps" + +[[pair]] +name = "curl-cve-2022-32208" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2022-32208" +cwe = "CWE-119" +commit = "6ecdf5136b52af747e7bda08db9a748256b1cd09" +parent = "2b67a0a1129b20a56ed04859fec8999f5c0c4280" +commit_url = "https://github.com/curl/curl/commit/6ecdf5136b52af747e7bda08db9a748256b1cd09" +vuln = "curl-cve-2022-32208/vuln.c" +fixed = "curl-cve-2022-32208/fixed.c" +relpath = "lib/krb5.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/krb5.c" +sink = "unknown" +evidence = "krb5: return error properly on decode errors" + +[[pair]] +name = "curl-cve-2022-27782-curl_init_userdefined" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2022-27782" +cwe = "CWE-119" +commit = "f18af4f874cecab82a9797e8c7541e0990c7a64c" +parent = "7e92d12b4e6911f424678a133b19de670e183a59" +commit_url = "https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c" +vuln = "curl-cve-2022-27782-curl_init_userdefined/vuln.c" +fixed = "curl-cve-2022-27782-curl_init_userdefined/fixed.c" +relpath = "lib/url.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/url.c" +sink = "unknown" +evidence = "tls: check more TLS details for connection reuse" + +[[pair]] +name = "curl-cve-2022-27782-gtls_shutdown" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2022-27782" +cwe = "CWE-119" +commit = "f18af4f874cecab82a9797e8c7541e0990c7a64c" +parent = "7e92d12b4e6911f424678a133b19de670e183a59" +commit_url = "https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c" +vuln = "curl-cve-2022-27782-gtls_shutdown/vuln.c" +fixed = "curl-cve-2022-27782-gtls_shutdown/fixed.c" +relpath = "lib/vtls/gtls.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/vtls/gtls.c" +sink = "unknown" +evidence = "tls: check more TLS details for connection reuse" + +[[pair]] +name = "curl-cve-2022-27782-nss_setup_connect" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2022-27782" +cwe = "CWE-119" +commit = "f18af4f874cecab82a9797e8c7541e0990c7a64c" +parent = "7e92d12b4e6911f424678a133b19de670e183a59" +commit_url = "https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c" +vuln = "curl-cve-2022-27782-nss_setup_connect/vuln.c" +fixed = "curl-cve-2022-27782-nss_setup_connect/fixed.c" +relpath = "lib/vtls/nss.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/vtls/nss.c" +sink = "unknown" +evidence = "tls: check more TLS details for connection reuse" + +[[pair]] +name = "curl-cve-2022-27782-ossl_connect_step1" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2022-27782" +cwe = "CWE-119" +commit = "f18af4f874cecab82a9797e8c7541e0990c7a64c" +parent = "7e92d12b4e6911f424678a133b19de670e183a59" +commit_url = "https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c" +vuln = "curl-cve-2022-27782-ossl_connect_step1/vuln.c" +fixed = "curl-cve-2022-27782-ossl_connect_step1/fixed.c" +relpath = "lib/vtls/openssl.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/vtls/openssl.c" +sink = "unknown" +evidence = "tls: check more TLS details for connection reuse" + +[[pair]] +name = "curl-cve-2022-27782-curl_free_primary_ssl_co" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2022-27782" +cwe = "CWE-119" +commit = "f18af4f874cecab82a9797e8c7541e0990c7a64c" +parent = "7e92d12b4e6911f424678a133b19de670e183a59" +commit_url = "https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c" +vuln = "curl-cve-2022-27782-curl_free_primary_ssl_co/vuln.c" +fixed = "curl-cve-2022-27782-curl_free_primary_ssl_co/fixed.c" +relpath = "lib/vtls/vtls.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/vtls/vtls.c" +sink = "unknown" +evidence = "tls: check more TLS details for connection reuse" + +[[pair]] +name = "curl-cve-2022-27778" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2022-27778" +cwe = "CWE-119" +commit = "8c7ee9083d0d719d0a77ab20d9cc2ae84eeea7f3" +parent = "fae6fea209a2d4db1582f608bd8cc8000721733a" +commit_url = "https://github.com/curl/curl/commit/8c7ee9083d0d719d0a77ab20d9cc2ae84eeea7f3" +vuln = "curl-cve-2022-27778/vuln.c" +fixed = "curl-cve-2022-27778/fixed.c" +relpath = "src/tool_operate.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "src/tool_operate.c" +sink = "unknown" +evidence = "post_per_transfer: remove the updated file name" + +[[pair]] +name = "curl-cve-2022-30115" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2022-30115" +cwe = "CWE-119" +commit = "fae6fea209a2d4db1582f608bd8cc8000721733a" +parent = "ff3ee510c328db03bf171cae6179bb9463fb054f" +commit_url = "https://github.com/curl/curl/commit/fae6fea209a2d4db1582f608bd8cc8000721733a" +vuln = "curl-cve-2022-30115/vuln.c" +fixed = "curl-cve-2022-30115/fixed.c" +relpath = "lib/hsts.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/hsts.c" +sink = "unknown" +evidence = "hsts: ignore trailing dots when comparing hosts names" + +[[pair]] +name = "curl-cve-2022-27780" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2022-27780" +cwe = "CWE-119" +commit = "914aaab9153764ef8fa4178215b8ad89d3ac263a" +parent = "5c7da89d404bf59c8dd82a001119a16d18365917" +commit_url = "https://github.com/curl/curl/commit/914aaab9153764ef8fa4178215b8ad89d3ac263a" +vuln = "curl-cve-2022-27780/vuln.c" +fixed = "curl-cve-2022-27780/fixed.c" +relpath = "lib/urlapi.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/urlapi.c" +sink = "unknown" +evidence = "urlapi: reject percent-decoding host name into separator bytes" + +[[pair]] +name = "curl-cve-2022-27774" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2022-27774" +cwe = "CWE-119" +commit = "620ea21410030a9977396b4661806bc187231b79" +parent = "08b8ef4e726ba10f45081ecda5b3cea788d3c839" +commit_url = "https://github.com/curl/curl/commit/620ea21410030a9977396b4661806bc187231b79" +vuln = "curl-cve-2022-27774/vuln.c" +fixed = "curl-cve-2022-27774/fixed.c" +relpath = "lib/transfer.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/transfer.c" +sink = "unknown" +evidence = "transfer: redirects to other protocols or ports clear auth" + +[[pair]] +name = "curl-cve-2022-27776" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2022-27776" +cwe = "CWE-119" +commit = "6e659993952aa5f90f48864be84a1bbb047fc258" +parent = "8f2079154f80561ccffcaa954268798b658e66b6" +commit_url = "https://github.com/curl/curl/commit/6e659993952aa5f90f48864be84a1bbb047fc258" +vuln = "curl-cve-2022-27776/vuln.c" +fixed = "curl-cve-2022-27776/fixed.c" +relpath = "lib/http.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/http.c" +sink = "unknown" +evidence = "http: avoid auth/cookie on redirects same host diff port" + +[[pair]] +name = "curl-cve-2022-27775" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2022-27775" +cwe = "CWE-119" +commit = "058f98dc3fe595f21dc26a5b9b1699e519ba5705" +parent = "852aa5ad351ea53e5f01d2f44b5b4370c2bf5425" +commit_url = "https://github.com/curl/curl/commit/058f98dc3fe595f21dc26a5b9b1699e519ba5705" +vuln = "curl-cve-2022-27775/vuln.c" +fixed = "curl-cve-2022-27775/fixed.c" +relpath = "lib/conncache.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/conncache.c" +sink = "unknown" +evidence = "conncache: include the zone id in the \"bundle\" hashkey" + +[[pair]] +name = "curl-cve-2022-22576-conn_free" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2022-22576" +cwe = "CWE-119" +commit = "852aa5ad351ea53e5f01d2f44b5b4370c2bf5425" +parent = "ff2f3e836702daa82e2356195482fcc95f4257dc" +commit_url = "https://github.com/curl/curl/commit/852aa5ad351ea53e5f01d2f44b5b4370c2bf5425" +vuln = "curl-cve-2022-22576-conn_free/vuln.c" +fixed = "curl-cve-2022-22576-conn_free/fixed.c" +relpath = "lib/url.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/url.c" +sink = "unknown" +evidence = "url: check sasl additional parameters for connection reuse." + +[[pair]] +name = "curl-cve-2021-22947" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2021-22947" +cwe = "CWE-119" +commit = "8ef147c43646e91fdaad5d0e7b60351f842e5c68" +parent = "364f174724ef115c63d5e5dc1d3342c8a43b1cca" +commit_url = "https://github.com/curl/curl/commit/8ef147c43646e91fdaad5d0e7b60351f842e5c68" +vuln = "curl-cve-2021-22947/vuln.c" +fixed = "curl-cve-2021-22947/fixed.c" +relpath = "lib/ftp.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/ftp.c" +sink = "unknown" +evidence = "ftp,imap,pop3,smtp: reject STARTTLS server response pipelining" + +[[pair]] +name = "curl-cve-2021-22947-imap_state_starttls_resp" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2021-22947" +cwe = "CWE-119" +commit = "8ef147c43646e91fdaad5d0e7b60351f842e5c68" +parent = "364f174724ef115c63d5e5dc1d3342c8a43b1cca" +commit_url = "https://github.com/curl/curl/commit/8ef147c43646e91fdaad5d0e7b60351f842e5c68" +vuln = "curl-cve-2021-22947-imap_state_starttls_resp/vuln.c" +fixed = "curl-cve-2021-22947-imap_state_starttls_resp/fixed.c" +relpath = "lib/imap.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/imap.c" +sink = "unknown" +evidence = "ftp,imap,pop3,smtp: reject STARTTLS server response pipelining" + +[[pair]] +name = "curl-cve-2021-22947-pop3_state_starttls_resp" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2021-22947" +cwe = "CWE-119" +commit = "8ef147c43646e91fdaad5d0e7b60351f842e5c68" +parent = "364f174724ef115c63d5e5dc1d3342c8a43b1cca" +commit_url = "https://github.com/curl/curl/commit/8ef147c43646e91fdaad5d0e7b60351f842e5c68" +vuln = "curl-cve-2021-22947-pop3_state_starttls_resp/vuln.c" +fixed = "curl-cve-2021-22947-pop3_state_starttls_resp/fixed.c" +relpath = "lib/pop3.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/pop3.c" +sink = "unknown" +evidence = "ftp,imap,pop3,smtp: reject STARTTLS server response pipelining" + +[[pair]] +name = "curl-cve-2021-22947-smtp_state_starttls_resp" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2021-22947" +cwe = "CWE-119" +commit = "8ef147c43646e91fdaad5d0e7b60351f842e5c68" +parent = "364f174724ef115c63d5e5dc1d3342c8a43b1cca" +commit_url = "https://github.com/curl/curl/commit/8ef147c43646e91fdaad5d0e7b60351f842e5c68" +vuln = "curl-cve-2021-22947-smtp_state_starttls_resp/vuln.c" +fixed = "curl-cve-2021-22947-smtp_state_starttls_resp/fixed.c" +relpath = "lib/smtp.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/smtp.c" +sink = "unknown" +evidence = "ftp,imap,pop3,smtp: reject STARTTLS server response pipelining" + +[[pair]] +name = "curl-cve-2021-22946" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2021-22946" +cwe = "CWE-119" +commit = "364f174724ef115c63d5e5dc1d3342c8a43b1cca" +parent = "43157490a5054bd24256fe12876931e8abc9df49" +commit_url = "https://github.com/curl/curl/commit/364f174724ef115c63d5e5dc1d3342c8a43b1cca" +vuln = "curl-cve-2021-22946/vuln.c" +fixed = "curl-cve-2021-22946/fixed.c" +relpath = "lib/ftp.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/ftp.c" +sink = "unknown" +evidence = "ftp,imap,pop3: do not ignore --ssl-reqd" + +[[pair]] +name = "curl-cve-2021-22946-imap_state_capability_re" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2021-22946" +cwe = "CWE-119" +commit = "364f174724ef115c63d5e5dc1d3342c8a43b1cca" +parent = "43157490a5054bd24256fe12876931e8abc9df49" +commit_url = "https://github.com/curl/curl/commit/364f174724ef115c63d5e5dc1d3342c8a43b1cca" +vuln = "curl-cve-2021-22946-imap_state_capability_re/vuln.c" +fixed = "curl-cve-2021-22946-imap_state_capability_re/fixed.c" +relpath = "lib/imap.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/imap.c" +sink = "unknown" +evidence = "ftp,imap,pop3: do not ignore --ssl-reqd" + +[[pair]] +name = "curl-cve-2021-22946-pop3_state_capa_resp" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2021-22946" +cwe = "CWE-119" +commit = "364f174724ef115c63d5e5dc1d3342c8a43b1cca" +parent = "43157490a5054bd24256fe12876931e8abc9df49" +commit_url = "https://github.com/curl/curl/commit/364f174724ef115c63d5e5dc1d3342c8a43b1cca" +vuln = "curl-cve-2021-22946-pop3_state_capa_resp/vuln.c" +fixed = "curl-cve-2021-22946-pop3_state_capa_resp/fixed.c" +relpath = "lib/pop3.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/pop3.c" +sink = "unknown" +evidence = "ftp,imap,pop3: do not ignore --ssl-reqd" + +[[pair]] +name = "curl-cve-2021-22945" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2021-22945" +cwe = "CWE-119" +commit = "43157490a5054bd24256fe12876931e8abc9df49" +parent = "409a4412409371db00af0a3fe987e517bfab3d19" +commit_url = "https://github.com/curl/curl/commit/43157490a5054bd24256fe12876931e8abc9df49" +vuln = "curl-cve-2021-22945/vuln.c" +fixed = "curl-cve-2021-22945/fixed.c" +relpath = "lib/mqtt.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/mqtt.c" +sink = "unknown" +evidence = "mqtt: clear the leftovers pointer when sending succeeds" + +[[pair]] +name = "curl-cve-2021-22924" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2021-22924" +cwe = "CWE-119" +commit = "5ea3145850ebff1dc2b13d17440300a01ca38161" +parent = "fd9b40bf8dfd43edcbc0d254d613d95a11061c05" +commit_url = "https://github.com/curl/curl/commit/5ea3145850ebff1dc2b13d17440300a01ca38161" +vuln = "curl-cve-2021-22924/vuln.c" +fixed = "curl-cve-2021-22924/fixed.c" +relpath = "lib/url.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/url.c" +sink = "unknown" +evidence = "vtls: fix connection reuse checks for issuer cert and case sensitivity" + +[[pair]] +name = "curl-cve-2021-22924-nss_do_connect" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2021-22924" +cwe = "CWE-119" +commit = "5ea3145850ebff1dc2b13d17440300a01ca38161" +parent = "fd9b40bf8dfd43edcbc0d254d613d95a11061c05" +commit_url = "https://github.com/curl/curl/commit/5ea3145850ebff1dc2b13d17440300a01ca38161" +vuln = "curl-cve-2021-22924-nss_do_connect/vuln.c" +fixed = "curl-cve-2021-22924-nss_do_connect/fixed.c" +relpath = "lib/vtls/nss.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/vtls/nss.c" +sink = "unknown" +evidence = "vtls: fix connection reuse checks for issuer cert and case sensitivity" + +[[pair]] +name = "curl-cve-2021-22924-servercert" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2021-22924" +cwe = "CWE-119" +commit = "5ea3145850ebff1dc2b13d17440300a01ca38161" +parent = "fd9b40bf8dfd43edcbc0d254d613d95a11061c05" +commit_url = "https://github.com/curl/curl/commit/5ea3145850ebff1dc2b13d17440300a01ca38161" +vuln = "curl-cve-2021-22924-servercert/vuln.c" +fixed = "curl-cve-2021-22924-servercert/fixed.c" +relpath = "lib/vtls/openssl.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/vtls/openssl.c" +sink = "unknown" +evidence = "vtls: fix connection reuse checks for issuer cert and case sensitivity" + +[[pair]] +name = "curl-cve-2021-22925" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2021-22925" +cwe = "CWE-119" +commit = "894f6ec730597eb243618d33cc84d71add8d6a8a" +parent = "12284e008bad5156b67d0ac253331a96d77201d1" +commit_url = "https://github.com/curl/curl/commit/894f6ec730597eb243618d33cc84d71add8d6a8a" +vuln = "curl-cve-2021-22925/vuln.c" +fixed = "curl-cve-2021-22925/fixed.c" +relpath = "lib/telnet.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/telnet.c" +sink = "unknown" +evidence = "telnet: fix option parser to not send uninitialized contents" + +[[pair]] +name = "curl-cve-2021-22901-ossl_connect_step1" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2021-22901" +cwe = "CWE-119" +commit = "7f4a9a9b2a49547eae24d2e19bc5c346e9026479" +parent = "39ce47f219b09c380b81f89fe54ac586c8db6bde" +commit_url = "https://github.com/curl/curl/commit/7f4a9a9b2a49547eae24d2e19bc5c346e9026479" +vuln = "curl-cve-2021-22901-ossl_connect_step1/vuln.c" +fixed = "curl-cve-2021-22901-ossl_connect_step1/fixed.c" +relpath = "lib/vtls/openssl.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/vtls/openssl.c" +sink = "unknown" +evidence = "openssl: associate/detach the transfer from connection" + +[[pair]] +name = "curl-cve-2021-22898" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2021-22898" +cwe = "CWE-119" +commit = "39ce47f219b09c380b81f89fe54ac586c8db6bde" +parent = "bbb71507b7bab52002f9b1e0880bed6a32834511" +commit_url = "https://github.com/curl/curl/commit/39ce47f219b09c380b81f89fe54ac586c8db6bde" +vuln = "curl-cve-2021-22898/vuln.c" +fixed = "curl-cve-2021-22898/fixed.c" +relpath = "lib/telnet.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/telnet.c" +sink = "unknown" +evidence = "telnet: check sscanf() for correct number of matches" + +[[pair]] +name = "curl-cve-2021-22890" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2021-22890" +cwe = "CWE-119" +commit = "b09c8ee15771c614c4bf3ddac893cdb12187c844" +parent = "7214288898f5625a6cc196e22a74232eada7861c" +commit_url = "https://github.com/curl/curl/commit/b09c8ee15771c614c4bf3ddac893cdb12187c844" +vuln = "curl-cve-2021-22890/vuln.c" +fixed = "curl-cve-2021-22890/fixed.c" +relpath = "lib/vtls/bearssl.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/vtls/bearssl.c" +sink = "unknown" +evidence = "vtls: add 'isproxy' argument to Curl_ssl_get/addsessionid()" + +[[pair]] +name = "curl-cve-2021-22876" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2021-22876" +cwe = "CWE-119" +commit = "7214288898f5625a6cc196e22a74232eada7861c" +parent = "184ffc0bdfcab17eb96d1dd64f9c0cecc139e3e9" +commit_url = "https://github.com/curl/curl/commit/7214288898f5625a6cc196e22a74232eada7861c" +vuln = "curl-cve-2021-22876/vuln.c" +fixed = "curl-cve-2021-22876/fixed.c" +relpath = "lib/transfer.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/transfer.c" +sink = "unknown" +evidence = "transfer: strip credentials from the auto-referer header field" + +[[pair]] +name = "curl-cve-2020-8286" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2020-8286" +cwe = "CWE-119" +commit = "d9d01672785b8ac04aab1abb6de95fe3072ae199" +parent = "69a358f2186e04cf44698b5100332cbf1ee7f01d" +commit_url = "https://github.com/curl/curl/commit/d9d01672785b8ac04aab1abb6de95fe3072ae199" +vuln = "curl-cve-2020-8286/vuln.c" +fixed = "curl-cve-2020-8286/fixed.c" +relpath = "lib/vtls/openssl.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/vtls/openssl.c" +sink = "unknown" +evidence = "openssl: make the OCSP verification verify the certificate id" + +[[pair]] +name = "curl-cve-2020-8284" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2020-8284" +cwe = "CWE-119" +commit = "ec9cc725d598ac77de7b6df8afeec292b3c8ad46" +parent = "abd846c374c5269809ce11740754bc6f00a0b193" +commit_url = "https://github.com/curl/curl/commit/ec9cc725d598ac77de7b6df8afeec292b3c8ad46" +vuln = "curl-cve-2020-8284/vuln.c" +fixed = "curl-cve-2020-8284/fixed.c" +relpath = "lib/url.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/url.c" +sink = "unknown" +evidence = "ftp: CURLOPT_FTP_SKIP_PASV_IP by default" + +[[pair]] +name = "curl-cve-2020-8284-config_init" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2020-8284" +cwe = "CWE-119" +commit = "ec9cc725d598ac77de7b6df8afeec292b3c8ad46" +parent = "abd846c374c5269809ce11740754bc6f00a0b193" +commit_url = "https://github.com/curl/curl/commit/ec9cc725d598ac77de7b6df8afeec292b3c8ad46" +vuln = "curl-cve-2020-8284-config_init/vuln.c" +fixed = "curl-cve-2020-8284-config_init/fixed.c" +relpath = "src/tool_cfgable.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "src/tool_cfgable.c" +sink = "unknown" +evidence = "ftp: CURLOPT_FTP_SKIP_PASV_IP by default" + +[[pair]] +name = "curl-cve-2020-8231-curl_multi_add_handle" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2020-8231" +cwe = "CWE-119" +commit = "3c9e021f86872baae412a427e807fbfa2f3e8a22" +parent = "687908c6e6332b2bf4ba74b271e795f9c65a5a61" +commit_url = "https://github.com/curl/curl/commit/3c9e021f86872baae412a427e807fbfa2f3e8a22" +vuln = "curl-cve-2020-8231-curl_multi_add_handle/vuln.c" +fixed = "curl-cve-2020-8231-curl_multi_add_handle/fixed.c" +relpath = "lib/multi.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/multi.c" +sink = "unknown" +evidence = "Curl_easy: remember last connection by id, not by pointer" + +[[pair]] +name = "curl-cve-2020-8231-curl_open" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2020-8231" +cwe = "CWE-119" +commit = "3c9e021f86872baae412a427e807fbfa2f3e8a22" +parent = "687908c6e6332b2bf4ba74b271e795f9c65a5a61" +commit_url = "https://github.com/curl/curl/commit/3c9e021f86872baae412a427e807fbfa2f3e8a22" +vuln = "curl-cve-2020-8231-curl_open/vuln.c" +fixed = "curl-cve-2020-8231-curl_open/fixed.c" +relpath = "lib/url.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "lib/url.c" +sink = "unknown" +evidence = "Curl_easy: remember last connection by id, not by pointer" + +[[pair]] +name = "curl-cve-2020-8177" +slice = "vfc" +language = "c_cpp" +origin = "curl" +license = "curl" +repo = "curl/curl" +cve = "CVE-2020-8177" +cwe = "CWE-119" +commit = "8236aba58542c5f89f1d41ca09d84579efb05e22" +parent = "26d2755d7c3181e90e46014778941bff53d2309f" +commit_url = "https://github.com/curl/curl/commit/8236aba58542c5f89f1d41ca09d84579efb05e22" +vuln = "curl-cve-2020-8177/vuln.c" +fixed = "curl-cve-2020-8177/fixed.c" +relpath = "src/tool_cb_hdr.c" +min_recall = 1.0 +fix_policy = "silent" + +[[pair.expected]] +cwe = "CWE-119" +class = "security fix" +path = "src/tool_cb_hdr.c" +sink = "unknown" +evidence = "tool_getparam: -i is not OK if -J is used" diff --git a/benchmarks/pairs/vfc/chromium-cve-2019-5786/fixed.cc b/benchmarks/pairs/vfc/chromium-cve-2019-5786/fixed.cc new file mode 100644 index 0000000..930453c --- /dev/null +++ b/benchmarks/pairs/vfc/chromium-cve-2019-5786/fixed.cc @@ -0,0 +1,67 @@ +/* Provenance: Chromium FileReaderLoader::ArrayBufferResult after CVE-2019-5786. + * repo: chromium/chromium + * commit: ba9748e78ec7e9c0d594e7edf7b2c07ea2a90449 + * parent: 9f3fccdba567f30ea39b08f57d8d5b49cd832b4a + * commit_url: https://github.com/chromium/chromium/commit/ba9748e78ec7e9c0d594e7edf7b2c07ea2a90449 + * cve: CVE-2019-5786 + * license: BSD-3-Clause + * function: FileReaderLoader::ArrayBufferResult + * relpath: third_party/blink/renderer/core/fileapi/file_reader_loader.cc + */ +#include +#include + +enum class FileErrorCode { kOK }; + +class ArrayBuffer { + public: + static void *Create(const void *data, size_t length) { + (void)data; + (void)length; + return nullptr; + } +}; + +class DOMArrayBuffer { + public: + static DOMArrayBuffer *Create(void *buffer) { + (void)buffer; + return nullptr; + } +}; + +struct RawData { + void *ToArrayBuffer() { return nullptr; } + size_t ByteLength() const { return 0; } + const void *Data() const { return nullptr; } +}; + +class FileReaderLoader { + public: + DOMArrayBuffer *ArrayBufferResult(); + + DOMArrayBuffer *array_buffer_result_ = nullptr; + std::unique_ptr raw_data_; + FileErrorCode error_code_ = FileErrorCode::kOK; + bool finished_loading_ = false; + + void AdjustReportedMemoryUsageToV8(int64_t delta) { (void)delta; } +}; + +DOMArrayBuffer *FileReaderLoader::ArrayBufferResult() { + if (array_buffer_result_) + return array_buffer_result_; + + // If the loading is not started or an error occurs, return an empty result. + if (!raw_data_ || error_code_ != FileErrorCode::kOK) + return nullptr; + + if (!finished_loading_) { + return DOMArrayBuffer::Create(ArrayBuffer::Create(raw_data_->Data(), raw_data_->ByteLength())); + } + + array_buffer_result_ = DOMArrayBuffer::Create(raw_data_->ToArrayBuffer()); + AdjustReportedMemoryUsageToV8(-1 * static_cast(raw_data_->ByteLength())); + raw_data_.reset(); + return array_buffer_result_; +} diff --git a/benchmarks/pairs/vfc/chromium-cve-2019-5786/vuln.cc b/benchmarks/pairs/vfc/chromium-cve-2019-5786/vuln.cc new file mode 100644 index 0000000..b9562be --- /dev/null +++ b/benchmarks/pairs/vfc/chromium-cve-2019-5786/vuln.cc @@ -0,0 +1,67 @@ +/* Provenance: Chromium FileReaderLoader::ArrayBufferResult before CVE-2019-5786. + * repo: chromium/chromium + * commit: 9f3fccdba567f30ea39b08f57d8d5b49cd832b4a + * parent: 9f3fccdba567f30ea39b08f57d8d5b49cd832b4a + * fix: ba9748e78ec7e9c0d594e7edf7b2c07ea2a90449 + * commit_url: https://github.com/chromium/chromium/commit/ba9748e78ec7e9c0d594e7edf7b2c07ea2a90449 + * cve: CVE-2019-5786 + * license: BSD-3-Clause + * function: FileReaderLoader::ArrayBufferResult + * relpath: third_party/blink/renderer/core/fileapi/file_reader_loader.cc + */ +#include +#include + +enum class FileErrorCode { kOK }; + +class ArrayBuffer { + public: + static void *Create(const void *data, size_t length) { + (void)data; + (void)length; + return nullptr; + } +}; + +class DOMArrayBuffer { + public: + static DOMArrayBuffer *Create(void *buffer) { + (void)buffer; + return nullptr; + } +}; + +struct RawData { + void *ToArrayBuffer() { return nullptr; } + size_t ByteLength() const { return 0; } + const void *Data() const { return nullptr; } +}; + +class FileReaderLoader { + public: + DOMArrayBuffer *ArrayBufferResult(); + + DOMArrayBuffer *array_buffer_result_ = nullptr; + std::unique_ptr raw_data_; + FileErrorCode error_code_ = FileErrorCode::kOK; + bool finished_loading_ = false; + + void AdjustReportedMemoryUsageToV8(int64_t delta) { (void)delta; } +}; + +DOMArrayBuffer *FileReaderLoader::ArrayBufferResult() { + if (array_buffer_result_) + return array_buffer_result_; + + // If the loading is not started or an error occurs, return an empty result. + if (!raw_data_ || error_code_ != FileErrorCode::kOK) + return nullptr; + + DOMArrayBuffer *result = DOMArrayBuffer::Create(raw_data_->ToArrayBuffer()); + if (finished_loading_) { + array_buffer_result_ = result; + AdjustReportedMemoryUsageToV8(-1 * static_cast(raw_data_->ByteLength())); + raw_data_.reset(); + } + return result; +} diff --git a/benchmarks/pairs/vfc/chromium-cve-2022-2162/fixed.cc b/benchmarks/pairs/vfc/chromium-cve-2022-2162/fixed.cc new file mode 100644 index 0000000..e58eb23 --- /dev/null +++ b/benchmarks/pairs/vfc/chromium-cve-2022-2162/fixed.cc @@ -0,0 +1,44 @@ +// Provenance: chromium/chromium IsShellIntegratedExtension (fixed). +// repo: chromium/chromium +// commit: 22c61cfae5d1b37c773e638d342488ae11118b51 +// parent: a07d0ae0a7dc68686adca10dcf11138cb2f4ab6d +// commit_url: https://github.com/chromium/chromium/commit/22c61cfae5d1b37c773e638d342488ae11118b51 +// cve: CVE-2022-2162 +// license: BSD-3-Clause +// function: IsShellIntegratedExtension +// relpath: content/browser/file_system_access/file_system_chooser.cc + +bool FileSystemChooser::IsShellIntegratedExtension( + const base::FilePath::StringType& extension) { + // TODO(https://crbug.com/1154757): Figure out some way to unify this with + // net::IsSafePortablePathComponent, with the result probably ending up in + // base/i18n/file_util_icu.h. + // - For the sake of consistency across platforms, we sanitize '.lnk' and + // '.local' files on all platforms (not just Windows) + // - There are some extensions (i.e. '.scf') we would like to sanitize which + // `net::GenerateFileName()` does not + base::FilePath::StringType extension_lower = + base::ToLowerASCII(GetLastExtension(extension)); + + // '.lnk' and '.scf' files may be used to execute arbitrary code (see + // https://nvd.nist.gov/vuln/detail/CVE-2010-2568 and + // https://crbug.com/1227995, respectively). '.local' files are used by + // Windows to determine which DLLs to load for an application. '.url' files + // can be used to read arbirtary files (see https://crbug.com/1307930). + if ((extension_lower == FILE_PATH_LITERAL("lnk")) || + (extension_lower == FILE_PATH_LITERAL("local")) || + (extension_lower == FILE_PATH_LITERAL("scf")) || + (extension_lower == FILE_PATH_LITERAL("url"))) { + return true; + } + + // Setting a file's extension to a CLSID may conceal its actual file type on + // some Windows versions (see https://nvd.nist.gov/vuln/detail/CVE-2004-0420). + if (!extension_lower.empty() && + (extension_lower.front() == FILE_PATH_LITERAL('{')) && + (extension_lower.back() == FILE_PATH_LITERAL('}'))) { + return true; + } + + return false; +} diff --git a/benchmarks/pairs/vfc/chromium-cve-2022-2162/vuln.cc b/benchmarks/pairs/vfc/chromium-cve-2022-2162/vuln.cc new file mode 100644 index 0000000..7bd9c1d --- /dev/null +++ b/benchmarks/pairs/vfc/chromium-cve-2022-2162/vuln.cc @@ -0,0 +1,42 @@ +// Provenance: chromium/chromium IsShellIntegratedExtension (vuln). +// repo: chromium/chromium +// commit: a07d0ae0a7dc68686adca10dcf11138cb2f4ab6d +// parent: a07d0ae0a7dc68686adca10dcf11138cb2f4ab6d +// commit_url: https://github.com/chromium/chromium/commit/22c61cfae5d1b37c773e638d342488ae11118b51 +// cve: CVE-2022-2162 +// license: BSD-3-Clause +// function: IsShellIntegratedExtension +// relpath: content/browser/file_system_access/file_system_chooser.cc + +bool FileSystemChooser::IsShellIntegratedExtension( + const base::FilePath::StringType& extension) { + // TODO(https://crbug.com/1154757): Figure out some way to unify this with + // net::IsSafePortablePathComponent, with the result probably ending up in + // base/i18n/file_util_icu.h. + // - For the sake of consistency across platforms, we sanitize '.lnk' and + // '.local' files on all platforms (not just Windows) + // - There are some extensions (i.e. '.scf') we would like to sanitize which + // `net::GenerateFileName()` does not + base::FilePath::StringType extension_lower = + base::ToLowerASCII(GetLastExtension(extension)); + + // .lnk and .scf files may be used to execute arbitrary code (see + // https://nvd.nist.gov/vuln/detail/CVE-2010-2568 and + // https://crbug.com/1227995, respectively). .local files are used by Windows + // to determine which DLLs to load for an application. + if ((extension_lower == FILE_PATH_LITERAL("lnk")) || + (extension_lower == FILE_PATH_LITERAL("local")) || + (extension_lower == FILE_PATH_LITERAL("scf"))) { + return true; + } + + // Setting a file's extension to a CLSID may conceal its actual file type on + // some Windows versions (see https://nvd.nist.gov/vuln/detail/CVE-2004-0420). + if (!extension_lower.empty() && + (extension_lower.front() == FILE_PATH_LITERAL('{')) && + (extension_lower.back() == FILE_PATH_LITERAL('}'))) { + return true; + } + + return false; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2020-8177/fixed.c b/benchmarks/pairs/vfc/curl-cve-2020-8177/fixed.c new file mode 100644 index 0000000..b145936 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2020-8177/fixed.c @@ -0,0 +1,186 @@ +/* Provenance: curl/curl tool_header_cb (fixed). + * repo: curl/curl + * commit: 8236aba58542c5f89f1d41ca09d84579efb05e22 + * parent: 26d2755d7c3181e90e46014778941bff53d2309f + * commit_url: https://github.com/curl/curl/commit/8236aba58542c5f89f1d41ca09d84579efb05e22 + * cve: CVE-2020-8177 + * license: curl + * function: tool_header_cb + * relpath: src/tool_cb_hdr.c + */ + +size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) +{ + struct per_transfer *per = userdata; + struct HdrCbData *hdrcbdata = &per->hdrcbdata; + struct OutStruct *outs = &per->outs; + struct OutStruct *heads = &per->heads; + struct OutStruct *etag_save = &per->etag_save; + const char *str = ptr; + const size_t cb = size * nmemb; + const char *end = (char *)ptr + cb; + long protocol = 0; + + /* + * Once that libcurl has called back tool_header_cb() the returned value + * is checked against the amount that was intended to be written, if + * it does not match then it fails with CURLE_WRITE_ERROR. So at this + * point returning a value different from sz*nmemb indicates failure. + */ + size_t failure = (size && nmemb) ? 0 : 1; + + if(!per->config) + return failure; + +#ifdef DEBUGBUILD + if(size * nmemb > (size_t)CURL_MAX_HTTP_HEADER) { + warnf(per->config->global, "Header data exceeds single call write " + "limit!\n"); + return failure; + } +#endif + + /* + * Write header data when curl option --dump-header (-D) is given. + */ + + if(per->config->headerfile && heads->stream) { + size_t rc = fwrite(ptr, size, nmemb, heads->stream); + if(rc != cb) + return rc; + /* flush the stream to send off what we got earlier */ + (void)fflush(heads->stream); + } + + /* + * Write etag to file when --etag-save option is given. + * etag string that we want is enveloped in double quotes + */ + if(per->config->etag_save_file && etag_save->stream) { + /* match only header that start with etag (case insensitive) */ + if(curl_strnequal(str, "etag:", 5)) { + char *etag_h = NULL; + char *first = NULL; + char *last = NULL; + size_t etag_length = 0; + + etag_h = ptr; + /* point to first occurrence of double quote */ + first = memchr(etag_h, '\"', cb); + + /* + * if server side messed with the etag header and doesn't include + * double quotes around the etag, kindly exit with a warning + */ + + if(!first) { + warnf(per->config->global, + "\nReceived header etag is missing double quote/s\n"); + return 1; + } + else { + /* discard first double quote */ + first++; + } + + /* point to last occurrence of double quote */ + last = memchr(first, '\"', cb); + + if(!last) { + warnf(per->config->global, + "\nReceived header etag is missing double quote/s\n"); + return 1; + } + + /* get length of desired etag */ + etag_length = (size_t)last - (size_t)first; + + fwrite(first, size, etag_length, etag_save->stream); + /* terminate with new line */ + fputc('\n', etag_save->stream); + } + + (void)fflush(etag_save->stream); + } + + /* + * This callback sets the filename where output shall be written when + * curl options --remote-name (-O) and --remote-header-name (-J) have + * been simultaneously given and additionally server returns an HTTP + * Content-Disposition header specifying a filename property. + */ + + curl_easy_getinfo(per->curl, CURLINFO_PROTOCOL, &protocol); + if(hdrcbdata->honor_cd_filename && + (cb > 20) && checkprefix("Content-disposition:", str) && + (protocol & (CURLPROTO_HTTPS|CURLPROTO_HTTP))) { + const char *p = str + 20; + + /* look for the 'filename=' parameter + (encoded filenames (*=) are not supported) */ + for(;;) { + char *filename; + size_t len; + + while(*p && (p < end) && !ISALPHA(*p)) + p++; + if(p > end - 9) + break; + + if(memcmp(p, "filename=", 9)) { + /* no match, find next parameter */ + while((p < end) && (*p != ';')) + p++; + continue; + } + p += 9; + + /* this expression below typecasts 'cb' only to avoid + warning: signed and unsigned type in conditional expression + */ + len = (ssize_t)cb - (p - str); + filename = parse_filename(p, len); + if(filename) { + if(outs->stream) { + /* indication of problem, get out! */ + free(filename); + return failure; + } + + outs->is_cd_filename = TRUE; + outs->s_isreg = TRUE; + outs->fopened = FALSE; + outs->filename = filename; + outs->alloc_filename = TRUE; + hdrcbdata->honor_cd_filename = FALSE; /* done now! */ + if(!tool_create_output_file(outs, per->config)) + return failure; + } + break; + } + if(!outs->stream && !tool_create_output_file(outs, per->config)) + return failure; + } + + if(hdrcbdata->config->show_headers && + (protocol & + (CURLPROTO_HTTP|CURLPROTO_HTTPS|CURLPROTO_RTSP|CURLPROTO_FILE))) { + /* bold headers only for selected protocols */ + char *value = NULL; + + if(!outs->stream && !tool_create_output_file(outs, per->config)) + return failure; + + if(hdrcbdata->global->isatty && hdrcbdata->global->styled_output) + value = memchr(ptr, ':', cb); + if(value) { + size_t namelen = value - ptr; + fprintf(outs->stream, BOLD "%.*s" BOLDOFF ":", namelen, ptr); + fwrite(&value[1], cb - namelen - 1, 1, outs->stream); + } + else + /* not "handled", just show it */ + fwrite(ptr, cb, 1, outs->stream); + } + return cb; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2020-8177/vuln.c b/benchmarks/pairs/vfc/curl-cve-2020-8177/vuln.c new file mode 100644 index 0000000..c1c71ec --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2020-8177/vuln.c @@ -0,0 +1,200 @@ +/* Provenance: curl/curl tool_header_cb (vuln). + * repo: curl/curl + * commit: 26d2755d7c3181e90e46014778941bff53d2309f + * parent: 26d2755d7c3181e90e46014778941bff53d2309f + * commit_url: https://github.com/curl/curl/commit/8236aba58542c5f89f1d41ca09d84579efb05e22 + * cve: CVE-2020-8177 + * license: curl + * function: tool_header_cb + * relpath: src/tool_cb_hdr.c + */ + +size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) +{ + struct per_transfer *per = userdata; + struct HdrCbData *hdrcbdata = &per->hdrcbdata; + struct OutStruct *outs = &per->outs; + struct OutStruct *heads = &per->heads; + struct OutStruct *etag_save = &per->etag_save; + const char *str = ptr; + const size_t cb = size * nmemb; + const char *end = (char *)ptr + cb; + long protocol = 0; + + /* + * Once that libcurl has called back tool_header_cb() the returned value + * is checked against the amount that was intended to be written, if + * it does not match then it fails with CURLE_WRITE_ERROR. So at this + * point returning a value different from sz*nmemb indicates failure. + */ + size_t failure = (size && nmemb) ? 0 : 1; + + if(!per->config) + return failure; + +#ifdef DEBUGBUILD + if(size * nmemb > (size_t)CURL_MAX_HTTP_HEADER) { + warnf(per->config->global, "Header data exceeds single call write " + "limit!\n"); + return failure; + } +#endif + + /* + * Write header data when curl option --dump-header (-D) is given. + */ + + if(per->config->headerfile && heads->stream) { + size_t rc = fwrite(ptr, size, nmemb, heads->stream); + if(rc != cb) + return rc; + /* flush the stream to send off what we got earlier */ + (void)fflush(heads->stream); + } + + /* + * Write etag to file when --etag-save option is given. + * etag string that we want is enveloped in double quotes + */ + if(per->config->etag_save_file && etag_save->stream) { + /* match only header that start with etag (case insensitive) */ + if(curl_strnequal(str, "etag:", 5)) { + char *etag_h = NULL; + char *first = NULL; + char *last = NULL; + size_t etag_length = 0; + + etag_h = ptr; + /* point to first occurrence of double quote */ + first = memchr(etag_h, '\"', cb); + + /* + * if server side messed with the etag header and doesn't include + * double quotes around the etag, kindly exit with a warning + */ + + if(!first) { + warnf(per->config->global, + "\nReceived header etag is missing double quote/s\n"); + return 1; + } + else { + /* discard first double quote */ + first++; + } + + /* point to last occurrence of double quote */ + last = memchr(first, '\"', cb); + + if(!last) { + warnf(per->config->global, + "\nReceived header etag is missing double quote/s\n"); + return 1; + } + + /* get length of desired etag */ + etag_length = (size_t)last - (size_t)first; + + fwrite(first, size, etag_length, etag_save->stream); + /* terminate with new line */ + fputc('\n', etag_save->stream); + } + + (void)fflush(etag_save->stream); + } + + /* + * This callback sets the filename where output shall be written when + * curl options --remote-name (-O) and --remote-header-name (-J) have + * been simultaneously given and additionally server returns an HTTP + * Content-Disposition header specifying a filename property. + */ + + curl_easy_getinfo(per->curl, CURLINFO_PROTOCOL, &protocol); + if(hdrcbdata->honor_cd_filename && + (cb > 20) && checkprefix("Content-disposition:", str) && + (protocol & (CURLPROTO_HTTPS|CURLPROTO_HTTP))) { + const char *p = str + 20; + + /* look for the 'filename=' parameter + (encoded filenames (*=) are not supported) */ + for(;;) { + char *filename; + size_t len; + + while(*p && (p < end) && !ISALPHA(*p)) + p++; + if(p > end - 9) + break; + + if(memcmp(p, "filename=", 9)) { + /* no match, find next parameter */ + while((p < end) && (*p != ';')) + p++; + continue; + } + p += 9; + + /* this expression below typecasts 'cb' only to avoid + warning: signed and unsigned type in conditional expression + */ + len = (ssize_t)cb - (p - str); + filename = parse_filename(p, len); + if(filename) { + if(outs->stream) { + int rc; + /* already opened and possibly written to */ + if(outs->fopened) + fclose(outs->stream); + outs->stream = NULL; + + /* rename the initial file name to the new file name */ + rc = rename(outs->filename, filename); + if(rc != 0) { + warnf(per->config->global, "Failed to rename %s -> %s: %s\n", + outs->filename, filename, strerror(errno)); + } + if(outs->alloc_filename) + Curl_safefree(outs->filename); + if(rc != 0) { + free(filename); + return failure; + } + } + outs->is_cd_filename = TRUE; + outs->s_isreg = TRUE; + outs->fopened = FALSE; + outs->filename = filename; + outs->alloc_filename = TRUE; + hdrcbdata->honor_cd_filename = FALSE; /* done now! */ + if(!tool_create_output_file(outs, per->config)) + return failure; + } + break; + } + if(!outs->stream && !tool_create_output_file(outs, per->config)) + return failure; + } + + if(hdrcbdata->config->show_headers && + (protocol & + (CURLPROTO_HTTP|CURLPROTO_HTTPS|CURLPROTO_RTSP|CURLPROTO_FILE))) { + /* bold headers only for selected protocols */ + char *value = NULL; + + if(!outs->stream && !tool_create_output_file(outs, per->config)) + return failure; + + if(hdrcbdata->global->isatty && hdrcbdata->global->styled_output) + value = memchr(ptr, ':', cb); + if(value) { + size_t namelen = value - ptr; + fprintf(outs->stream, BOLD "%.*s" BOLDOFF ":", namelen, ptr); + fwrite(&value[1], cb - namelen - 1, 1, outs->stream); + } + else + /* not "handled", just show it */ + fwrite(ptr, cb, 1, outs->stream); + } + return cb; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2020-8231-curl_multi_add_handle/fixed.c b/benchmarks/pairs/vfc/curl-cve-2020-8231-curl_multi_add_handle/fixed.c new file mode 100644 index 0000000..42b8ca3 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2020-8231-curl_multi_add_handle/fixed.c @@ -0,0 +1,126 @@ +/* Provenance: curl/curl curl_multi_add_handle (fixed). + * repo: curl/curl + * commit: 3c9e021f86872baae412a427e807fbfa2f3e8a22 + * parent: 687908c6e6332b2bf4ba74b271e795f9c65a5a61 + * commit_url: https://github.com/curl/curl/commit/3c9e021f86872baae412a427e807fbfa2f3e8a22 + * cve: CVE-2020-8231 + * license: curl + * function: curl_multi_add_handle + * relpath: lib/multi.c + */ + +CURLMcode curl_multi_add_handle(struct Curl_multi *multi, + struct Curl_easy *data) +{ + /* First, make some basic checks that the CURLM handle is a good handle */ + if(!GOOD_MULTI_HANDLE(multi)) + return CURLM_BAD_HANDLE; + + /* Verify that we got a somewhat good easy handle too */ + if(!GOOD_EASY_HANDLE(data)) + return CURLM_BAD_EASY_HANDLE; + + /* Prevent users from adding same easy handle more than once and prevent + adding to more than one multi stack */ + if(data->multi) + return CURLM_ADDED_ALREADY; + + if(multi->in_callback) + return CURLM_RECURSIVE_API_CALL; + + /* Initialize timeout list for this handle */ + Curl_llist_init(&data->state.timeoutlist, NULL); + + /* + * No failure allowed in this function beyond this point. And no + * modification of easy nor multi handle allowed before this except for + * potential multi's connection cache growing which won't be undone in this + * function no matter what. + */ + if(data->set.errorbuffer) + data->set.errorbuffer[0] = 0; + + /* set the easy handle */ + multistate(data, CURLM_STATE_INIT); + + /* for multi interface connections, we share DNS cache automatically if the + easy handle's one is currently not set. */ + if(!data->dns.hostcache || + (data->dns.hostcachetype == HCACHE_NONE)) { + data->dns.hostcache = &multi->hostcache; + data->dns.hostcachetype = HCACHE_MULTI; + } + + /* Point to the shared or multi handle connection cache */ + if(data->share && (data->share->specifier & (1<< CURL_LOCK_DATA_CONNECT))) + data->state.conn_cache = &data->share->conn_cache; + else + data->state.conn_cache = &multi->conn_cache; + data->state.lastconnect_id = -1; + +#ifdef USE_LIBPSL + /* Do the same for PSL. */ + if(data->share && (data->share->specifier & (1 << CURL_LOCK_DATA_PSL))) + data->psl = &data->share->psl; + else + data->psl = &multi->psl; +#endif + + /* We add the new entry last in the list. */ + data->next = NULL; /* end of the line */ + if(multi->easyp) { + struct Curl_easy *last = multi->easylp; + last->next = data; + data->prev = last; + multi->easylp = data; /* the new last node */ + } + else { + /* first node, make prev NULL! */ + data->prev = NULL; + multi->easylp = multi->easyp = data; /* both first and last */ + } + + /* make the Curl_easy refer back to this multi handle */ + data->multi = multi; + + /* Set the timeout for this handle to expire really soon so that it will + be taken care of even when this handle is added in the midst of operation + when only the curl_multi_socket() API is used. During that flow, only + sockets that time-out or have actions will be dealt with. Since this + handle has no action yet, we make sure it times out to get things to + happen. */ + Curl_expire(data, 0, EXPIRE_RUN_NOW); + + /* increase the node-counter */ + multi->num_easy++; + + /* increase the alive-counter */ + multi->num_alive++; + + /* A somewhat crude work-around for a little glitch in Curl_update_timer() + that happens if the lastcall time is set to the same time when the handle + is removed as when the next handle is added, as then the check in + Curl_update_timer() that prevents calling the application multiple times + with the same timer info will not trigger and then the new handle's + timeout will not be notified to the app. + + The work-around is thus simply to clear the 'lastcall' variable to force + Curl_update_timer() to always trigger a callback to the app when a new + easy handle is added */ + memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall)); + + CONNCACHE_LOCK(data); + /* The closure handle only ever has default timeouts set. To improve the + state somewhat we clone the timeouts from each added handle so that the + closure handle always has the same timeouts as the most recently added + easy handle. */ + data->state.conn_cache->closure_handle->set.timeout = data->set.timeout; + data->state.conn_cache->closure_handle->set.server_response_timeout = + data->set.server_response_timeout; + data->state.conn_cache->closure_handle->set.no_signal = + data->set.no_signal; + CONNCACHE_UNLOCK(data); + + Curl_update_timer(multi); + return CURLM_OK; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2020-8231-curl_multi_add_handle/vuln.c b/benchmarks/pairs/vfc/curl-cve-2020-8231-curl_multi_add_handle/vuln.c new file mode 100644 index 0000000..4bddeea --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2020-8231-curl_multi_add_handle/vuln.c @@ -0,0 +1,125 @@ +/* Provenance: curl/curl curl_multi_add_handle (vuln). + * repo: curl/curl + * commit: 687908c6e6332b2bf4ba74b271e795f9c65a5a61 + * parent: 687908c6e6332b2bf4ba74b271e795f9c65a5a61 + * commit_url: https://github.com/curl/curl/commit/3c9e021f86872baae412a427e807fbfa2f3e8a22 + * cve: CVE-2020-8231 + * license: curl + * function: curl_multi_add_handle + * relpath: lib/multi.c + */ + +CURLMcode curl_multi_add_handle(struct Curl_multi *multi, + struct Curl_easy *data) +{ + /* First, make some basic checks that the CURLM handle is a good handle */ + if(!GOOD_MULTI_HANDLE(multi)) + return CURLM_BAD_HANDLE; + + /* Verify that we got a somewhat good easy handle too */ + if(!GOOD_EASY_HANDLE(data)) + return CURLM_BAD_EASY_HANDLE; + + /* Prevent users from adding same easy handle more than once and prevent + adding to more than one multi stack */ + if(data->multi) + return CURLM_ADDED_ALREADY; + + if(multi->in_callback) + return CURLM_RECURSIVE_API_CALL; + + /* Initialize timeout list for this handle */ + Curl_llist_init(&data->state.timeoutlist, NULL); + + /* + * No failure allowed in this function beyond this point. And no + * modification of easy nor multi handle allowed before this except for + * potential multi's connection cache growing which won't be undone in this + * function no matter what. + */ + if(data->set.errorbuffer) + data->set.errorbuffer[0] = 0; + + /* set the easy handle */ + multistate(data, CURLM_STATE_INIT); + + /* for multi interface connections, we share DNS cache automatically if the + easy handle's one is currently not set. */ + if(!data->dns.hostcache || + (data->dns.hostcachetype == HCACHE_NONE)) { + data->dns.hostcache = &multi->hostcache; + data->dns.hostcachetype = HCACHE_MULTI; + } + + /* Point to the shared or multi handle connection cache */ + if(data->share && (data->share->specifier & (1<< CURL_LOCK_DATA_CONNECT))) + data->state.conn_cache = &data->share->conn_cache; + else + data->state.conn_cache = &multi->conn_cache; + +#ifdef USE_LIBPSL + /* Do the same for PSL. */ + if(data->share && (data->share->specifier & (1 << CURL_LOCK_DATA_PSL))) + data->psl = &data->share->psl; + else + data->psl = &multi->psl; +#endif + + /* We add the new entry last in the list. */ + data->next = NULL; /* end of the line */ + if(multi->easyp) { + struct Curl_easy *last = multi->easylp; + last->next = data; + data->prev = last; + multi->easylp = data; /* the new last node */ + } + else { + /* first node, make prev NULL! */ + data->prev = NULL; + multi->easylp = multi->easyp = data; /* both first and last */ + } + + /* make the Curl_easy refer back to this multi handle */ + data->multi = multi; + + /* Set the timeout for this handle to expire really soon so that it will + be taken care of even when this handle is added in the midst of operation + when only the curl_multi_socket() API is used. During that flow, only + sockets that time-out or have actions will be dealt with. Since this + handle has no action yet, we make sure it times out to get things to + happen. */ + Curl_expire(data, 0, EXPIRE_RUN_NOW); + + /* increase the node-counter */ + multi->num_easy++; + + /* increase the alive-counter */ + multi->num_alive++; + + /* A somewhat crude work-around for a little glitch in Curl_update_timer() + that happens if the lastcall time is set to the same time when the handle + is removed as when the next handle is added, as then the check in + Curl_update_timer() that prevents calling the application multiple times + with the same timer info will not trigger and then the new handle's + timeout will not be notified to the app. + + The work-around is thus simply to clear the 'lastcall' variable to force + Curl_update_timer() to always trigger a callback to the app when a new + easy handle is added */ + memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall)); + + CONNCACHE_LOCK(data); + /* The closure handle only ever has default timeouts set. To improve the + state somewhat we clone the timeouts from each added handle so that the + closure handle always has the same timeouts as the most recently added + easy handle. */ + data->state.conn_cache->closure_handle->set.timeout = data->set.timeout; + data->state.conn_cache->closure_handle->set.server_response_timeout = + data->set.server_response_timeout; + data->state.conn_cache->closure_handle->set.no_signal = + data->set.no_signal; + CONNCACHE_UNLOCK(data); + + Curl_update_timer(multi); + return CURLM_OK; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2020-8231-curl_open/fixed.c b/benchmarks/pairs/vfc/curl-cve-2020-8231-curl_open/fixed.c new file mode 100644 index 0000000..4f26d9f --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2020-8231-curl_open/fixed.c @@ -0,0 +1,65 @@ +/* Provenance: curl/curl Curl_open (fixed). + * repo: curl/curl + * commit: 3c9e021f86872baae412a427e807fbfa2f3e8a22 + * parent: 687908c6e6332b2bf4ba74b271e795f9c65a5a61 + * commit_url: https://github.com/curl/curl/commit/3c9e021f86872baae412a427e807fbfa2f3e8a22 + * cve: CVE-2020-8231 + * license: curl + * function: Curl_open + * relpath: lib/url.c + */ + +* Curl_open() + * + * @param curl is a pointer to a sessionhandle pointer that gets set by this + * function. + * @return CURLcode + */ + +CURLcode Curl_open(struct Curl_easy **curl) +{ + CURLcode result; + struct Curl_easy *data; + + /* Very simple start-up: alloc the struct, init it with zeroes and return */ + data = calloc(1, sizeof(struct Curl_easy)); + if(!data) { + /* this is a very serious error */ + DEBUGF(fprintf(stderr, "Error: calloc of Curl_easy failed\n")); + return CURLE_OUT_OF_MEMORY; + } + + data->magic = CURLEASY_MAGIC_NUMBER; + + result = Curl_resolver_init(data, &data->state.resolver); + if(result) { + DEBUGF(fprintf(stderr, "Error: resolver_init failed\n")); + free(data); + return result; + } + + result = Curl_init_userdefined(data); + if(!result) { + Curl_dyn_init(&data->state.headerb, CURL_MAX_HTTP_HEADER); + Curl_convert_init(data); + Curl_initinfo(data); + + /* most recent connection is not yet defined */ + data->state.lastconnect_id = -1; + + data->progress.flags |= PGRS_HIDE; + data->state.current_speed = -1; /* init to negative == impossible */ + } + + if(result) { + Curl_resolver_cleanup(data->state.resolver); + Curl_dyn_free(&data->state.headerb); + Curl_freeset(data); + free(data); + data = NULL; + } + else + *curl = data; + + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2020-8231-curl_open/vuln.c b/benchmarks/pairs/vfc/curl-cve-2020-8231-curl_open/vuln.c new file mode 100644 index 0000000..1ccd153 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2020-8231-curl_open/vuln.c @@ -0,0 +1,65 @@ +/* Provenance: curl/curl Curl_open (vuln). + * repo: curl/curl + * commit: 687908c6e6332b2bf4ba74b271e795f9c65a5a61 + * parent: 687908c6e6332b2bf4ba74b271e795f9c65a5a61 + * commit_url: https://github.com/curl/curl/commit/3c9e021f86872baae412a427e807fbfa2f3e8a22 + * cve: CVE-2020-8231 + * license: curl + * function: Curl_open + * relpath: lib/url.c + */ + +* Curl_open() + * + * @param curl is a pointer to a sessionhandle pointer that gets set by this + * function. + * @return CURLcode + */ + +CURLcode Curl_open(struct Curl_easy **curl) +{ + CURLcode result; + struct Curl_easy *data; + + /* Very simple start-up: alloc the struct, init it with zeroes and return */ + data = calloc(1, sizeof(struct Curl_easy)); + if(!data) { + /* this is a very serious error */ + DEBUGF(fprintf(stderr, "Error: calloc of Curl_easy failed\n")); + return CURLE_OUT_OF_MEMORY; + } + + data->magic = CURLEASY_MAGIC_NUMBER; + + result = Curl_resolver_init(data, &data->state.resolver); + if(result) { + DEBUGF(fprintf(stderr, "Error: resolver_init failed\n")); + free(data); + return result; + } + + result = Curl_init_userdefined(data); + if(!result) { + Curl_dyn_init(&data->state.headerb, CURL_MAX_HTTP_HEADER); + Curl_convert_init(data); + Curl_initinfo(data); + + /* most recent connection is not yet defined */ + data->state.lastconnect = NULL; + + data->progress.flags |= PGRS_HIDE; + data->state.current_speed = -1; /* init to negative == impossible */ + } + + if(result) { + Curl_resolver_cleanup(data->state.resolver); + Curl_dyn_free(&data->state.headerb); + Curl_freeset(data); + free(data); + data = NULL; + } + else + *curl = data; + + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2020-8284-config_init/fixed.c b/benchmarks/pairs/vfc/curl-cve-2020-8284-config_init/fixed.c new file mode 100644 index 0000000..e1dd53a --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2020-8284-config_init/fixed.c @@ -0,0 +1,31 @@ +/* Provenance: curl/curl config_init (fixed). + * repo: curl/curl + * commit: ec9cc725d598ac77de7b6df8afeec292b3c8ad46 + * parent: abd846c374c5269809ce11740754bc6f00a0b193 + * commit_url: https://github.com/curl/curl/commit/ec9cc725d598ac77de7b6df8afeec292b3c8ad46 + * cve: CVE-2020-8284 + * license: curl + * function: config_init + * relpath: src/tool_cfgable.c + */ + +void config_init(struct OperationConfig *config) +{ + memset(config, 0, sizeof(struct OperationConfig)); + + config->postfieldsize = -1; + config->use_httpget = FALSE; + config->create_dirs = FALSE; + config->maxredirs = DEFAULT_MAXREDIRS; + config->proto = CURLPROTO_ALL; + config->proto_present = FALSE; + config->proto_redir = CURLPROTO_ALL & /* All except FILE, SCP and SMB */ + ~(CURLPROTO_FILE | CURLPROTO_SCP | CURLPROTO_SMB | + CURLPROTO_SMBS); + config->proto_redir_present = FALSE; + config->proto_default = NULL; + config->tcp_nodelay = TRUE; /* enabled by default */ + config->happy_eyeballs_timeout_ms = CURL_HET_DEFAULT; + config->http09_allowed = FALSE; + config->ftp_skip_ip = TRUE; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2020-8284-config_init/vuln.c b/benchmarks/pairs/vfc/curl-cve-2020-8284-config_init/vuln.c new file mode 100644 index 0000000..387c337 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2020-8284-config_init/vuln.c @@ -0,0 +1,30 @@ +/* Provenance: curl/curl config_init (vuln). + * repo: curl/curl + * commit: abd846c374c5269809ce11740754bc6f00a0b193 + * parent: abd846c374c5269809ce11740754bc6f00a0b193 + * commit_url: https://github.com/curl/curl/commit/ec9cc725d598ac77de7b6df8afeec292b3c8ad46 + * cve: CVE-2020-8284 + * license: curl + * function: config_init + * relpath: src/tool_cfgable.c + */ + +void config_init(struct OperationConfig *config) +{ + memset(config, 0, sizeof(struct OperationConfig)); + + config->postfieldsize = -1; + config->use_httpget = FALSE; + config->create_dirs = FALSE; + config->maxredirs = DEFAULT_MAXREDIRS; + config->proto = CURLPROTO_ALL; + config->proto_present = FALSE; + config->proto_redir = CURLPROTO_ALL & /* All except FILE, SCP and SMB */ + ~(CURLPROTO_FILE | CURLPROTO_SCP | CURLPROTO_SMB | + CURLPROTO_SMBS); + config->proto_redir_present = FALSE; + config->proto_default = NULL; + config->tcp_nodelay = TRUE; /* enabled by default */ + config->happy_eyeballs_timeout_ms = CURL_HET_DEFAULT; + config->http09_allowed = FALSE; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2020-8284/fixed.c b/benchmarks/pairs/vfc/curl-cve-2020-8284/fixed.c new file mode 100644 index 0000000..64ded2e --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2020-8284/fixed.c @@ -0,0 +1,160 @@ +/* Provenance: curl/curl Curl_init_userdefined (fixed). + * repo: curl/curl + * commit: ec9cc725d598ac77de7b6df8afeec292b3c8ad46 + * parent: abd846c374c5269809ce11740754bc6f00a0b193 + * commit_url: https://github.com/curl/curl/commit/ec9cc725d598ac77de7b6df8afeec292b3c8ad46 + * cve: CVE-2020-8284 + * license: curl + * function: Curl_init_userdefined + * relpath: lib/url.c + */ + +CURLcode Curl_init_userdefined(struct Curl_easy *data) +{ + struct UserDefined *set = &data->set; + CURLcode result = CURLE_OK; + + set->out = stdout; /* default output to stdout */ + set->in_set = stdin; /* default input from stdin */ + set->err = stderr; /* default stderr to stderr */ + + /* use fwrite as default function to store output */ + set->fwrite_func = (curl_write_callback)fwrite; + + /* use fread as default function to read input */ + set->fread_func_set = (curl_read_callback)fread; + set->is_fread_set = 0; + set->is_fwrite_set = 0; + + set->seek_func = ZERO_NULL; + set->seek_client = ZERO_NULL; + + /* conversion callbacks for non-ASCII hosts */ + set->convfromnetwork = ZERO_NULL; + set->convtonetwork = ZERO_NULL; + set->convfromutf8 = ZERO_NULL; + + set->filesize = -1; /* we don't know the size */ + set->postfieldsize = -1; /* unknown size */ + set->maxredirs = -1; /* allow any amount by default */ + + set->method = HTTPREQ_GET; /* Default HTTP request */ + set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */ +#ifndef CURL_DISABLE_FTP + set->ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */ + set->ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */ + set->ftp_use_pret = FALSE; /* mainly useful for drftpd servers */ + set->ftp_filemethod = FTPFILE_MULTICWD; + set->ftp_skip_ip = TRUE; /* skip PASV IP by default */ +#endif + set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */ + + /* Set the default size of the SSL session ID cache */ + set->general_ssl.max_ssl_sessions = 5; + + set->proxyport = 0; + set->proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */ + set->httpauth = CURLAUTH_BASIC; /* defaults to basic */ + set->proxyauth = CURLAUTH_BASIC; /* defaults to basic */ + + /* SOCKS5 proxy auth defaults to username/password + GSS-API */ + set->socks5auth = CURLAUTH_BASIC | CURLAUTH_GSSAPI; + + /* make libcurl quiet by default: */ + set->hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */ + + Curl_mime_initpart(&set->mimepost, data); + + /* + * libcurl 7.10 introduced SSL verification *by default*! This needs to be + * switched off unless wanted. + */ + set->ssl.primary.verifypeer = TRUE; + set->ssl.primary.verifyhost = TRUE; +#ifdef USE_TLS_SRP + set->ssl.authtype = CURL_TLSAUTH_NONE; +#endif + set->ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth + type */ + set->ssl.primary.sessionid = TRUE; /* session ID caching enabled by + default */ +#ifndef CURL_DISABLE_PROXY + set->proxy_ssl = set->ssl; +#endif + + set->new_file_perms = 0644; /* Default permissions */ + set->new_directory_perms = 0755; /* Default permissions */ + + /* for the *protocols fields we don't use the CURLPROTO_ALL convenience + define since we internally only use the lower 16 bits for the passed + in bitmask to not conflict with the private bits */ + set->allowed_protocols = CURLPROTO_ALL; + set->redir_protocols = CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FTP | + CURLPROTO_FTPS; + +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + /* + * disallow unprotected protection negotiation NEC reference implementation + * seem not to follow rfc1961 section 4.3/4.4 + */ + set->socks5_gssapi_nec = FALSE; +#endif + + /* Set the default CA cert bundle/path detected/specified at build time. + * + * If Schannel is the selected SSL backend then these locations are + * ignored. We allow setting CA location for schannel only when explicitly + * specified by the user via CURLOPT_CAINFO / --cacert. + */ + if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) { +#if defined(CURL_CA_BUNDLE) + result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_ORIG], CURL_CA_BUNDLE); + if(result) + return result; + + result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PROXY], + CURL_CA_BUNDLE); + if(result) + return result; +#endif +#if defined(CURL_CA_PATH) + result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_ORIG], CURL_CA_PATH); + if(result) + return result; + + result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_PROXY], CURL_CA_PATH); + if(result) + return result; +#endif + } + + set->wildcard_enabled = FALSE; + set->chunk_bgn = ZERO_NULL; + set->chunk_end = ZERO_NULL; + set->tcp_keepalive = FALSE; + set->tcp_keepintvl = 60; + set->tcp_keepidle = 60; + set->tcp_fastopen = FALSE; + set->tcp_nodelay = TRUE; + set->ssl_enable_npn = TRUE; + set->ssl_enable_alpn = TRUE; + set->expect_100_timeout = 1000L; /* Wait for a second by default. */ + set->sep_headers = TRUE; /* separated header lists by default */ + set->buffer_size = READBUFFER_SIZE; + set->upload_buffer_size = UPLOADBUFFER_DEFAULT; + set->happy_eyeballs_timeout = CURL_HET_DEFAULT; + set->fnmatch = ZERO_NULL; + set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT; + set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */ + set->maxage_conn = 118; + set->http09_allowed = FALSE; + set->httpversion = +#ifdef USE_NGHTTP2 + CURL_HTTP_VERSION_2TLS +#else + CURL_HTTP_VERSION_1_1 +#endif + ; + Curl_http2_init_userset(set); + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2020-8284/vuln.c b/benchmarks/pairs/vfc/curl-cve-2020-8284/vuln.c new file mode 100644 index 0000000..bc5a523 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2020-8284/vuln.c @@ -0,0 +1,159 @@ +/* Provenance: curl/curl Curl_init_userdefined (vuln). + * repo: curl/curl + * commit: abd846c374c5269809ce11740754bc6f00a0b193 + * parent: abd846c374c5269809ce11740754bc6f00a0b193 + * commit_url: https://github.com/curl/curl/commit/ec9cc725d598ac77de7b6df8afeec292b3c8ad46 + * cve: CVE-2020-8284 + * license: curl + * function: Curl_init_userdefined + * relpath: lib/url.c + */ + +CURLcode Curl_init_userdefined(struct Curl_easy *data) +{ + struct UserDefined *set = &data->set; + CURLcode result = CURLE_OK; + + set->out = stdout; /* default output to stdout */ + set->in_set = stdin; /* default input from stdin */ + set->err = stderr; /* default stderr to stderr */ + + /* use fwrite as default function to store output */ + set->fwrite_func = (curl_write_callback)fwrite; + + /* use fread as default function to read input */ + set->fread_func_set = (curl_read_callback)fread; + set->is_fread_set = 0; + set->is_fwrite_set = 0; + + set->seek_func = ZERO_NULL; + set->seek_client = ZERO_NULL; + + /* conversion callbacks for non-ASCII hosts */ + set->convfromnetwork = ZERO_NULL; + set->convtonetwork = ZERO_NULL; + set->convfromutf8 = ZERO_NULL; + + set->filesize = -1; /* we don't know the size */ + set->postfieldsize = -1; /* unknown size */ + set->maxredirs = -1; /* allow any amount by default */ + + set->method = HTTPREQ_GET; /* Default HTTP request */ + set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */ +#ifndef CURL_DISABLE_FTP + set->ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */ + set->ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */ + set->ftp_use_pret = FALSE; /* mainly useful for drftpd servers */ + set->ftp_filemethod = FTPFILE_MULTICWD; +#endif + set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */ + + /* Set the default size of the SSL session ID cache */ + set->general_ssl.max_ssl_sessions = 5; + + set->proxyport = 0; + set->proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */ + set->httpauth = CURLAUTH_BASIC; /* defaults to basic */ + set->proxyauth = CURLAUTH_BASIC; /* defaults to basic */ + + /* SOCKS5 proxy auth defaults to username/password + GSS-API */ + set->socks5auth = CURLAUTH_BASIC | CURLAUTH_GSSAPI; + + /* make libcurl quiet by default: */ + set->hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */ + + Curl_mime_initpart(&set->mimepost, data); + + /* + * libcurl 7.10 introduced SSL verification *by default*! This needs to be + * switched off unless wanted. + */ + set->ssl.primary.verifypeer = TRUE; + set->ssl.primary.verifyhost = TRUE; +#ifdef USE_TLS_SRP + set->ssl.authtype = CURL_TLSAUTH_NONE; +#endif + set->ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth + type */ + set->ssl.primary.sessionid = TRUE; /* session ID caching enabled by + default */ +#ifndef CURL_DISABLE_PROXY + set->proxy_ssl = set->ssl; +#endif + + set->new_file_perms = 0644; /* Default permissions */ + set->new_directory_perms = 0755; /* Default permissions */ + + /* for the *protocols fields we don't use the CURLPROTO_ALL convenience + define since we internally only use the lower 16 bits for the passed + in bitmask to not conflict with the private bits */ + set->allowed_protocols = CURLPROTO_ALL; + set->redir_protocols = CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FTP | + CURLPROTO_FTPS; + +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + /* + * disallow unprotected protection negotiation NEC reference implementation + * seem not to follow rfc1961 section 4.3/4.4 + */ + set->socks5_gssapi_nec = FALSE; +#endif + + /* Set the default CA cert bundle/path detected/specified at build time. + * + * If Schannel is the selected SSL backend then these locations are + * ignored. We allow setting CA location for schannel only when explicitly + * specified by the user via CURLOPT_CAINFO / --cacert. + */ + if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) { +#if defined(CURL_CA_BUNDLE) + result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_ORIG], CURL_CA_BUNDLE); + if(result) + return result; + + result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PROXY], + CURL_CA_BUNDLE); + if(result) + return result; +#endif +#if defined(CURL_CA_PATH) + result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_ORIG], CURL_CA_PATH); + if(result) + return result; + + result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_PROXY], CURL_CA_PATH); + if(result) + return result; +#endif + } + + set->wildcard_enabled = FALSE; + set->chunk_bgn = ZERO_NULL; + set->chunk_end = ZERO_NULL; + set->tcp_keepalive = FALSE; + set->tcp_keepintvl = 60; + set->tcp_keepidle = 60; + set->tcp_fastopen = FALSE; + set->tcp_nodelay = TRUE; + set->ssl_enable_npn = TRUE; + set->ssl_enable_alpn = TRUE; + set->expect_100_timeout = 1000L; /* Wait for a second by default. */ + set->sep_headers = TRUE; /* separated header lists by default */ + set->buffer_size = READBUFFER_SIZE; + set->upload_buffer_size = UPLOADBUFFER_DEFAULT; + set->happy_eyeballs_timeout = CURL_HET_DEFAULT; + set->fnmatch = ZERO_NULL; + set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT; + set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */ + set->maxage_conn = 118; + set->http09_allowed = FALSE; + set->httpversion = +#ifdef USE_NGHTTP2 + CURL_HTTP_VERSION_2TLS +#else + CURL_HTTP_VERSION_1_1 +#endif + ; + Curl_http2_init_userset(set); + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2020-8286/fixed.c b/benchmarks/pairs/vfc/curl-cve-2020-8286/fixed.c new file mode 100644 index 0000000..540ee75 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2020-8286/fixed.c @@ -0,0 +1,164 @@ +/* Provenance: curl/curl verifystatus (fixed). + * repo: curl/curl + * commit: d9d01672785b8ac04aab1abb6de95fe3072ae199 + * parent: 69a358f2186e04cf44698b5100332cbf1ee7f01d + * commit_url: https://github.com/curl/curl/commit/d9d01672785b8ac04aab1abb6de95fe3072ae199 + * cve: CVE-2020-8286 + * license: curl + * function: verifystatus + * relpath: lib/vtls/openssl.c + */ + +!defined(OPENSSL_NO_OCSP) +static CURLcode verifystatus(struct connectdata *conn, + struct ssl_connect_data *connssl) +{ + int i, ocsp_status; + unsigned char *status; + const unsigned char *p; + CURLcode result = CURLE_OK; + struct Curl_easy *data = conn->data; + OCSP_RESPONSE *rsp = NULL; + OCSP_BASICRESP *br = NULL; + X509_STORE *st = NULL; + STACK_OF(X509) *ch = NULL; + struct ssl_backend_data *backend = connssl->backend; + X509 *cert; + OCSP_CERTID *id = NULL; + int cert_status, crl_reason; + ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; + int ret; + + long len = SSL_get_tlsext_status_ocsp_resp(backend->handle, &status); + + if(!status) { + failf(data, "No OCSP response received"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + p = status; + rsp = d2i_OCSP_RESPONSE(NULL, &p, len); + if(!rsp) { + failf(data, "Invalid OCSP response"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + ocsp_status = OCSP_response_status(rsp); + if(ocsp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { + failf(data, "Invalid OCSP response status: %s (%d)", + OCSP_response_status_str(ocsp_status), ocsp_status); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + br = OCSP_response_get1_basic(rsp); + if(!br) { + failf(data, "Invalid OCSP response"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + ch = SSL_get_peer_cert_chain(backend->handle); + st = SSL_CTX_get_cert_store(backend->ctx); + +#if ((OPENSSL_VERSION_NUMBER <= 0x1000201fL) /* Fixed after 1.0.2a */ || \ + (defined(LIBRESSL_VERSION_NUMBER) && \ + LIBRESSL_VERSION_NUMBER <= 0x2040200fL)) + /* The authorized responder cert in the OCSP response MUST be signed by the + peer cert's issuer (see RFC6960 section 4.2.2.2). If that's a root cert, + no problem, but if it's an intermediate cert OpenSSL has a bug where it + expects this issuer to be present in the chain embedded in the OCSP + response. So we add it if necessary. */ + + /* First make sure the peer cert chain includes both a peer and an issuer, + and the OCSP response contains a responder cert. */ + if(sk_X509_num(ch) >= 2 && sk_X509_num(br->certs) >= 1) { + X509 *responder = sk_X509_value(br->certs, sk_X509_num(br->certs) - 1); + + /* Find issuer of responder cert and add it to the OCSP response chain */ + for(i = 0; i < sk_X509_num(ch); i++) { + X509 *issuer = sk_X509_value(ch, i); + if(X509_check_issued(issuer, responder) == X509_V_OK) { + if(!OCSP_basic_add1_cert(br, issuer)) { + failf(data, "Could not add issuer cert to OCSP response"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + } + } + } +#endif + + if(OCSP_basic_verify(br, ch, st, 0) <= 0) { + failf(data, "OCSP response verification failed"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + /* Compute the certificate's ID */ + cert = SSL_get_peer_certificate(backend->handle); + if(!cert) { + failf(data, "Error getting peer certficate"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + for(i = 0; i < sk_X509_num(ch); i++) { + X509 *issuer = sk_X509_value(ch, i); + if(X509_check_issued(issuer, cert) == X509_V_OK) { + id = OCSP_cert_to_id(EVP_sha1(), cert, issuer); + break; + } + } + X509_free(cert); + + if(!id) { + failf(data, "Error computing OCSP ID"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + /* Find the single OCSP response corresponding to the certificate ID */ + ret = OCSP_resp_find_status(br, id, &cert_status, &crl_reason, &rev, + &thisupd, &nextupd); + OCSP_CERTID_free(id); + if(ret != 1) { + failf(data, "Could not find certificate ID in OCSP response"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + /* Validate the corresponding single OCSP response */ + if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) { + failf(data, "OCSP response has expired"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + infof(data, "SSL certificate status: %s (%d)\n", + OCSP_cert_status_str(cert_status), cert_status); + + switch(cert_status) { + case V_OCSP_CERTSTATUS_GOOD: + break; + + case V_OCSP_CERTSTATUS_REVOKED: + result = CURLE_SSL_INVALIDCERTSTATUS; + failf(data, "SSL certificate revocation reason: %s (%d)", + OCSP_crl_reason_str(crl_reason), crl_reason); + goto end; + + case V_OCSP_CERTSTATUS_UNKNOWN: + default: + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + +end: + if(br) + OCSP_BASICRESP_free(br); + OCSP_RESPONSE_free(rsp); + + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2020-8286/vuln.c b/benchmarks/pairs/vfc/curl-cve-2020-8286/vuln.c new file mode 100644 index 0000000..03a9720 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2020-8286/vuln.c @@ -0,0 +1,139 @@ +/* Provenance: curl/curl verifystatus (vuln). + * repo: curl/curl + * commit: 69a358f2186e04cf44698b5100332cbf1ee7f01d + * parent: 69a358f2186e04cf44698b5100332cbf1ee7f01d + * commit_url: https://github.com/curl/curl/commit/d9d01672785b8ac04aab1abb6de95fe3072ae199 + * cve: CVE-2020-8286 + * license: curl + * function: verifystatus + * relpath: lib/vtls/openssl.c + */ + +!defined(OPENSSL_NO_OCSP) +static CURLcode verifystatus(struct connectdata *conn, + struct ssl_connect_data *connssl) +{ + int i, ocsp_status; + unsigned char *status; + const unsigned char *p; + CURLcode result = CURLE_OK; + struct Curl_easy *data = conn->data; + OCSP_RESPONSE *rsp = NULL; + OCSP_BASICRESP *br = NULL; + X509_STORE *st = NULL; + STACK_OF(X509) *ch = NULL; + struct ssl_backend_data *backend = connssl->backend; + + long len = SSL_get_tlsext_status_ocsp_resp(backend->handle, &status); + + if(!status) { + failf(data, "No OCSP response received"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + p = status; + rsp = d2i_OCSP_RESPONSE(NULL, &p, len); + if(!rsp) { + failf(data, "Invalid OCSP response"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + ocsp_status = OCSP_response_status(rsp); + if(ocsp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { + failf(data, "Invalid OCSP response status: %s (%d)", + OCSP_response_status_str(ocsp_status), ocsp_status); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + br = OCSP_response_get1_basic(rsp); + if(!br) { + failf(data, "Invalid OCSP response"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + ch = SSL_get_peer_cert_chain(backend->handle); + st = SSL_CTX_get_cert_store(backend->ctx); + +#if ((OPENSSL_VERSION_NUMBER <= 0x1000201fL) /* Fixed after 1.0.2a */ || \ + (defined(LIBRESSL_VERSION_NUMBER) && \ + LIBRESSL_VERSION_NUMBER <= 0x2040200fL)) + /* The authorized responder cert in the OCSP response MUST be signed by the + peer cert's issuer (see RFC6960 section 4.2.2.2). If that's a root cert, + no problem, but if it's an intermediate cert OpenSSL has a bug where it + expects this issuer to be present in the chain embedded in the OCSP + response. So we add it if necessary. */ + + /* First make sure the peer cert chain includes both a peer and an issuer, + and the OCSP response contains a responder cert. */ + if(sk_X509_num(ch) >= 2 && sk_X509_num(br->certs) >= 1) { + X509 *responder = sk_X509_value(br->certs, sk_X509_num(br->certs) - 1); + + /* Find issuer of responder cert and add it to the OCSP response chain */ + for(i = 0; i < sk_X509_num(ch); i++) { + X509 *issuer = sk_X509_value(ch, i); + if(X509_check_issued(issuer, responder) == X509_V_OK) { + if(!OCSP_basic_add1_cert(br, issuer)) { + failf(data, "Could not add issuer cert to OCSP response"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + } + } + } +#endif + + if(OCSP_basic_verify(br, ch, st, 0) <= 0) { + failf(data, "OCSP response verification failed"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + for(i = 0; i < OCSP_resp_count(br); i++) { + int cert_status, crl_reason; + OCSP_SINGLERESP *single = NULL; + + ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; + + single = OCSP_resp_get0(br, i); + if(!single) + continue; + + cert_status = OCSP_single_get0_status(single, &crl_reason, &rev, + &thisupd, &nextupd); + + if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) { + failf(data, "OCSP response has expired"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + infof(data, "SSL certificate status: %s (%d)\n", + OCSP_cert_status_str(cert_status), cert_status); + + switch(cert_status) { + case V_OCSP_CERTSTATUS_GOOD: + break; + + case V_OCSP_CERTSTATUS_REVOKED: + result = CURLE_SSL_INVALIDCERTSTATUS; + + failf(data, "SSL certificate revocation reason: %s (%d)", + OCSP_crl_reason_str(crl_reason), crl_reason); + goto end; + + case V_OCSP_CERTSTATUS_UNKNOWN: + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + } + +end: + if(br) + OCSP_BASICRESP_free(br); + OCSP_RESPONSE_free(rsp); + + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22876/fixed.c b/benchmarks/pairs/vfc/curl-cve-2021-22876/fixed.c new file mode 100644 index 0000000..09b28bf --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22876/fixed.c @@ -0,0 +1,247 @@ +/* Provenance: curl/curl Curl_follow (fixed). + * repo: curl/curl + * commit: 7214288898f5625a6cc196e22a74232eada7861c + * parent: 184ffc0bdfcab17eb96d1dd64f9c0cecc139e3e9 + * commit_url: https://github.com/curl/curl/commit/7214288898f5625a6cc196e22a74232eada7861c + * cve: CVE-2021-22876 + * license: curl + * function: Curl_follow + * relpath: lib/transfer.c + */ + +* Curl_follow() handles the URL redirect magic. Pass in the 'newurl' string + * as given by the remote server and set up the new URL to request. + * + * This function DOES NOT FREE the given url. + */ +CURLcode Curl_follow(struct Curl_easy *data, + char *newurl, /* the Location: string */ + followtype type) /* see transfer.h */ +{ +#ifdef CURL_DISABLE_HTTP + (void)data; + (void)newurl; + (void)type; + /* Location: following will not happen when HTTP is disabled */ + return CURLE_TOO_MANY_REDIRECTS; +#else + + /* Location: redirect */ + bool disallowport = FALSE; + bool reachedmax = FALSE; + CURLUcode uc; + + DEBUGASSERT(type != FOLLOW_NONE); + + if(type == FOLLOW_REDIR) { + if((data->set.maxredirs != -1) && + (data->state.followlocation >= data->set.maxredirs)) { + reachedmax = TRUE; + type = FOLLOW_FAKE; /* switch to fake to store the would-be-redirected + to URL */ + } + else { + /* mark the next request as a followed location: */ + data->state.this_is_a_follow = TRUE; + + data->state.followlocation++; /* count location-followers */ + + if(data->set.http_auto_referer) { + CURLU *u; + char *referer; + + /* We are asked to automatically set the previous URL as the referer + when we get the next URL. We pick the ->url field, which may or may + not be 100% correct */ + + if(data->state.referer_alloc) { + Curl_safefree(data->state.referer); + data->state.referer_alloc = FALSE; + } + + /* Make a copy of the URL without crenditals and fragment */ + u = curl_url(); + if(!u) + return CURLE_OUT_OF_MEMORY; + + uc = curl_url_set(u, CURLUPART_URL, data->state.url, 0); + if(!uc) + uc = curl_url_set(u, CURLUPART_FRAGMENT, NULL, 0); + if(!uc) + uc = curl_url_set(u, CURLUPART_USER, NULL, 0); + if(!uc) + uc = curl_url_set(u, CURLUPART_PASSWORD, NULL, 0); + if(!uc) + uc = curl_url_get(u, CURLUPART_URL, &referer, 0); + + curl_url_cleanup(u); + + if(uc || referer == NULL) + return CURLE_OUT_OF_MEMORY; + + data->state.referer = referer; + data->state.referer_alloc = TRUE; /* yes, free this later */ + } + } + } + + if((type != FOLLOW_RETRY) && + (data->req.httpcode != 401) && (data->req.httpcode != 407) && + Curl_is_absolute_url(newurl, NULL, MAX_SCHEME_LEN)) + /* If this is not redirect due to a 401 or 407 response and an absolute + URL: don't allow a custom port number */ + disallowport = TRUE; + + DEBUGASSERT(data->state.uh); + uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl, + (type == FOLLOW_FAKE) ? CURLU_NON_SUPPORT_SCHEME : + ((type == FOLLOW_REDIR) ? CURLU_URLENCODE : 0) ); + if(uc) { + if(type != FOLLOW_FAKE) + return Curl_uc_to_curlcode(uc); + + /* the URL could not be parsed for some reason, but since this is FAKE + mode, just duplicate the field as-is */ + newurl = strdup(newurl); + if(!newurl) + return CURLE_OUT_OF_MEMORY; + } + else { + + uc = curl_url_get(data->state.uh, CURLUPART_URL, &newurl, 0); + if(uc) + return Curl_uc_to_curlcode(uc); + } + + if(type == FOLLOW_FAKE) { + /* we're only figuring out the new url if we would've followed locations + but now we're done so we can get out! */ + data->info.wouldredirect = newurl; + + if(reachedmax) { + failf(data, "Maximum (%ld) redirects followed", data->set.maxredirs); + return CURLE_TOO_MANY_REDIRECTS; + } + return CURLE_OK; + } + + if(disallowport) + data->state.allow_port = FALSE; + + if(data->state.url_alloc) + Curl_safefree(data->state.url); + + data->state.url = newurl; + data->state.url_alloc = TRUE; + + infof(data, "Issue another request to this URL: '%s'\n", data->state.url); + + /* + * We get here when the HTTP code is 300-399 (and 401). We need to perform + * differently based on exactly what return code there was. + * + * News from 7.10.6: we can also get here on a 401 or 407, in case we act on + * a HTTP (proxy-) authentication scheme other than Basic. + */ + switch(data->info.httpcode) { + /* 401 - Act on a WWW-Authenticate, we keep on moving and do the + Authorization: XXXX header in the HTTP request code snippet */ + /* 407 - Act on a Proxy-Authenticate, we keep on moving and do the + Proxy-Authorization: XXXX header in the HTTP request code snippet */ + /* 300 - Multiple Choices */ + /* 306 - Not used */ + /* 307 - Temporary Redirect */ + default: /* for all above (and the unknown ones) */ + /* Some codes are explicitly mentioned since I've checked RFC2616 and they + * seem to be OK to POST to. + */ + break; + case 301: /* Moved Permanently */ + /* (quote from RFC7231, section 6.4.2) + * + * Note: For historical reasons, a user agent MAY change the request + * method from POST to GET for the subsequent request. If this + * behavior is undesired, the 307 (Temporary Redirect) status code + * can be used instead. + * + * ---- + * + * Many webservers expect this, so these servers often answers to a POST + * request with an error page. To be sure that libcurl gets the page that + * most user agents would get, libcurl has to force GET. + * + * This behavior is forbidden by RFC1945 and the obsolete RFC2616, and + * can be overridden with CURLOPT_POSTREDIR. + */ + if((data->state.httpreq == HTTPREQ_POST + || data->state.httpreq == HTTPREQ_POST_FORM + || data->state.httpreq == HTTPREQ_POST_MIME) + && !(data->set.keep_post & CURL_REDIR_POST_301)) { + infof(data, "Switch from POST to GET\n"); + data->state.httpreq = HTTPREQ_GET; + } + break; + case 302: /* Found */ + /* (quote from RFC7231, section 6.4.3) + * + * Note: For historical reasons, a user agent MAY change the request + * method from POST to GET for the subsequent request. If this + * behavior is undesired, the 307 (Temporary Redirect) status code + * can be used instead. + * + * ---- + * + * Many webservers expect this, so these servers often answers to a POST + * request with an error page. To be sure that libcurl gets the page that + * most user agents would get, libcurl has to force GET. + * + * This behavior is forbidden by RFC1945 and the obsolete RFC2616, and + * can be overridden with CURLOPT_POSTREDIR. + */ + if((data->state.httpreq == HTTPREQ_POST + || data->state.httpreq == HTTPREQ_POST_FORM + || data->state.httpreq == HTTPREQ_POST_MIME) + && !(data->set.keep_post & CURL_REDIR_POST_302)) { + infof(data, "Switch from POST to GET\n"); + data->state.httpreq = HTTPREQ_GET; + } + break; + + case 303: /* See Other */ + /* 'See Other' location is not the resource but a substitute for the + * resource. In this case we switch the method to GET/HEAD, unless the + * method is POST and the user specified to keep it as POST. + * https://github.com/curl/curl/issues/5237#issuecomment-614641049 + */ + if(data->state.httpreq != HTTPREQ_GET && + ((data->state.httpreq != HTTPREQ_POST && + data->state.httpreq != HTTPREQ_POST_FORM && + data->state.httpreq != HTTPREQ_POST_MIME) || + !(data->set.keep_post & CURL_REDIR_POST_303))) { + data->state.httpreq = HTTPREQ_GET; + data->set.upload = false; + infof(data, "Switch to %s\n", + data->set.opt_no_body?"HEAD":"GET"); + } + break; + case 304: /* Not Modified */ + /* 304 means we did a conditional request and it was "Not modified". + * We shouldn't get any Location: header in this response! + */ + break; + case 305: /* Use Proxy */ + /* (quote from RFC2616, section 10.3.6): + * "The requested resource MUST be accessed through the proxy given + * by the Location field. The Location field gives the URI of the + * proxy. The recipient is expected to repeat this single request + * via the proxy. 305 responses MUST only be generated by origin + * servers." + */ + break; + } + Curl_pgrsTime(data, TIMER_REDIRECT); + Curl_pgrsResetTransferSizes(data); + + return CURLE_OK; +#endif /* CURL_DISABLE_HTTP */ +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22876/vuln.c b/benchmarks/pairs/vfc/curl-cve-2021-22876/vuln.c new file mode 100644 index 0000000..d4545af --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22876/vuln.c @@ -0,0 +1,226 @@ +/* Provenance: curl/curl Curl_follow (vuln). + * repo: curl/curl + * commit: 184ffc0bdfcab17eb96d1dd64f9c0cecc139e3e9 + * parent: 184ffc0bdfcab17eb96d1dd64f9c0cecc139e3e9 + * commit_url: https://github.com/curl/curl/commit/7214288898f5625a6cc196e22a74232eada7861c + * cve: CVE-2021-22876 + * license: curl + * function: Curl_follow + * relpath: lib/transfer.c + */ + +* Curl_follow() handles the URL redirect magic. Pass in the 'newurl' string + * as given by the remote server and set up the new URL to request. + * + * This function DOES NOT FREE the given url. + */ +CURLcode Curl_follow(struct Curl_easy *data, + char *newurl, /* the Location: string */ + followtype type) /* see transfer.h */ +{ +#ifdef CURL_DISABLE_HTTP + (void)data; + (void)newurl; + (void)type; + /* Location: following will not happen when HTTP is disabled */ + return CURLE_TOO_MANY_REDIRECTS; +#else + + /* Location: redirect */ + bool disallowport = FALSE; + bool reachedmax = FALSE; + CURLUcode uc; + + DEBUGASSERT(type != FOLLOW_NONE); + + if(type == FOLLOW_REDIR) { + if((data->set.maxredirs != -1) && + (data->state.followlocation >= data->set.maxredirs)) { + reachedmax = TRUE; + type = FOLLOW_FAKE; /* switch to fake to store the would-be-redirected + to URL */ + } + else { + /* mark the next request as a followed location: */ + data->state.this_is_a_follow = TRUE; + + data->state.followlocation++; /* count location-followers */ + + if(data->set.http_auto_referer) { + /* We are asked to automatically set the previous URL as the referer + when we get the next URL. We pick the ->url field, which may or may + not be 100% correct */ + + if(data->state.referer_alloc) { + Curl_safefree(data->state.referer); + data->state.referer_alloc = FALSE; + } + + data->state.referer = strdup(data->state.url); + if(!data->state.referer) + return CURLE_OUT_OF_MEMORY; + data->state.referer_alloc = TRUE; /* yes, free this later */ + } + } + } + + if((type != FOLLOW_RETRY) && + (data->req.httpcode != 401) && (data->req.httpcode != 407) && + Curl_is_absolute_url(newurl, NULL, MAX_SCHEME_LEN)) + /* If this is not redirect due to a 401 or 407 response and an absolute + URL: don't allow a custom port number */ + disallowport = TRUE; + + DEBUGASSERT(data->state.uh); + uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl, + (type == FOLLOW_FAKE) ? CURLU_NON_SUPPORT_SCHEME : + ((type == FOLLOW_REDIR) ? CURLU_URLENCODE : 0) ); + if(uc) { + if(type != FOLLOW_FAKE) + return Curl_uc_to_curlcode(uc); + + /* the URL could not be parsed for some reason, but since this is FAKE + mode, just duplicate the field as-is */ + newurl = strdup(newurl); + if(!newurl) + return CURLE_OUT_OF_MEMORY; + } + else { + + uc = curl_url_get(data->state.uh, CURLUPART_URL, &newurl, 0); + if(uc) + return Curl_uc_to_curlcode(uc); + } + + if(type == FOLLOW_FAKE) { + /* we're only figuring out the new url if we would've followed locations + but now we're done so we can get out! */ + data->info.wouldredirect = newurl; + + if(reachedmax) { + failf(data, "Maximum (%ld) redirects followed", data->set.maxredirs); + return CURLE_TOO_MANY_REDIRECTS; + } + return CURLE_OK; + } + + if(disallowport) + data->state.allow_port = FALSE; + + if(data->state.url_alloc) + Curl_safefree(data->state.url); + + data->state.url = newurl; + data->state.url_alloc = TRUE; + + infof(data, "Issue another request to this URL: '%s'\n", data->state.url); + + /* + * We get here when the HTTP code is 300-399 (and 401). We need to perform + * differently based on exactly what return code there was. + * + * News from 7.10.6: we can also get here on a 401 or 407, in case we act on + * a HTTP (proxy-) authentication scheme other than Basic. + */ + switch(data->info.httpcode) { + /* 401 - Act on a WWW-Authenticate, we keep on moving and do the + Authorization: XXXX header in the HTTP request code snippet */ + /* 407 - Act on a Proxy-Authenticate, we keep on moving and do the + Proxy-Authorization: XXXX header in the HTTP request code snippet */ + /* 300 - Multiple Choices */ + /* 306 - Not used */ + /* 307 - Temporary Redirect */ + default: /* for all above (and the unknown ones) */ + /* Some codes are explicitly mentioned since I've checked RFC2616 and they + * seem to be OK to POST to. + */ + break; + case 301: /* Moved Permanently */ + /* (quote from RFC7231, section 6.4.2) + * + * Note: For historical reasons, a user agent MAY change the request + * method from POST to GET for the subsequent request. If this + * behavior is undesired, the 307 (Temporary Redirect) status code + * can be used instead. + * + * ---- + * + * Many webservers expect this, so these servers often answers to a POST + * request with an error page. To be sure that libcurl gets the page that + * most user agents would get, libcurl has to force GET. + * + * This behavior is forbidden by RFC1945 and the obsolete RFC2616, and + * can be overridden with CURLOPT_POSTREDIR. + */ + if((data->state.httpreq == HTTPREQ_POST + || data->state.httpreq == HTTPREQ_POST_FORM + || data->state.httpreq == HTTPREQ_POST_MIME) + && !(data->set.keep_post & CURL_REDIR_POST_301)) { + infof(data, "Switch from POST to GET\n"); + data->state.httpreq = HTTPREQ_GET; + } + break; + case 302: /* Found */ + /* (quote from RFC7231, section 6.4.3) + * + * Note: For historical reasons, a user agent MAY change the request + * method from POST to GET for the subsequent request. If this + * behavior is undesired, the 307 (Temporary Redirect) status code + * can be used instead. + * + * ---- + * + * Many webservers expect this, so these servers often answers to a POST + * request with an error page. To be sure that libcurl gets the page that + * most user agents would get, libcurl has to force GET. + * + * This behavior is forbidden by RFC1945 and the obsolete RFC2616, and + * can be overridden with CURLOPT_POSTREDIR. + */ + if((data->state.httpreq == HTTPREQ_POST + || data->state.httpreq == HTTPREQ_POST_FORM + || data->state.httpreq == HTTPREQ_POST_MIME) + && !(data->set.keep_post & CURL_REDIR_POST_302)) { + infof(data, "Switch from POST to GET\n"); + data->state.httpreq = HTTPREQ_GET; + } + break; + + case 303: /* See Other */ + /* 'See Other' location is not the resource but a substitute for the + * resource. In this case we switch the method to GET/HEAD, unless the + * method is POST and the user specified to keep it as POST. + * https://github.com/curl/curl/issues/5237#issuecomment-614641049 + */ + if(data->state.httpreq != HTTPREQ_GET && + ((data->state.httpreq != HTTPREQ_POST && + data->state.httpreq != HTTPREQ_POST_FORM && + data->state.httpreq != HTTPREQ_POST_MIME) || + !(data->set.keep_post & CURL_REDIR_POST_303))) { + data->state.httpreq = HTTPREQ_GET; + data->set.upload = false; + infof(data, "Switch to %s\n", + data->set.opt_no_body?"HEAD":"GET"); + } + break; + case 304: /* Not Modified */ + /* 304 means we did a conditional request and it was "Not modified". + * We shouldn't get any Location: header in this response! + */ + break; + case 305: /* Use Proxy */ + /* (quote from RFC2616, section 10.3.6): + * "The requested resource MUST be accessed through the proxy given + * by the Location field. The Location field gives the URI of the + * proxy. The recipient is expected to repeat this single request + * via the proxy. 305 responses MUST only be generated by origin + * servers." + */ + break; + } + Curl_pgrsTime(data, TIMER_REDIRECT); + Curl_pgrsResetTransferSizes(data); + + return CURLE_OK; +#endif /* CURL_DISABLE_HTTP */ +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22890/fixed.c b/benchmarks/pairs/vfc/curl-cve-2021-22890/fixed.c new file mode 100644 index 0000000..b5f70d6 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22890/fixed.c @@ -0,0 +1,146 @@ +/* Provenance: curl/curl bearssl_connect_step1 (fixed). + * repo: curl/curl + * commit: b09c8ee15771c614c4bf3ddac893cdb12187c844 + * parent: 7214288898f5625a6cc196e22a74232eada7861c + * commit_url: https://github.com/curl/curl/commit/b09c8ee15771c614c4bf3ddac893cdb12187c844 + * cve: CVE-2021-22890 + * license: curl + * function: bearssl_connect_step1 + * relpath: lib/vtls/bearssl.c + */ + +static CURLcode bearssl_connect_step1(struct Curl_easy *data, + struct connectdata *conn, int sockindex) +{ + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; + const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); +#ifndef CURL_DISABLE_PROXY + const char *hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name; +#else + const char *hostname = conn->host.name; +#endif + const bool verifypeer = SSL_CONN_CONFIG(verifypeer); + const bool verifyhost = SSL_CONN_CONFIG(verifyhost); + CURLcode ret; + unsigned version_min, version_max; +#ifdef ENABLE_IPV6 + struct in6_addr addr; +#else + struct in_addr addr; +#endif + + switch(SSL_CONN_CONFIG(version)) { + case CURL_SSLVERSION_SSLv2: + failf(data, "BearSSL does not support SSLv2"); + return CURLE_SSL_CONNECT_ERROR; + case CURL_SSLVERSION_SSLv3: + failf(data, "BearSSL does not support SSLv3"); + return CURLE_SSL_CONNECT_ERROR; + case CURL_SSLVERSION_TLSv1_0: + version_min = BR_TLS10; + version_max = BR_TLS10; + break; + case CURL_SSLVERSION_TLSv1_1: + version_min = BR_TLS11; + version_max = BR_TLS11; + break; + case CURL_SSLVERSION_TLSv1_2: + version_min = BR_TLS12; + version_max = BR_TLS12; + break; + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + version_min = BR_TLS10; + version_max = BR_TLS12; + break; + default: + failf(data, "BearSSL: unknown CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; + } + + if(ssl_cafile) { + ret = load_cafile(ssl_cafile, &backend->anchors, &backend->anchors_len); + if(ret != CURLE_OK) { + if(verifypeer) { + failf(data, "error setting certificate verify locations." + " CAfile: %s", ssl_cafile); + return ret; + } + infof(data, "error setting certificate verify locations," + " continuing anyway:\n"); + } + } + + /* initialize SSL context */ + br_ssl_client_init_full(&backend->ctx, &backend->x509.minimal, + backend->anchors, backend->anchors_len); + br_ssl_engine_set_versions(&backend->ctx.eng, version_min, version_max); + br_ssl_engine_set_buffer(&backend->ctx.eng, backend->buf, + sizeof(backend->buf), 1); + + /* initialize X.509 context */ + backend->x509.vtable = &x509_vtable; + backend->x509.verifypeer = verifypeer; + backend->x509.verifyhost = verifyhost; + br_ssl_engine_set_x509(&backend->ctx.eng, &backend->x509.vtable); + + if(SSL_SET_OPTION(primary.sessionid)) { + void *session; + + Curl_ssl_sessionid_lock(data); + if(!Curl_ssl_getsessionid(data, conn, SSL_IS_PROXY() ? TRUE : FALSE, + &session, NULL, sockindex)) { + br_ssl_engine_set_session_parameters(&backend->ctx.eng, session); + infof(data, "BearSSL: re-using session ID\n"); + } + Curl_ssl_sessionid_unlock(data); + } + + if(conn->bits.tls_enable_alpn) { + int cur = 0; + + /* NOTE: when adding more protocols here, increase the size of the + * protocols array in `struct ssl_backend_data`. + */ + +#ifdef USE_NGHTTP2 + if(data->state.httpversion >= CURL_HTTP_VERSION_2 +#ifndef CURL_DISABLE_PROXY + && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy) +#endif + ) { + backend->protocols[cur++] = NGHTTP2_PROTO_VERSION_ID; + infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); + } +#endif + + backend->protocols[cur++] = ALPN_HTTP_1_1; + infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); + + br_ssl_engine_set_protocol_names(&backend->ctx.eng, + backend->protocols, cur); + } + + if((1 == Curl_inet_pton(AF_INET, hostname, &addr)) +#ifdef ENABLE_IPV6 + || (1 == Curl_inet_pton(AF_INET6, hostname, &addr)) +#endif + ) { + if(verifyhost) { + failf(data, "BearSSL: " + "host verification of IP address is not supported"); + return CURLE_PEER_FAILED_VERIFICATION; + } + hostname = NULL; + } + + if(!br_ssl_client_reset(&backend->ctx, hostname, 0)) + return CURLE_FAILED_INIT; + backend->active = TRUE; + + connssl->connecting_state = ssl_connect_2; + + return CURLE_OK; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22890/vuln.c b/benchmarks/pairs/vfc/curl-cve-2021-22890/vuln.c new file mode 100644 index 0000000..4481de0 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22890/vuln.c @@ -0,0 +1,145 @@ +/* Provenance: curl/curl bearssl_connect_step1 (vuln). + * repo: curl/curl + * commit: 7214288898f5625a6cc196e22a74232eada7861c + * parent: 7214288898f5625a6cc196e22a74232eada7861c + * commit_url: https://github.com/curl/curl/commit/b09c8ee15771c614c4bf3ddac893cdb12187c844 + * cve: CVE-2021-22890 + * license: curl + * function: bearssl_connect_step1 + * relpath: lib/vtls/bearssl.c + */ + +static CURLcode bearssl_connect_step1(struct Curl_easy *data, + struct connectdata *conn, int sockindex) +{ + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; + const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); +#ifndef CURL_DISABLE_PROXY + const char *hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name; +#else + const char *hostname = conn->host.name; +#endif + const bool verifypeer = SSL_CONN_CONFIG(verifypeer); + const bool verifyhost = SSL_CONN_CONFIG(verifyhost); + CURLcode ret; + unsigned version_min, version_max; +#ifdef ENABLE_IPV6 + struct in6_addr addr; +#else + struct in_addr addr; +#endif + + switch(SSL_CONN_CONFIG(version)) { + case CURL_SSLVERSION_SSLv2: + failf(data, "BearSSL does not support SSLv2"); + return CURLE_SSL_CONNECT_ERROR; + case CURL_SSLVERSION_SSLv3: + failf(data, "BearSSL does not support SSLv3"); + return CURLE_SSL_CONNECT_ERROR; + case CURL_SSLVERSION_TLSv1_0: + version_min = BR_TLS10; + version_max = BR_TLS10; + break; + case CURL_SSLVERSION_TLSv1_1: + version_min = BR_TLS11; + version_max = BR_TLS11; + break; + case CURL_SSLVERSION_TLSv1_2: + version_min = BR_TLS12; + version_max = BR_TLS12; + break; + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + version_min = BR_TLS10; + version_max = BR_TLS12; + break; + default: + failf(data, "BearSSL: unknown CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; + } + + if(ssl_cafile) { + ret = load_cafile(ssl_cafile, &backend->anchors, &backend->anchors_len); + if(ret != CURLE_OK) { + if(verifypeer) { + failf(data, "error setting certificate verify locations." + " CAfile: %s", ssl_cafile); + return ret; + } + infof(data, "error setting certificate verify locations," + " continuing anyway:\n"); + } + } + + /* initialize SSL context */ + br_ssl_client_init_full(&backend->ctx, &backend->x509.minimal, + backend->anchors, backend->anchors_len); + br_ssl_engine_set_versions(&backend->ctx.eng, version_min, version_max); + br_ssl_engine_set_buffer(&backend->ctx.eng, backend->buf, + sizeof(backend->buf), 1); + + /* initialize X.509 context */ + backend->x509.vtable = &x509_vtable; + backend->x509.verifypeer = verifypeer; + backend->x509.verifyhost = verifyhost; + br_ssl_engine_set_x509(&backend->ctx.eng, &backend->x509.vtable); + + if(SSL_SET_OPTION(primary.sessionid)) { + void *session; + + Curl_ssl_sessionid_lock(data); + if(!Curl_ssl_getsessionid(data, conn, &session, NULL, sockindex)) { + br_ssl_engine_set_session_parameters(&backend->ctx.eng, session); + infof(data, "BearSSL: re-using session ID\n"); + } + Curl_ssl_sessionid_unlock(data); + } + + if(conn->bits.tls_enable_alpn) { + int cur = 0; + + /* NOTE: when adding more protocols here, increase the size of the + * protocols array in `struct ssl_backend_data`. + */ + +#ifdef USE_NGHTTP2 + if(data->state.httpversion >= CURL_HTTP_VERSION_2 +#ifndef CURL_DISABLE_PROXY + && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy) +#endif + ) { + backend->protocols[cur++] = NGHTTP2_PROTO_VERSION_ID; + infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); + } +#endif + + backend->protocols[cur++] = ALPN_HTTP_1_1; + infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); + + br_ssl_engine_set_protocol_names(&backend->ctx.eng, + backend->protocols, cur); + } + + if((1 == Curl_inet_pton(AF_INET, hostname, &addr)) +#ifdef ENABLE_IPV6 + || (1 == Curl_inet_pton(AF_INET6, hostname, &addr)) +#endif + ) { + if(verifyhost) { + failf(data, "BearSSL: " + "host verification of IP address is not supported"); + return CURLE_PEER_FAILED_VERIFICATION; + } + hostname = NULL; + } + + if(!br_ssl_client_reset(&backend->ctx, hostname, 0)) + return CURLE_FAILED_INIT; + backend->active = TRUE; + + connssl->connecting_state = ssl_connect_2; + + return CURLE_OK; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22898/fixed.c b/benchmarks/pairs/vfc/curl-cve-2021-22898/fixed.c new file mode 100644 index 0000000..e7ef2f6 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22898/fixed.c @@ -0,0 +1,86 @@ +/* Provenance: curl/curl suboption (fixed). + * repo: curl/curl + * commit: 39ce47f219b09c380b81f89fe54ac586c8db6bde + * parent: bbb71507b7bab52002f9b1e0880bed6a32834511 + * commit_url: https://github.com/curl/curl/commit/39ce47f219b09c380b81f89fe54ac586c8db6bde + * cve: CVE-2021-22898 + * license: curl + * function: suboption + * relpath: lib/telnet.c + */ + +* suboption() + * + * Look at the sub-option buffer, and try to be helpful to the other + * side. + */ + +static void suboption(struct Curl_easy *data) +{ + struct curl_slist *v; + unsigned char temp[2048]; + ssize_t bytes_written; + size_t len; + int err; + char varname[128] = ""; + char varval[128] = ""; + struct TELNET *tn = data->req.p.telnet; + struct connectdata *conn = data->conn; + + printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn) + 2); + switch(CURL_SB_GET(tn)) { + case CURL_TELOPT_TTYPE: + len = strlen(tn->subopt_ttype) + 4 + 2; + msnprintf((char *)temp, sizeof(temp), + "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE, + CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE); + bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); + if(bytes_written < 0) { + err = SOCKERRNO; + failf(data,"Sending data failed (%d)",err); + } + printsub(data, '>', &temp[2], len-2); + break; + case CURL_TELOPT_XDISPLOC: + len = strlen(tn->subopt_xdisploc) + 4 + 2; + msnprintf((char *)temp, sizeof(temp), + "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC, + CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE); + bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); + if(bytes_written < 0) { + err = SOCKERRNO; + failf(data,"Sending data failed (%d)",err); + } + printsub(data, '>', &temp[2], len-2); + break; + case CURL_TELOPT_NEW_ENVIRON: + msnprintf((char *)temp, sizeof(temp), + "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON, + CURL_TELQUAL_IS); + len = 4; + + for(v = tn->telnet_vars; v; v = v->next) { + size_t tmplen = (strlen(v->data) + 1); + /* Add the variable only if it fits */ + if(len + tmplen < (int)sizeof(temp)-6) { + if(sscanf(v->data, "%127[^,],%127s", varname, varval) == 2) { + msnprintf((char *)&temp[len], sizeof(temp) - len, + "%c%s%c%s", CURL_NEW_ENV_VAR, varname, + CURL_NEW_ENV_VALUE, varval); + len += tmplen; + } + } + } + msnprintf((char *)&temp[len], sizeof(temp) - len, + "%c%c", CURL_IAC, CURL_SE); + len += 2; + bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); + if(bytes_written < 0) { + err = SOCKERRNO; + failf(data,"Sending data failed (%d)",err); + } + printsub(data, '>', &temp[2], len-2); + break; + } + return; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22898/vuln.c b/benchmarks/pairs/vfc/curl-cve-2021-22898/vuln.c new file mode 100644 index 0000000..dbb2528 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22898/vuln.c @@ -0,0 +1,86 @@ +/* Provenance: curl/curl suboption (vuln). + * repo: curl/curl + * commit: bbb71507b7bab52002f9b1e0880bed6a32834511 + * parent: bbb71507b7bab52002f9b1e0880bed6a32834511 + * commit_url: https://github.com/curl/curl/commit/39ce47f219b09c380b81f89fe54ac586c8db6bde + * cve: CVE-2021-22898 + * license: curl + * function: suboption + * relpath: lib/telnet.c + */ + +* suboption() + * + * Look at the sub-option buffer, and try to be helpful to the other + * side. + */ + +static void suboption(struct Curl_easy *data) +{ + struct curl_slist *v; + unsigned char temp[2048]; + ssize_t bytes_written; + size_t len; + int err; + char varname[128] = ""; + char varval[128] = ""; + struct TELNET *tn = data->req.p.telnet; + struct connectdata *conn = data->conn; + + printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn) + 2); + switch(CURL_SB_GET(tn)) { + case CURL_TELOPT_TTYPE: + len = strlen(tn->subopt_ttype) + 4 + 2; + msnprintf((char *)temp, sizeof(temp), + "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE, + CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE); + bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); + if(bytes_written < 0) { + err = SOCKERRNO; + failf(data,"Sending data failed (%d)",err); + } + printsub(data, '>', &temp[2], len-2); + break; + case CURL_TELOPT_XDISPLOC: + len = strlen(tn->subopt_xdisploc) + 4 + 2; + msnprintf((char *)temp, sizeof(temp), + "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC, + CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE); + bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); + if(bytes_written < 0) { + err = SOCKERRNO; + failf(data,"Sending data failed (%d)",err); + } + printsub(data, '>', &temp[2], len-2); + break; + case CURL_TELOPT_NEW_ENVIRON: + msnprintf((char *)temp, sizeof(temp), + "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON, + CURL_TELQUAL_IS); + len = 4; + + for(v = tn->telnet_vars; v; v = v->next) { + size_t tmplen = (strlen(v->data) + 1); + /* Add the variable only if it fits */ + if(len + tmplen < (int)sizeof(temp)-6) { + if(sscanf(v->data, "%127[^,],%127s", varname, varval)) { + msnprintf((char *)&temp[len], sizeof(temp) - len, + "%c%s%c%s", CURL_NEW_ENV_VAR, varname, + CURL_NEW_ENV_VALUE, varval); + len += tmplen; + } + } + } + msnprintf((char *)&temp[len], sizeof(temp) - len, + "%c%c", CURL_IAC, CURL_SE); + len += 2; + bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); + if(bytes_written < 0) { + err = SOCKERRNO; + failf(data,"Sending data failed (%d)",err); + } + printsub(data, '>', &temp[2], len-2); + break; + } + return; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22901-ossl_connect_step1/fixed.c b/benchmarks/pairs/vfc/curl-cve-2021-22901-ossl_connect_step1/fixed.c new file mode 100644 index 0000000..14bf0d7 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22901-ossl_connect_step1/fixed.c @@ -0,0 +1,707 @@ +/* Provenance: curl/curl ossl_connect_step1 (fixed). + * repo: curl/curl + * commit: 7f4a9a9b2a49547eae24d2e19bc5c346e9026479 + * parent: 39ce47f219b09c380b81f89fe54ac586c8db6bde + * commit_url: https://github.com/curl/curl/commit/7f4a9a9b2a49547eae24d2e19bc5c346e9026479 + * cve: CVE-2021-22901 + * license: curl + * function: ossl_connect_step1 + * relpath: lib/vtls/openssl.c + */ + +static CURLcode ossl_connect_step1(struct Curl_easy *data, + struct connectdata *conn, int sockindex) +{ + CURLcode result = CURLE_OK; + char *ciphers; + SSL_METHOD_QUAL SSL_METHOD *req_method = NULL; + X509_LOOKUP *lookup = NULL; + curl_socket_t sockfd = conn->sock[sockindex]; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + ctx_option_t ctx_options = 0; + void *ssl_sessionid = NULL; + +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + bool sni; + const char * const hostname = SSL_HOST_NAME(); + +#ifdef ENABLE_IPV6 + struct in6_addr addr; +#else + struct in_addr addr; +#endif +#endif + const long int ssl_version = SSL_CONN_CONFIG(version); +#ifdef USE_OPENSSL_SRP + const enum CURL_TLSAUTH ssl_authtype = SSL_SET_OPTION(authtype); +#endif + char * const ssl_cert = SSL_SET_OPTION(primary.clientcert); + const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(primary.cert_blob); + const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_blob); + const char * const ssl_cert_type = SSL_SET_OPTION(cert_type); + const char * const ssl_cafile = + /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */ + (ca_info_blob ? NULL : SSL_CONN_CONFIG(CAfile)); + const char * const ssl_capath = SSL_CONN_CONFIG(CApath); + const bool verifypeer = SSL_CONN_CONFIG(verifypeer); + const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile); + char error_buffer[256]; + struct ssl_backend_data *backend = connssl->backend; + bool imported_native_ca = false; + + DEBUGASSERT(ssl_connect_1 == connssl->connecting_state); + + /* Make funny stuff to get random input */ + result = ossl_seed(data); + if(result) + return result; + + SSL_SET_OPTION_LVALUE(certverifyresult) = !X509_V_OK; + + /* check to see if we've been told to use an explicit SSL/TLS version */ + + switch(ssl_version) { + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + case CURL_SSLVERSION_TLSv1_0: + case CURL_SSLVERSION_TLSv1_1: + case CURL_SSLVERSION_TLSv1_2: + case CURL_SSLVERSION_TLSv1_3: + /* it will be handled later with the context options */ +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) + req_method = TLS_client_method(); +#else + req_method = SSLv23_client_method(); +#endif + use_sni(TRUE); + break; + case CURL_SSLVERSION_SSLv2: + failf(data, "No SSLv2 support"); + return CURLE_NOT_BUILT_IN; + case CURL_SSLVERSION_SSLv3: + failf(data, "No SSLv3 support"); + return CURLE_NOT_BUILT_IN; + default: + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; + } + + if(backend->ctx) + SSL_CTX_free(backend->ctx); + backend->ctx = SSL_CTX_new(req_method); + + if(!backend->ctx) { + failf(data, "SSL: couldn't create a context: %s", + ossl_strerror(ERR_peek_error(), error_buffer, sizeof(error_buffer))); + return CURLE_OUT_OF_MEMORY; + } + +#ifdef SSL_MODE_RELEASE_BUFFERS + SSL_CTX_set_mode(backend->ctx, SSL_MODE_RELEASE_BUFFERS); +#endif + +#ifdef SSL_CTRL_SET_MSG_CALLBACK + if(data->set.fdebug && data->set.verbose) { + /* the SSL trace callback is only used for verbose logging */ + SSL_CTX_set_msg_callback(backend->ctx, ossl_trace); + SSL_CTX_set_msg_callback_arg(backend->ctx, conn); + set_logger(conn, data); + } +#endif + + /* OpenSSL contains code to work-around lots of bugs and flaws in various + SSL-implementations. SSL_CTX_set_options() is used to enabled those + work-arounds. The man page for this option states that SSL_OP_ALL enables + all the work-arounds and that "It is usually safe to use SSL_OP_ALL to + enable the bug workaround options if compatibility with somewhat broken + implementations is desired." + + The "-no_ticket" option was introduced in Openssl0.9.8j. It's a flag to + disable "rfc4507bis session ticket support". rfc4507bis was later turned + into the proper RFC5077 it seems: https://tools.ietf.org/html/rfc5077 + + The enabled extension concerns the session management. I wonder how often + libcurl stops a connection and then resumes a TLS session. also, sending + the session data is some overhead. .I suggest that you just use your + proposed patch (which explicitly disables TICKET). + + If someone writes an application with libcurl and openssl who wants to + enable the feature, one can do this in the SSL callback. + + SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG option enabling allowed proper + interoperability with web server Netscape Enterprise Server 2.0.1 which + was released back in 1996. + + Due to CVE-2010-4180, option SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG has + become ineffective as of OpenSSL 0.9.8q and 1.0.0c. In order to mitigate + CVE-2010-4180 when using previous OpenSSL versions we no longer enable + this option regardless of OpenSSL version and SSL_OP_ALL definition. + + OpenSSL added a work-around for a SSL 3.0/TLS 1.0 CBC vulnerability + (https://www.openssl.org/~bodo/tls-cbc.txt). In 0.9.6e they added a bit to + SSL_OP_ALL that _disables_ that work-around despite the fact that + SSL_OP_ALL is documented to do "rather harmless" workarounds. In order to + keep the secure work-around, the SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS bit + must not be set. + */ + + ctx_options = SSL_OP_ALL; + +#ifdef SSL_OP_NO_TICKET + ctx_options |= SSL_OP_NO_TICKET; +#endif + +#ifdef SSL_OP_NO_COMPRESSION + ctx_options |= SSL_OP_NO_COMPRESSION; +#endif + +#ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG + /* mitigate CVE-2010-4180 */ + ctx_options &= ~SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG; +#endif + +#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS + /* unless the user explicitly ask to allow the protocol vulnerability we + use the work-around */ + if(!SSL_SET_OPTION(enable_beast)) + ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; +#endif + + switch(ssl_version) { + case CURL_SSLVERSION_SSLv2: + case CURL_SSLVERSION_SSLv3: + return CURLE_NOT_BUILT_IN; + + /* "--tlsv" options mean TLS >= version */ + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: /* TLS >= version 1.0 */ + case CURL_SSLVERSION_TLSv1_0: /* TLS >= version 1.0 */ + case CURL_SSLVERSION_TLSv1_1: /* TLS >= version 1.1 */ + case CURL_SSLVERSION_TLSv1_2: /* TLS >= version 1.2 */ + case CURL_SSLVERSION_TLSv1_3: /* TLS >= version 1.3 */ + /* asking for any TLS version as the minimum, means no SSL versions + allowed */ + ctx_options |= SSL_OP_NO_SSLv2; + ctx_options |= SSL_OP_NO_SSLv3; + +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) /* 1.1.0 */ + result = set_ssl_version_min_max(backend->ctx, conn); +#else + result = set_ssl_version_min_max_legacy(&ctx_options, data, conn, + sockindex); +#endif + if(result != CURLE_OK) + return result; + break; + + default: + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; + } + + SSL_CTX_set_options(backend->ctx, ctx_options); + +#ifdef HAS_NPN + if(conn->bits.tls_enable_npn) + SSL_CTX_set_next_proto_select_cb(backend->ctx, select_next_proto_cb, data); +#endif + +#ifdef HAS_ALPN + if(conn->bits.tls_enable_alpn) { + int cur = 0; + unsigned char protocols[128]; + +#ifdef USE_HTTP2 + if(data->state.httpwant >= CURL_HTTP_VERSION_2 +#ifndef CURL_DISABLE_PROXY + && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy) +#endif + ) { + protocols[cur++] = ALPN_H2_LENGTH; + + memcpy(&protocols[cur], ALPN_H2, ALPN_H2_LENGTH); + cur += ALPN_H2_LENGTH; + infof(data, "ALPN, offering %s\n", ALPN_H2); + } +#endif + + protocols[cur++] = ALPN_HTTP_1_1_LENGTH; + memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); + cur += ALPN_HTTP_1_1_LENGTH; + infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); + + /* expects length prefixed preference ordered list of protocols in wire + * format + */ + if(SSL_CTX_set_alpn_protos(backend->ctx, protocols, cur)) { + failf(data, "Error setting ALPN"); + return CURLE_SSL_CONNECT_ERROR; + } + } +#endif + + if(ssl_cert || ssl_cert_blob || ssl_cert_type) { + if(!result && + !cert_stuff(data, backend->ctx, + ssl_cert, ssl_cert_blob, ssl_cert_type, + SSL_SET_OPTION(key), SSL_SET_OPTION(key_blob), + SSL_SET_OPTION(key_type), SSL_SET_OPTION(key_passwd))) + result = CURLE_SSL_CERTPROBLEM; + if(result) + /* failf() is already done in cert_stuff() */ + return result; + } + + ciphers = SSL_CONN_CONFIG(cipher_list); + if(!ciphers) + ciphers = (char *)DEFAULT_CIPHER_SELECTION; + if(ciphers) { + if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) { + failf(data, "failed setting cipher list: %s", ciphers); + return CURLE_SSL_CIPHER; + } + infof(data, "Cipher selection: %s\n", ciphers); + } + +#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES + { + char *ciphers13 = SSL_CONN_CONFIG(cipher_list13); + if(ciphers13) { + if(!SSL_CTX_set_ciphersuites(backend->ctx, ciphers13)) { + failf(data, "failed setting TLS 1.3 cipher suite: %s", ciphers13); + return CURLE_SSL_CIPHER; + } + infof(data, "TLS 1.3 cipher selection: %s\n", ciphers13); + } + } +#endif + +#ifdef HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH + /* OpenSSL 1.1.1 requires clients to opt-in for PHA */ + SSL_CTX_set_post_handshake_auth(backend->ctx, 1); +#endif + +#ifdef HAVE_SSL_CTX_SET_EC_CURVES + { + char *curves = SSL_CONN_CONFIG(curves); + if(curves) { + if(!SSL_CTX_set1_curves_list(backend->ctx, curves)) { + failf(data, "failed setting curves list: '%s'", curves); + return CURLE_SSL_CIPHER; + } + } + } +#endif + +#ifdef USE_OPENSSL_SRP + if(ssl_authtype == CURL_TLSAUTH_SRP) { + char * const ssl_username = SSL_SET_OPTION(username); + + infof(data, "Using TLS-SRP username: %s\n", ssl_username); + + if(!SSL_CTX_set_srp_username(backend->ctx, ssl_username)) { + failf(data, "Unable to set SRP user name"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + if(!SSL_CTX_set_srp_password(backend->ctx, SSL_SET_OPTION(password))) { + failf(data, "failed setting SRP password"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + if(!SSL_CONN_CONFIG(cipher_list)) { + infof(data, "Setting cipher list SRP\n"); + + if(!SSL_CTX_set_cipher_list(backend->ctx, "SRP")) { + failf(data, "failed setting SRP cipher list"); + return CURLE_SSL_CIPHER; + } + } + } +#endif + + +#if defined(USE_WIN32_CRYPTO) + /* Import certificates from the Windows root certificate store if requested. + https://stackoverflow.com/questions/9507184/ + https://github.com/d3x0r/SACK/blob/master/src/netlib/ssl_layer.c#L1037 + https://tools.ietf.org/html/rfc5280 */ + if((SSL_CONN_CONFIG(verifypeer) || SSL_CONN_CONFIG(verifyhost)) && + (SSL_SET_OPTION(native_ca_store))) { + X509_STORE *store = SSL_CTX_get_cert_store(backend->ctx); + HCERTSTORE hStore = CertOpenSystemStore(0, TEXT("ROOT")); + + if(hStore) { + PCCERT_CONTEXT pContext = NULL; + /* The array of enhanced key usage OIDs will vary per certificate and is + declared outside of the loop so that rather than malloc/free each + iteration we can grow it with realloc, when necessary. */ + CERT_ENHKEY_USAGE *enhkey_usage = NULL; + DWORD enhkey_usage_size = 0; + + /* This loop makes a best effort to import all valid certificates from + the MS root store. If a certificate cannot be imported it is skipped. + 'result' is used to store only hard-fail conditions (such as out of + memory) that cause an early break. */ + result = CURLE_OK; + for(;;) { + X509 *x509; + FILETIME now; + BYTE key_usage[2]; + DWORD req_size; + const unsigned char *encoded_cert; +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + char cert_name[256]; +#endif + + pContext = CertEnumCertificatesInStore(hStore, pContext); + if(!pContext) + break; + +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + if(!CertGetNameStringA(pContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, + NULL, cert_name, sizeof(cert_name))) { + strcpy(cert_name, "Unknown"); + } + infof(data, "SSL: Checking cert \"%s\"\n", cert_name); +#endif + + encoded_cert = (const unsigned char *)pContext->pbCertEncoded; + if(!encoded_cert) + continue; + + GetSystemTimeAsFileTime(&now); + if(CompareFileTime(&pContext->pCertInfo->NotBefore, &now) > 0 || + CompareFileTime(&now, &pContext->pCertInfo->NotAfter) > 0) + continue; + + /* If key usage exists check for signing attribute */ + if(CertGetIntendedKeyUsage(pContext->dwCertEncodingType, + pContext->pCertInfo, + key_usage, sizeof(key_usage))) { + if(!(key_usage[0] & CERT_KEY_CERT_SIGN_KEY_USAGE)) + continue; + } + else if(GetLastError()) + continue; + + /* If enhanced key usage exists check for server auth attribute. + * + * Note "In a Microsoft environment, a certificate might also have EKU + * extended properties that specify valid uses for the certificate." + * The call below checks both, and behavior varies depending on what is + * found. For more details see CertGetEnhancedKeyUsage doc. + */ + if(CertGetEnhancedKeyUsage(pContext, 0, NULL, &req_size)) { + if(req_size && req_size > enhkey_usage_size) { + void *tmp = realloc(enhkey_usage, req_size); + + if(!tmp) { + failf(data, "SSL: Out of memory allocating for OID list"); + result = CURLE_OUT_OF_MEMORY; + break; + } + + enhkey_usage = (CERT_ENHKEY_USAGE *)tmp; + enhkey_usage_size = req_size; + } + + if(CertGetEnhancedKeyUsage(pContext, 0, enhkey_usage, &req_size)) { + if(!enhkey_usage->cUsageIdentifier) { + /* "If GetLastError returns CRYPT_E_NOT_FOUND, the certificate is + good for all uses. If it returns zero, the certificate has no + valid uses." */ + if((HRESULT)GetLastError() != CRYPT_E_NOT_FOUND) + continue; + } + else { + DWORD i; + bool found = false; + + for(i = 0; i < enhkey_usage->cUsageIdentifier; ++i) { + if(!strcmp("1.3.6.1.5.5.7.3.1" /* OID server auth */, + enhkey_usage->rgpszUsageIdentifier[i])) { + found = true; + break; + } + } + + if(!found) + continue; + } + } + else + continue; + } + else + continue; + + x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded); + if(!x509) + continue; + + /* Try to import the certificate. This may fail for legitimate reasons + such as duplicate certificate, which is allowed by MS but not + OpenSSL. */ + if(X509_STORE_add_cert(store, x509) == 1) { +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + infof(data, "SSL: Imported cert \"%s\"\n", cert_name); +#endif + imported_native_ca = true; + } + X509_free(x509); + } + + free(enhkey_usage); + CertFreeCertificateContext(pContext); + CertCloseStore(hStore, 0); + + if(result) + return result; + } + if(imported_native_ca) + infof(data, "successfully imported windows ca store\n"); + else + infof(data, "error importing windows ca store, continuing anyway\n"); + } +#endif + + if(ca_info_blob) { + result = load_cacert_from_memory(backend->ctx, ca_info_blob); + if(result) { + if(result == CURLE_OUT_OF_MEMORY || + (verifypeer && !imported_native_ca)) { + failf(data, "error importing CA certificate blob"); + return result; + } + /* Only warning if no certificate verification is required. */ + infof(data, "error importing CA certificate blob, continuing anyway\n"); + } + } + +#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) + /* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */ + { + if(ssl_cafile) { + if(!SSL_CTX_load_verify_file(backend->ctx, ssl_cafile)) { + if(verifypeer && !imported_native_ca) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate file: %s", ssl_cafile); + return CURLE_SSL_CACERT_BADFILE; + } + /* Continue with a warning if no certificate verif is required. */ + infof(data, "error setting certificate file, continuing anyway\n"); + } + infof(data, " CAfile: %s\n", ssl_cafile); + } + if(ssl_capath) { + if(!SSL_CTX_load_verify_dir(backend->ctx, ssl_capath)) { + if(verifypeer && !imported_native_ca) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate path: %s", ssl_capath); + return CURLE_SSL_CACERT_BADFILE; + } + /* Continue with a warning if no certificate verif is required. */ + infof(data, "error setting certificate path, continuing anyway\n"); + } + infof(data, " CApath: %s\n", ssl_capath); + } + } +#else + if(ssl_cafile || ssl_capath) { + /* tell SSL where to find CA certificates that are used to verify + the servers certificate. */ + if(!SSL_CTX_load_verify_locations(backend->ctx, ssl_cafile, ssl_capath)) { + if(verifypeer && !imported_native_ca) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate verify locations:" + " CAfile: %s CApath: %s", + ssl_cafile ? ssl_cafile : "none", + ssl_capath ? ssl_capath : "none"); + return CURLE_SSL_CACERT_BADFILE; + } + /* Just continue with a warning if no strict certificate verification + is required. */ + infof(data, "error setting certificate verify locations," + " continuing anyway:\n"); + } + else { + /* Everything is fine. */ + infof(data, "successfully set certificate verify locations:\n"); + } + infof(data, " CAfile: %s\n", ssl_cafile ? ssl_cafile : "none"); + infof(data, " CApath: %s\n", ssl_capath ? ssl_capath : "none"); + } +#endif + +#ifdef CURL_CA_FALLBACK + if(verifypeer && + !ca_info_blob && !ssl_cafile && !ssl_capath && !imported_native_ca) { + /* verifying the peer without any CA certificates won't + work so use openssl's built in default as fallback */ + SSL_CTX_set_default_verify_paths(backend->ctx); + } +#endif + + if(ssl_crlfile) { + /* tell SSL where to find CRL file that is used to check certificate + * revocation */ + lookup = X509_STORE_add_lookup(SSL_CTX_get_cert_store(backend->ctx), + X509_LOOKUP_file()); + if(!lookup || + (!X509_load_crl_file(lookup, ssl_crlfile, X509_FILETYPE_PEM)) ) { + failf(data, "error loading CRL file: %s", ssl_crlfile); + return CURLE_SSL_CRL_BADFILE; + } + /* Everything is fine. */ + infof(data, "successfully load CRL file:\n"); + X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx), + X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); + + infof(data, " CRLfile: %s\n", ssl_crlfile); + } + + if(verifypeer) { + /* Try building a chain using issuers in the trusted store first to avoid + problems with server-sent legacy intermediates. Newer versions of + OpenSSL do alternate chain checking by default but we do not know how to + determine that in a reliable manner. + https://rt.openssl.org/Ticket/Display.html?id=3621&user=guest&pass=guest + */ +#if defined(X509_V_FLAG_TRUSTED_FIRST) + X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx), + X509_V_FLAG_TRUSTED_FIRST); +#endif +#ifdef X509_V_FLAG_PARTIAL_CHAIN + if(!SSL_SET_OPTION(no_partialchain) && !ssl_crlfile) { + /* Have intermediate certificates in the trust store be treated as + trust-anchors, in the same way as self-signed root CA certificates + are. This allows users to verify servers using the intermediate cert + only, instead of needing the whole chain. + + Due to OpenSSL bug https://github.com/openssl/openssl/issues/5081 we + cannot do partial chains with CRL check. + */ + X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx), + X509_V_FLAG_PARTIAL_CHAIN); + } +#endif + } + + /* SSL always tries to verify the peer, this only says whether it should + * fail to connect if the verification fails, or if it should continue + * anyway. In the latter case the result of the verification is checked with + * SSL_get_verify_result() below. */ + SSL_CTX_set_verify(backend->ctx, + verifypeer ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL); + + /* Enable logging of secrets to the file specified in env SSLKEYLOGFILE. */ +#ifdef HAVE_KEYLOG_CALLBACK + if(Curl_tls_keylog_enabled()) { + SSL_CTX_set_keylog_callback(backend->ctx, ossl_keylog_callback); + } +#endif + + /* Enable the session cache because it's a prerequisite for the "new session" + * callback. Use the "external storage" mode to avoid that OpenSSL creates + * an internal session cache. + */ + SSL_CTX_set_session_cache_mode(backend->ctx, + SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL); + SSL_CTX_sess_set_new_cb(backend->ctx, ossl_new_session_cb); + + /* give application a chance to interfere with SSL set up. */ + if(data->set.ssl.fsslctx) { + Curl_set_in_callback(data, true); + result = (*data->set.ssl.fsslctx)(data, backend->ctx, + data->set.ssl.fsslctxp); + Curl_set_in_callback(data, false); + if(result) { + failf(data, "error signaled by ssl ctx callback"); + return result; + } + } + + /* Lets make an SSL structure */ + if(backend->handle) + SSL_free(backend->handle); + backend->handle = SSL_new(backend->ctx); + if(!backend->handle) { + failf(data, "SSL: couldn't create a context (handle)!"); + return CURLE_OUT_OF_MEMORY; + } + +#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ + !defined(OPENSSL_NO_OCSP) + if(SSL_CONN_CONFIG(verifystatus)) + SSL_set_tlsext_status_type(backend->handle, TLSEXT_STATUSTYPE_ocsp); +#endif + +#if defined(OPENSSL_IS_BORINGSSL) && defined(ALLOW_RENEG) + SSL_set_renegotiate_mode(backend->handle, ssl_renegotiate_freely); +#endif + + SSL_set_connect_state(backend->handle); + + backend->server_cert = 0x0; +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) && +#ifdef ENABLE_IPV6 + (0 == Curl_inet_pton(AF_INET6, hostname, &addr)) && +#endif + sni) { + size_t nlen = strlen(hostname); + if((long)nlen >= data->set.buffer_size) + /* this is seriously messed up */ + return CURLE_SSL_CONNECT_ERROR; + + /* RFC 6066 section 3 says the SNI field is case insensitive, but browsers + send the data lowercase and subsequently there are now numerous servers + out there that don't work unless the name is lowercased */ + Curl_strntolower(data->state.buffer, hostname, nlen); + data->state.buffer[nlen] = 0; + if(!SSL_set_tlsext_host_name(backend->handle, data->state.buffer)) + infof(data, "WARNING: failed to configure server name indication (SNI) " + "TLS extension\n"); + } +#endif + + ossl_associate_connection(data, conn, sockindex); + + Curl_ssl_sessionid_lock(data); + if(!Curl_ssl_getsessionid(data, conn, SSL_IS_PROXY() ? TRUE : FALSE, + &ssl_sessionid, NULL, sockindex)) { + /* we got a session id, use it! */ + if(!SSL_set_session(backend->handle, ssl_sessionid)) { + Curl_ssl_sessionid_unlock(data); + failf(data, "SSL: SSL_set_session failed: %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer))); + return CURLE_SSL_CONNECT_ERROR; + } + /* Informational message */ + infof(data, "SSL re-using session ID\n"); + } + Curl_ssl_sessionid_unlock(data); + +#ifndef CURL_DISABLE_PROXY + if(conn->proxy_ssl[sockindex].use) { + BIO *const bio = BIO_new(BIO_f_ssl()); + SSL *handle = conn->proxy_ssl[sockindex].backend->handle; + DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state); + DEBUGASSERT(handle != NULL); + DEBUGASSERT(bio != NULL); + BIO_set_ssl(bio, handle, FALSE); + SSL_set_bio(backend->handle, bio, bio); + } + else +#endif + if(!SSL_set_fd(backend->handle, (int)sockfd)) { + /* pass the raw socket into the SSL layers */ + failf(data, "SSL: SSL_set_fd failed: %s", + ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer))); + return CURLE_SSL_CONNECT_ERROR; + } + + connssl->connecting_state = ssl_connect_2; + + return CURLE_OK; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22901-ossl_connect_step1/vuln.c b/benchmarks/pairs/vfc/curl-cve-2021-22901-ossl_connect_step1/vuln.c new file mode 100644 index 0000000..e539acc --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22901-ossl_connect_step1/vuln.c @@ -0,0 +1,729 @@ +/* Provenance: curl/curl ossl_connect_step1 (vuln). + * repo: curl/curl + * commit: 39ce47f219b09c380b81f89fe54ac586c8db6bde + * parent: 39ce47f219b09c380b81f89fe54ac586c8db6bde + * commit_url: https://github.com/curl/curl/commit/7f4a9a9b2a49547eae24d2e19bc5c346e9026479 + * cve: CVE-2021-22901 + * license: curl + * function: ossl_connect_step1 + * relpath: lib/vtls/openssl.c + */ + +static CURLcode ossl_connect_step1(struct Curl_easy *data, + struct connectdata *conn, int sockindex) +{ + CURLcode result = CURLE_OK; + char *ciphers; + SSL_METHOD_QUAL SSL_METHOD *req_method = NULL; + X509_LOOKUP *lookup = NULL; + curl_socket_t sockfd = conn->sock[sockindex]; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + ctx_option_t ctx_options = 0; + +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + bool sni; + const char * const hostname = SSL_HOST_NAME(); + +#ifdef ENABLE_IPV6 + struct in6_addr addr; +#else + struct in_addr addr; +#endif +#endif + const long int ssl_version = SSL_CONN_CONFIG(version); +#ifdef USE_OPENSSL_SRP + const enum CURL_TLSAUTH ssl_authtype = SSL_SET_OPTION(authtype); +#endif + char * const ssl_cert = SSL_SET_OPTION(primary.clientcert); + const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(primary.cert_blob); + const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_blob); + const char * const ssl_cert_type = SSL_SET_OPTION(cert_type); + const char * const ssl_cafile = + /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */ + (ca_info_blob ? NULL : SSL_CONN_CONFIG(CAfile)); + const char * const ssl_capath = SSL_CONN_CONFIG(CApath); + const bool verifypeer = SSL_CONN_CONFIG(verifypeer); + const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile); + char error_buffer[256]; + struct ssl_backend_data *backend = connssl->backend; + bool imported_native_ca = false; + + DEBUGASSERT(ssl_connect_1 == connssl->connecting_state); + + /* Make funny stuff to get random input */ + result = ossl_seed(data); + if(result) + return result; + + SSL_SET_OPTION_LVALUE(certverifyresult) = !X509_V_OK; + + /* check to see if we've been told to use an explicit SSL/TLS version */ + + switch(ssl_version) { + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + case CURL_SSLVERSION_TLSv1_0: + case CURL_SSLVERSION_TLSv1_1: + case CURL_SSLVERSION_TLSv1_2: + case CURL_SSLVERSION_TLSv1_3: + /* it will be handled later with the context options */ +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) + req_method = TLS_client_method(); +#else + req_method = SSLv23_client_method(); +#endif + use_sni(TRUE); + break; + case CURL_SSLVERSION_SSLv2: + failf(data, "No SSLv2 support"); + return CURLE_NOT_BUILT_IN; + case CURL_SSLVERSION_SSLv3: + failf(data, "No SSLv3 support"); + return CURLE_NOT_BUILT_IN; + default: + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; + } + + if(backend->ctx) + SSL_CTX_free(backend->ctx); + backend->ctx = SSL_CTX_new(req_method); + + if(!backend->ctx) { + failf(data, "SSL: couldn't create a context: %s", + ossl_strerror(ERR_peek_error(), error_buffer, sizeof(error_buffer))); + return CURLE_OUT_OF_MEMORY; + } + +#ifdef SSL_MODE_RELEASE_BUFFERS + SSL_CTX_set_mode(backend->ctx, SSL_MODE_RELEASE_BUFFERS); +#endif + +#ifdef SSL_CTRL_SET_MSG_CALLBACK + if(data->set.fdebug && data->set.verbose) { + /* the SSL trace callback is only used for verbose logging */ + SSL_CTX_set_msg_callback(backend->ctx, ossl_trace); + SSL_CTX_set_msg_callback_arg(backend->ctx, conn); + set_logger(conn, data); + } +#endif + + /* OpenSSL contains code to work-around lots of bugs and flaws in various + SSL-implementations. SSL_CTX_set_options() is used to enabled those + work-arounds. The man page for this option states that SSL_OP_ALL enables + all the work-arounds and that "It is usually safe to use SSL_OP_ALL to + enable the bug workaround options if compatibility with somewhat broken + implementations is desired." + + The "-no_ticket" option was introduced in Openssl0.9.8j. It's a flag to + disable "rfc4507bis session ticket support". rfc4507bis was later turned + into the proper RFC5077 it seems: https://tools.ietf.org/html/rfc5077 + + The enabled extension concerns the session management. I wonder how often + libcurl stops a connection and then resumes a TLS session. also, sending + the session data is some overhead. .I suggest that you just use your + proposed patch (which explicitly disables TICKET). + + If someone writes an application with libcurl and openssl who wants to + enable the feature, one can do this in the SSL callback. + + SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG option enabling allowed proper + interoperability with web server Netscape Enterprise Server 2.0.1 which + was released back in 1996. + + Due to CVE-2010-4180, option SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG has + become ineffective as of OpenSSL 0.9.8q and 1.0.0c. In order to mitigate + CVE-2010-4180 when using previous OpenSSL versions we no longer enable + this option regardless of OpenSSL version and SSL_OP_ALL definition. + + OpenSSL added a work-around for a SSL 3.0/TLS 1.0 CBC vulnerability + (https://www.openssl.org/~bodo/tls-cbc.txt). In 0.9.6e they added a bit to + SSL_OP_ALL that _disables_ that work-around despite the fact that + SSL_OP_ALL is documented to do "rather harmless" workarounds. In order to + keep the secure work-around, the SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS bit + must not be set. + */ + + ctx_options = SSL_OP_ALL; + +#ifdef SSL_OP_NO_TICKET + ctx_options |= SSL_OP_NO_TICKET; +#endif + +#ifdef SSL_OP_NO_COMPRESSION + ctx_options |= SSL_OP_NO_COMPRESSION; +#endif + +#ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG + /* mitigate CVE-2010-4180 */ + ctx_options &= ~SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG; +#endif + +#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS + /* unless the user explicitly ask to allow the protocol vulnerability we + use the work-around */ + if(!SSL_SET_OPTION(enable_beast)) + ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; +#endif + + switch(ssl_version) { + case CURL_SSLVERSION_SSLv2: + case CURL_SSLVERSION_SSLv3: + return CURLE_NOT_BUILT_IN; + + /* "--tlsv" options mean TLS >= version */ + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: /* TLS >= version 1.0 */ + case CURL_SSLVERSION_TLSv1_0: /* TLS >= version 1.0 */ + case CURL_SSLVERSION_TLSv1_1: /* TLS >= version 1.1 */ + case CURL_SSLVERSION_TLSv1_2: /* TLS >= version 1.2 */ + case CURL_SSLVERSION_TLSv1_3: /* TLS >= version 1.3 */ + /* asking for any TLS version as the minimum, means no SSL versions + allowed */ + ctx_options |= SSL_OP_NO_SSLv2; + ctx_options |= SSL_OP_NO_SSLv3; + +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) /* 1.1.0 */ + result = set_ssl_version_min_max(backend->ctx, conn); +#else + result = set_ssl_version_min_max_legacy(&ctx_options, data, conn, + sockindex); +#endif + if(result != CURLE_OK) + return result; + break; + + default: + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; + } + + SSL_CTX_set_options(backend->ctx, ctx_options); + +#ifdef HAS_NPN + if(conn->bits.tls_enable_npn) + SSL_CTX_set_next_proto_select_cb(backend->ctx, select_next_proto_cb, data); +#endif + +#ifdef HAS_ALPN + if(conn->bits.tls_enable_alpn) { + int cur = 0; + unsigned char protocols[128]; + +#ifdef USE_HTTP2 + if(data->state.httpwant >= CURL_HTTP_VERSION_2 +#ifndef CURL_DISABLE_PROXY + && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy) +#endif + ) { + protocols[cur++] = ALPN_H2_LENGTH; + + memcpy(&protocols[cur], ALPN_H2, ALPN_H2_LENGTH); + cur += ALPN_H2_LENGTH; + infof(data, "ALPN, offering %s\n", ALPN_H2); + } +#endif + + protocols[cur++] = ALPN_HTTP_1_1_LENGTH; + memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); + cur += ALPN_HTTP_1_1_LENGTH; + infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); + + /* expects length prefixed preference ordered list of protocols in wire + * format + */ + if(SSL_CTX_set_alpn_protos(backend->ctx, protocols, cur)) { + failf(data, "Error setting ALPN"); + return CURLE_SSL_CONNECT_ERROR; + } + } +#endif + + if(ssl_cert || ssl_cert_blob || ssl_cert_type) { + if(!result && + !cert_stuff(data, backend->ctx, + ssl_cert, ssl_cert_blob, ssl_cert_type, + SSL_SET_OPTION(key), SSL_SET_OPTION(key_blob), + SSL_SET_OPTION(key_type), SSL_SET_OPTION(key_passwd))) + result = CURLE_SSL_CERTPROBLEM; + if(result) + /* failf() is already done in cert_stuff() */ + return result; + } + + ciphers = SSL_CONN_CONFIG(cipher_list); + if(!ciphers) + ciphers = (char *)DEFAULT_CIPHER_SELECTION; + if(ciphers) { + if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) { + failf(data, "failed setting cipher list: %s", ciphers); + return CURLE_SSL_CIPHER; + } + infof(data, "Cipher selection: %s\n", ciphers); + } + +#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES + { + char *ciphers13 = SSL_CONN_CONFIG(cipher_list13); + if(ciphers13) { + if(!SSL_CTX_set_ciphersuites(backend->ctx, ciphers13)) { + failf(data, "failed setting TLS 1.3 cipher suite: %s", ciphers13); + return CURLE_SSL_CIPHER; + } + infof(data, "TLS 1.3 cipher selection: %s\n", ciphers13); + } + } +#endif + +#ifdef HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH + /* OpenSSL 1.1.1 requires clients to opt-in for PHA */ + SSL_CTX_set_post_handshake_auth(backend->ctx, 1); +#endif + +#ifdef HAVE_SSL_CTX_SET_EC_CURVES + { + char *curves = SSL_CONN_CONFIG(curves); + if(curves) { + if(!SSL_CTX_set1_curves_list(backend->ctx, curves)) { + failf(data, "failed setting curves list: '%s'", curves); + return CURLE_SSL_CIPHER; + } + } + } +#endif + +#ifdef USE_OPENSSL_SRP + if(ssl_authtype == CURL_TLSAUTH_SRP) { + char * const ssl_username = SSL_SET_OPTION(username); + + infof(data, "Using TLS-SRP username: %s\n", ssl_username); + + if(!SSL_CTX_set_srp_username(backend->ctx, ssl_username)) { + failf(data, "Unable to set SRP user name"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + if(!SSL_CTX_set_srp_password(backend->ctx, SSL_SET_OPTION(password))) { + failf(data, "failed setting SRP password"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + if(!SSL_CONN_CONFIG(cipher_list)) { + infof(data, "Setting cipher list SRP\n"); + + if(!SSL_CTX_set_cipher_list(backend->ctx, "SRP")) { + failf(data, "failed setting SRP cipher list"); + return CURLE_SSL_CIPHER; + } + } + } +#endif + + +#if defined(USE_WIN32_CRYPTO) + /* Import certificates from the Windows root certificate store if requested. + https://stackoverflow.com/questions/9507184/ + https://github.com/d3x0r/SACK/blob/master/src/netlib/ssl_layer.c#L1037 + https://tools.ietf.org/html/rfc5280 */ + if((SSL_CONN_CONFIG(verifypeer) || SSL_CONN_CONFIG(verifyhost)) && + (SSL_SET_OPTION(native_ca_store))) { + X509_STORE *store = SSL_CTX_get_cert_store(backend->ctx); + HCERTSTORE hStore = CertOpenSystemStore(0, TEXT("ROOT")); + + if(hStore) { + PCCERT_CONTEXT pContext = NULL; + /* The array of enhanced key usage OIDs will vary per certificate and is + declared outside of the loop so that rather than malloc/free each + iteration we can grow it with realloc, when necessary. */ + CERT_ENHKEY_USAGE *enhkey_usage = NULL; + DWORD enhkey_usage_size = 0; + + /* This loop makes a best effort to import all valid certificates from + the MS root store. If a certificate cannot be imported it is skipped. + 'result' is used to store only hard-fail conditions (such as out of + memory) that cause an early break. */ + result = CURLE_OK; + for(;;) { + X509 *x509; + FILETIME now; + BYTE key_usage[2]; + DWORD req_size; + const unsigned char *encoded_cert; +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + char cert_name[256]; +#endif + + pContext = CertEnumCertificatesInStore(hStore, pContext); + if(!pContext) + break; + +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + if(!CertGetNameStringA(pContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, + NULL, cert_name, sizeof(cert_name))) { + strcpy(cert_name, "Unknown"); + } + infof(data, "SSL: Checking cert \"%s\"\n", cert_name); +#endif + + encoded_cert = (const unsigned char *)pContext->pbCertEncoded; + if(!encoded_cert) + continue; + + GetSystemTimeAsFileTime(&now); + if(CompareFileTime(&pContext->pCertInfo->NotBefore, &now) > 0 || + CompareFileTime(&now, &pContext->pCertInfo->NotAfter) > 0) + continue; + + /* If key usage exists check for signing attribute */ + if(CertGetIntendedKeyUsage(pContext->dwCertEncodingType, + pContext->pCertInfo, + key_usage, sizeof(key_usage))) { + if(!(key_usage[0] & CERT_KEY_CERT_SIGN_KEY_USAGE)) + continue; + } + else if(GetLastError()) + continue; + + /* If enhanced key usage exists check for server auth attribute. + * + * Note "In a Microsoft environment, a certificate might also have EKU + * extended properties that specify valid uses for the certificate." + * The call below checks both, and behavior varies depending on what is + * found. For more details see CertGetEnhancedKeyUsage doc. + */ + if(CertGetEnhancedKeyUsage(pContext, 0, NULL, &req_size)) { + if(req_size && req_size > enhkey_usage_size) { + void *tmp = realloc(enhkey_usage, req_size); + + if(!tmp) { + failf(data, "SSL: Out of memory allocating for OID list"); + result = CURLE_OUT_OF_MEMORY; + break; + } + + enhkey_usage = (CERT_ENHKEY_USAGE *)tmp; + enhkey_usage_size = req_size; + } + + if(CertGetEnhancedKeyUsage(pContext, 0, enhkey_usage, &req_size)) { + if(!enhkey_usage->cUsageIdentifier) { + /* "If GetLastError returns CRYPT_E_NOT_FOUND, the certificate is + good for all uses. If it returns zero, the certificate has no + valid uses." */ + if((HRESULT)GetLastError() != CRYPT_E_NOT_FOUND) + continue; + } + else { + DWORD i; + bool found = false; + + for(i = 0; i < enhkey_usage->cUsageIdentifier; ++i) { + if(!strcmp("1.3.6.1.5.5.7.3.1" /* OID server auth */, + enhkey_usage->rgpszUsageIdentifier[i])) { + found = true; + break; + } + } + + if(!found) + continue; + } + } + else + continue; + } + else + continue; + + x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded); + if(!x509) + continue; + + /* Try to import the certificate. This may fail for legitimate reasons + such as duplicate certificate, which is allowed by MS but not + OpenSSL. */ + if(X509_STORE_add_cert(store, x509) == 1) { +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + infof(data, "SSL: Imported cert \"%s\"\n", cert_name); +#endif + imported_native_ca = true; + } + X509_free(x509); + } + + free(enhkey_usage); + CertFreeCertificateContext(pContext); + CertCloseStore(hStore, 0); + + if(result) + return result; + } + if(imported_native_ca) + infof(data, "successfully imported windows ca store\n"); + else + infof(data, "error importing windows ca store, continuing anyway\n"); + } +#endif + + if(ca_info_blob) { + result = load_cacert_from_memory(backend->ctx, ca_info_blob); + if(result) { + if(result == CURLE_OUT_OF_MEMORY || + (verifypeer && !imported_native_ca)) { + failf(data, "error importing CA certificate blob"); + return result; + } + /* Only warning if no certificate verification is required. */ + infof(data, "error importing CA certificate blob, continuing anyway\n"); + } + } + +#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) + /* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */ + { + if(ssl_cafile) { + if(!SSL_CTX_load_verify_file(backend->ctx, ssl_cafile)) { + if(verifypeer && !imported_native_ca) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate file: %s", ssl_cafile); + return CURLE_SSL_CACERT_BADFILE; + } + /* Continue with a warning if no certificate verif is required. */ + infof(data, "error setting certificate file, continuing anyway\n"); + } + infof(data, " CAfile: %s\n", ssl_cafile); + } + if(ssl_capath) { + if(!SSL_CTX_load_verify_dir(backend->ctx, ssl_capath)) { + if(verifypeer && !imported_native_ca) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate path: %s", ssl_capath); + return CURLE_SSL_CACERT_BADFILE; + } + /* Continue with a warning if no certificate verif is required. */ + infof(data, "error setting certificate path, continuing anyway\n"); + } + infof(data, " CApath: %s\n", ssl_capath); + } + } +#else + if(ssl_cafile || ssl_capath) { + /* tell SSL where to find CA certificates that are used to verify + the servers certificate. */ + if(!SSL_CTX_load_verify_locations(backend->ctx, ssl_cafile, ssl_capath)) { + if(verifypeer && !imported_native_ca) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate verify locations:" + " CAfile: %s CApath: %s", + ssl_cafile ? ssl_cafile : "none", + ssl_capath ? ssl_capath : "none"); + return CURLE_SSL_CACERT_BADFILE; + } + /* Just continue with a warning if no strict certificate verification + is required. */ + infof(data, "error setting certificate verify locations," + " continuing anyway:\n"); + } + else { + /* Everything is fine. */ + infof(data, "successfully set certificate verify locations:\n"); + } + infof(data, " CAfile: %s\n", ssl_cafile ? ssl_cafile : "none"); + infof(data, " CApath: %s\n", ssl_capath ? ssl_capath : "none"); + } +#endif + +#ifdef CURL_CA_FALLBACK + if(verifypeer && + !ca_info_blob && !ssl_cafile && !ssl_capath && !imported_native_ca) { + /* verifying the peer without any CA certificates won't + work so use openssl's built in default as fallback */ + SSL_CTX_set_default_verify_paths(backend->ctx); + } +#endif + + if(ssl_crlfile) { + /* tell SSL where to find CRL file that is used to check certificate + * revocation */ + lookup = X509_STORE_add_lookup(SSL_CTX_get_cert_store(backend->ctx), + X509_LOOKUP_file()); + if(!lookup || + (!X509_load_crl_file(lookup, ssl_crlfile, X509_FILETYPE_PEM)) ) { + failf(data, "error loading CRL file: %s", ssl_crlfile); + return CURLE_SSL_CRL_BADFILE; + } + /* Everything is fine. */ + infof(data, "successfully load CRL file:\n"); + X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx), + X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); + + infof(data, " CRLfile: %s\n", ssl_crlfile); + } + + if(verifypeer) { + /* Try building a chain using issuers in the trusted store first to avoid + problems with server-sent legacy intermediates. Newer versions of + OpenSSL do alternate chain checking by default but we do not know how to + determine that in a reliable manner. + https://rt.openssl.org/Ticket/Display.html?id=3621&user=guest&pass=guest + */ +#if defined(X509_V_FLAG_TRUSTED_FIRST) + X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx), + X509_V_FLAG_TRUSTED_FIRST); +#endif +#ifdef X509_V_FLAG_PARTIAL_CHAIN + if(!SSL_SET_OPTION(no_partialchain) && !ssl_crlfile) { + /* Have intermediate certificates in the trust store be treated as + trust-anchors, in the same way as self-signed root CA certificates + are. This allows users to verify servers using the intermediate cert + only, instead of needing the whole chain. + + Due to OpenSSL bug https://github.com/openssl/openssl/issues/5081 we + cannot do partial chains with CRL check. + */ + X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx), + X509_V_FLAG_PARTIAL_CHAIN); + } +#endif + } + + /* SSL always tries to verify the peer, this only says whether it should + * fail to connect if the verification fails, or if it should continue + * anyway. In the latter case the result of the verification is checked with + * SSL_get_verify_result() below. */ + SSL_CTX_set_verify(backend->ctx, + verifypeer ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL); + + /* Enable logging of secrets to the file specified in env SSLKEYLOGFILE. */ +#ifdef HAVE_KEYLOG_CALLBACK + if(Curl_tls_keylog_enabled()) { + SSL_CTX_set_keylog_callback(backend->ctx, ossl_keylog_callback); + } +#endif + + /* Enable the session cache because it's a prerequisite for the "new session" + * callback. Use the "external storage" mode to avoid that OpenSSL creates + * an internal session cache. + */ + SSL_CTX_set_session_cache_mode(backend->ctx, + SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL); + SSL_CTX_sess_set_new_cb(backend->ctx, ossl_new_session_cb); + + /* give application a chance to interfere with SSL set up. */ + if(data->set.ssl.fsslctx) { + Curl_set_in_callback(data, true); + result = (*data->set.ssl.fsslctx)(data, backend->ctx, + data->set.ssl.fsslctxp); + Curl_set_in_callback(data, false); + if(result) { + failf(data, "error signaled by ssl ctx callback"); + return result; + } + } + + /* Lets make an SSL structure */ + if(backend->handle) + SSL_free(backend->handle); + backend->handle = SSL_new(backend->ctx); + if(!backend->handle) { + failf(data, "SSL: couldn't create a context (handle)!"); + return CURLE_OUT_OF_MEMORY; + } + +#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ + !defined(OPENSSL_NO_OCSP) + if(SSL_CONN_CONFIG(verifystatus)) + SSL_set_tlsext_status_type(backend->handle, TLSEXT_STATUSTYPE_ocsp); +#endif + +#if defined(OPENSSL_IS_BORINGSSL) && defined(ALLOW_RENEG) + SSL_set_renegotiate_mode(backend->handle, ssl_renegotiate_freely); +#endif + + SSL_set_connect_state(backend->handle); + + backend->server_cert = 0x0; +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) && +#ifdef ENABLE_IPV6 + (0 == Curl_inet_pton(AF_INET6, hostname, &addr)) && +#endif + sni) { + size_t nlen = strlen(hostname); + if((long)nlen >= data->set.buffer_size) + /* this is seriously messed up */ + return CURLE_SSL_CONNECT_ERROR; + + /* RFC 6066 section 3 says the SNI field is case insensitive, but browsers + send the data lowercase and subsequently there are now numerous servers + out there that don't work unless the name is lowercased */ + Curl_strntolower(data->state.buffer, hostname, nlen); + data->state.buffer[nlen] = 0; + if(!SSL_set_tlsext_host_name(backend->handle, data->state.buffer)) + infof(data, "WARNING: failed to configure server name indication (SNI) " + "TLS extension\n"); + } +#endif + + /* Check if there's a cached ID we can/should use here! */ + if(SSL_SET_OPTION(primary.sessionid)) { + void *ssl_sessionid = NULL; + int data_idx = ossl_get_ssl_data_index(); + int connectdata_idx = ossl_get_ssl_conn_index(); + int sockindex_idx = ossl_get_ssl_sockindex_index(); + int proxy_idx = ossl_get_proxy_index(); + + if(data_idx >= 0 && connectdata_idx >= 0 && sockindex_idx >= 0 && + proxy_idx >= 0) { + /* Store the data needed for the "new session" callback. + * The sockindex is stored as a pointer to an array element. */ + SSL_set_ex_data(backend->handle, data_idx, data); + SSL_set_ex_data(backend->handle, connectdata_idx, conn); + SSL_set_ex_data(backend->handle, sockindex_idx, conn->sock + sockindex); +#ifndef CURL_DISABLE_PROXY + SSL_set_ex_data(backend->handle, proxy_idx, SSL_IS_PROXY() ? (void *) 1: + NULL); +#else + SSL_set_ex_data(backend->handle, proxy_idx, NULL); +#endif + + } + + Curl_ssl_sessionid_lock(data); + if(!Curl_ssl_getsessionid(data, conn, SSL_IS_PROXY() ? TRUE : FALSE, + &ssl_sessionid, NULL, sockindex)) { + /* we got a session id, use it! */ + if(!SSL_set_session(backend->handle, ssl_sessionid)) { + Curl_ssl_sessionid_unlock(data); + failf(data, "SSL: SSL_set_session failed: %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer))); + return CURLE_SSL_CONNECT_ERROR; + } + /* Informational message */ + infof(data, "SSL re-using session ID\n"); + } + Curl_ssl_sessionid_unlock(data); + } + +#ifndef CURL_DISABLE_PROXY + if(conn->proxy_ssl[sockindex].use) { + BIO *const bio = BIO_new(BIO_f_ssl()); + SSL *handle = conn->proxy_ssl[sockindex].backend->handle; + DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state); + DEBUGASSERT(handle != NULL); + DEBUGASSERT(bio != NULL); + BIO_set_ssl(bio, handle, FALSE); + SSL_set_bio(backend->handle, bio, bio); + } + else +#endif + if(!SSL_set_fd(backend->handle, (int)sockfd)) { + /* pass the raw socket into the SSL layers */ + failf(data, "SSL: SSL_set_fd failed: %s", + ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer))); + return CURLE_SSL_CONNECT_ERROR; + } + + connssl->connecting_state = ssl_connect_2; + + return CURLE_OK; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22924-nss_do_connect/fixed.c b/benchmarks/pairs/vfc/curl-cve-2021-22924-nss_do_connect/fixed.c new file mode 100644 index 0000000..e33477c --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22924-nss_do_connect/fixed.c @@ -0,0 +1,73 @@ +/* Provenance: curl/curl nss_do_connect (fixed). + * repo: curl/curl + * commit: 5ea3145850ebff1dc2b13d17440300a01ca38161 + * parent: fd9b40bf8dfd43edcbc0d254d613d95a11061c05 + * commit_url: https://github.com/curl/curl/commit/5ea3145850ebff1dc2b13d17440300a01ca38161 + * cve: CVE-2021-22924 + * license: curl + * function: nss_do_connect + * relpath: lib/vtls/nss.c + */ + +static CURLcode nss_do_connect(struct Curl_easy *data, + struct connectdata *conn, int sockindex) +{ + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; + CURLcode result = CURLE_SSL_CONNECT_ERROR; + PRUint32 timeout; + + /* check timeout situation */ + const timediff_t time_left = Curl_timeleft(data, NULL, TRUE); + if(time_left < 0) { + failf(data, "timed out before SSL handshake"); + result = CURLE_OPERATION_TIMEDOUT; + goto error; + } + + /* Force the handshake now */ + timeout = PR_MillisecondsToInterval((PRUint32) time_left); + if(SSL_ForceHandshakeWithTimeout(backend->handle, timeout) != SECSuccess) { + if(PR_GetError() == PR_WOULD_BLOCK_ERROR) + /* blocking direction is updated by nss_update_connecting_state() */ + return CURLE_AGAIN; + else if(SSL_SET_OPTION(certverifyresult) == SSL_ERROR_BAD_CERT_DOMAIN) + result = CURLE_PEER_FAILED_VERIFICATION; + else if(SSL_SET_OPTION(certverifyresult) != 0) + result = CURLE_PEER_FAILED_VERIFICATION; + goto error; + } + + result = display_conn_info(data, backend->handle); + if(result) + goto error; + + if(SSL_CONN_CONFIG(issuercert)) { + SECStatus ret = SECFailure; + char *nickname = dup_nickname(data, SSL_CONN_CONFIG(issuercert)); + if(nickname) { + /* we support only nicknames in case of issuercert for now */ + ret = check_issuer_cert(backend->handle, nickname); + free(nickname); + } + + if(SECFailure == ret) { + infof(data, "SSL certificate issuer check failed"); + result = CURLE_SSL_ISSUER_ERROR; + goto error; + } + else { + infof(data, "SSL certificate issuer check ok"); + } + } + + result = cmp_peer_pubkey(connssl, SSL_PINNED_PUB_KEY()); + if(result) + /* status already printed */ + goto error; + + return CURLE_OK; + +error: + return nss_fail_connect(connssl, data, result); +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22924-nss_do_connect/vuln.c b/benchmarks/pairs/vfc/curl-cve-2021-22924-nss_do_connect/vuln.c new file mode 100644 index 0000000..c053373 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22924-nss_do_connect/vuln.c @@ -0,0 +1,73 @@ +/* Provenance: curl/curl nss_do_connect (vuln). + * repo: curl/curl + * commit: fd9b40bf8dfd43edcbc0d254d613d95a11061c05 + * parent: fd9b40bf8dfd43edcbc0d254d613d95a11061c05 + * commit_url: https://github.com/curl/curl/commit/5ea3145850ebff1dc2b13d17440300a01ca38161 + * cve: CVE-2021-22924 + * license: curl + * function: nss_do_connect + * relpath: lib/vtls/nss.c + */ + +static CURLcode nss_do_connect(struct Curl_easy *data, + struct connectdata *conn, int sockindex) +{ + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; + CURLcode result = CURLE_SSL_CONNECT_ERROR; + PRUint32 timeout; + + /* check timeout situation */ + const timediff_t time_left = Curl_timeleft(data, NULL, TRUE); + if(time_left < 0) { + failf(data, "timed out before SSL handshake"); + result = CURLE_OPERATION_TIMEDOUT; + goto error; + } + + /* Force the handshake now */ + timeout = PR_MillisecondsToInterval((PRUint32) time_left); + if(SSL_ForceHandshakeWithTimeout(backend->handle, timeout) != SECSuccess) { + if(PR_GetError() == PR_WOULD_BLOCK_ERROR) + /* blocking direction is updated by nss_update_connecting_state() */ + return CURLE_AGAIN; + else if(SSL_SET_OPTION(certverifyresult) == SSL_ERROR_BAD_CERT_DOMAIN) + result = CURLE_PEER_FAILED_VERIFICATION; + else if(SSL_SET_OPTION(certverifyresult) != 0) + result = CURLE_PEER_FAILED_VERIFICATION; + goto error; + } + + result = display_conn_info(data, backend->handle); + if(result) + goto error; + + if(SSL_SET_OPTION(issuercert)) { + SECStatus ret = SECFailure; + char *nickname = dup_nickname(data, SSL_SET_OPTION(issuercert)); + if(nickname) { + /* we support only nicknames in case of issuercert for now */ + ret = check_issuer_cert(backend->handle, nickname); + free(nickname); + } + + if(SECFailure == ret) { + infof(data, "SSL certificate issuer check failed"); + result = CURLE_SSL_ISSUER_ERROR; + goto error; + } + else { + infof(data, "SSL certificate issuer check ok"); + } + } + + result = cmp_peer_pubkey(connssl, SSL_PINNED_PUB_KEY()); + if(result) + /* status already printed */ + goto error; + + return CURLE_OK; + +error: + return nss_fail_connect(connssl, data, result); +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22924-servercert/fixed.c b/benchmarks/pairs/vfc/curl-cve-2021-22924-servercert/fixed.c new file mode 100644 index 0000000..8c4ac3e --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22924-servercert/fixed.c @@ -0,0 +1,193 @@ +/* Provenance: curl/curl servercert (fixed). + * repo: curl/curl + * commit: 5ea3145850ebff1dc2b13d17440300a01ca38161 + * parent: fd9b40bf8dfd43edcbc0d254d613d95a11061c05 + * commit_url: https://github.com/curl/curl/commit/5ea3145850ebff1dc2b13d17440300a01ca38161 + * cve: CVE-2021-22924 + * license: curl + * function: servercert + * relpath: lib/vtls/openssl.c + */ + +static CURLcode servercert(struct Curl_easy *data, + struct connectdata *conn, + struct ssl_connect_data *connssl, + bool strict) +{ + CURLcode result = CURLE_OK; + int rc; + long lerr; + X509 *issuer; + BIO *fp = NULL; + char error_buffer[256]=""; + char buffer[2048]; + const char *ptr; + BIO *mem = BIO_new(BIO_s_mem()); + struct ssl_backend_data *backend = connssl->backend; + + if(data->set.ssl.certinfo) + /* we've been asked to gather certificate info! */ + (void)get_cert_chain(data, connssl); + + backend->server_cert = SSL_get_peer_certificate(backend->handle); + if(!backend->server_cert) { + BIO_free(mem); + if(!strict) + return CURLE_OK; + + failf(data, "SSL: couldn't get peer certificate!"); + return CURLE_PEER_FAILED_VERIFICATION; + } + + infof(data, "%s certificate:", SSL_IS_PROXY() ? "Proxy" : "Server"); + + rc = x509_name_oneline(X509_get_subject_name(backend->server_cert), + buffer, sizeof(buffer)); + infof(data, " subject: %s", rc?"[NONE]":buffer); + +#ifndef CURL_DISABLE_VERBOSE_STRINGS + { + long len; + ASN1_TIME_print(mem, X509_get0_notBefore(backend->server_cert)); + len = BIO_get_mem_data(mem, (char **) &ptr); + infof(data, " start date: %.*s", (int)len, ptr); + (void)BIO_reset(mem); + + ASN1_TIME_print(mem, X509_get0_notAfter(backend->server_cert)); + len = BIO_get_mem_data(mem, (char **) &ptr); + infof(data, " expire date: %.*s", (int)len, ptr); + (void)BIO_reset(mem); + } +#endif + + BIO_free(mem); + + if(SSL_CONN_CONFIG(verifyhost)) { + result = verifyhost(data, conn, backend->server_cert); + if(result) { + X509_free(backend->server_cert); + backend->server_cert = NULL; + return result; + } + } + + rc = x509_name_oneline(X509_get_issuer_name(backend->server_cert), + buffer, sizeof(buffer)); + if(rc) { + if(strict) + failf(data, "SSL: couldn't get X509-issuer name!"); + result = CURLE_PEER_FAILED_VERIFICATION; + } + else { + infof(data, " issuer: %s", buffer); + + /* We could do all sorts of certificate verification stuff here before + deallocating the certificate. */ + + /* e.g. match issuer name with provided issuer certificate */ + if(SSL_CONN_CONFIG(issuercert) || SSL_CONN_CONFIG(issuercert_blob)) { + if(SSL_CONN_CONFIG(issuercert_blob)) + fp = BIO_new_mem_buf(SSL_CONN_CONFIG(issuercert_blob)->data, + (int)SSL_CONN_CONFIG(issuercert_blob)->len); + else { + fp = BIO_new(BIO_s_file()); + if(!fp) { + failf(data, + "BIO_new return NULL, " OSSL_PACKAGE + " error %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer)) ); + X509_free(backend->server_cert); + backend->server_cert = NULL; + return CURLE_OUT_OF_MEMORY; + } + + if(BIO_read_filename(fp, SSL_CONN_CONFIG(issuercert)) <= 0) { + if(strict) + failf(data, "SSL: Unable to open issuer cert (%s)", + SSL_CONN_CONFIG(issuercert)); + BIO_free(fp); + X509_free(backend->server_cert); + backend->server_cert = NULL; + return CURLE_SSL_ISSUER_ERROR; + } + } + + issuer = PEM_read_bio_X509(fp, NULL, ZERO_NULL, NULL); + if(!issuer) { + if(strict) + failf(data, "SSL: Unable to read issuer cert (%s)", + SSL_CONN_CONFIG(issuercert)); + BIO_free(fp); + X509_free(issuer); + X509_free(backend->server_cert); + backend->server_cert = NULL; + return CURLE_SSL_ISSUER_ERROR; + } + + if(X509_check_issued(issuer, backend->server_cert) != X509_V_OK) { + if(strict) + failf(data, "SSL: Certificate issuer check failed (%s)", + SSL_CONN_CONFIG(issuercert)); + BIO_free(fp); + X509_free(issuer); + X509_free(backend->server_cert); + backend->server_cert = NULL; + return CURLE_SSL_ISSUER_ERROR; + } + + infof(data, " SSL certificate issuer check ok (%s)", + SSL_CONN_CONFIG(issuercert)); + BIO_free(fp); + X509_free(issuer); + } + + lerr = SSL_get_verify_result(backend->handle); + SSL_SET_OPTION_LVALUE(certverifyresult) = lerr; + if(lerr != X509_V_OK) { + if(SSL_CONN_CONFIG(verifypeer)) { + /* We probably never reach this, because SSL_connect() will fail + and we return earlier if verifypeer is set? */ + if(strict) + failf(data, "SSL certificate verify result: %s (%ld)", + X509_verify_cert_error_string(lerr), lerr); + result = CURLE_PEER_FAILED_VERIFICATION; + } + else + infof(data, " SSL certificate verify result: %s (%ld)," + " continuing anyway.", + X509_verify_cert_error_string(lerr), lerr); + } + else + infof(data, " SSL certificate verify ok."); + } + +#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ + !defined(OPENSSL_NO_OCSP) + if(SSL_CONN_CONFIG(verifystatus)) { + result = verifystatus(data, connssl); + if(result) { + X509_free(backend->server_cert); + backend->server_cert = NULL; + return result; + } + } +#endif + + if(!strict) + /* when not strict, we don't bother about the verify cert problems */ + result = CURLE_OK; + + ptr = SSL_PINNED_PUB_KEY(); + if(!result && ptr) { + result = pkp_pin_peer_pubkey(data, backend->server_cert, ptr); + if(result) + failf(data, "SSL: public key does not match pinned public key!"); + } + + X509_free(backend->server_cert); + backend->server_cert = NULL; + connssl->connecting_state = ssl_connect_done; + + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22924-servercert/vuln.c b/benchmarks/pairs/vfc/curl-cve-2021-22924-servercert/vuln.c new file mode 100644 index 0000000..b1eb60b --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22924-servercert/vuln.c @@ -0,0 +1,193 @@ +/* Provenance: curl/curl servercert (vuln). + * repo: curl/curl + * commit: fd9b40bf8dfd43edcbc0d254d613d95a11061c05 + * parent: fd9b40bf8dfd43edcbc0d254d613d95a11061c05 + * commit_url: https://github.com/curl/curl/commit/5ea3145850ebff1dc2b13d17440300a01ca38161 + * cve: CVE-2021-22924 + * license: curl + * function: servercert + * relpath: lib/vtls/openssl.c + */ + +static CURLcode servercert(struct Curl_easy *data, + struct connectdata *conn, + struct ssl_connect_data *connssl, + bool strict) +{ + CURLcode result = CURLE_OK; + int rc; + long lerr; + X509 *issuer; + BIO *fp = NULL; + char error_buffer[256]=""; + char buffer[2048]; + const char *ptr; + BIO *mem = BIO_new(BIO_s_mem()); + struct ssl_backend_data *backend = connssl->backend; + + if(data->set.ssl.certinfo) + /* we've been asked to gather certificate info! */ + (void)get_cert_chain(data, connssl); + + backend->server_cert = SSL_get_peer_certificate(backend->handle); + if(!backend->server_cert) { + BIO_free(mem); + if(!strict) + return CURLE_OK; + + failf(data, "SSL: couldn't get peer certificate!"); + return CURLE_PEER_FAILED_VERIFICATION; + } + + infof(data, "%s certificate:", SSL_IS_PROXY() ? "Proxy" : "Server"); + + rc = x509_name_oneline(X509_get_subject_name(backend->server_cert), + buffer, sizeof(buffer)); + infof(data, " subject: %s", rc?"[NONE]":buffer); + +#ifndef CURL_DISABLE_VERBOSE_STRINGS + { + long len; + ASN1_TIME_print(mem, X509_get0_notBefore(backend->server_cert)); + len = BIO_get_mem_data(mem, (char **) &ptr); + infof(data, " start date: %.*s", (int)len, ptr); + (void)BIO_reset(mem); + + ASN1_TIME_print(mem, X509_get0_notAfter(backend->server_cert)); + len = BIO_get_mem_data(mem, (char **) &ptr); + infof(data, " expire date: %.*s", (int)len, ptr); + (void)BIO_reset(mem); + } +#endif + + BIO_free(mem); + + if(SSL_CONN_CONFIG(verifyhost)) { + result = verifyhost(data, conn, backend->server_cert); + if(result) { + X509_free(backend->server_cert); + backend->server_cert = NULL; + return result; + } + } + + rc = x509_name_oneline(X509_get_issuer_name(backend->server_cert), + buffer, sizeof(buffer)); + if(rc) { + if(strict) + failf(data, "SSL: couldn't get X509-issuer name!"); + result = CURLE_PEER_FAILED_VERIFICATION; + } + else { + infof(data, " issuer: %s", buffer); + + /* We could do all sorts of certificate verification stuff here before + deallocating the certificate. */ + + /* e.g. match issuer name with provided issuer certificate */ + if(SSL_SET_OPTION(issuercert) || SSL_SET_OPTION(issuercert_blob)) { + if(SSL_SET_OPTION(issuercert_blob)) + fp = BIO_new_mem_buf(SSL_SET_OPTION(issuercert_blob)->data, + (int)SSL_SET_OPTION(issuercert_blob)->len); + else { + fp = BIO_new(BIO_s_file()); + if(!fp) { + failf(data, + "BIO_new return NULL, " OSSL_PACKAGE + " error %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer)) ); + X509_free(backend->server_cert); + backend->server_cert = NULL; + return CURLE_OUT_OF_MEMORY; + } + + if(BIO_read_filename(fp, SSL_SET_OPTION(issuercert)) <= 0) { + if(strict) + failf(data, "SSL: Unable to open issuer cert (%s)", + SSL_SET_OPTION(issuercert)); + BIO_free(fp); + X509_free(backend->server_cert); + backend->server_cert = NULL; + return CURLE_SSL_ISSUER_ERROR; + } + } + + issuer = PEM_read_bio_X509(fp, NULL, ZERO_NULL, NULL); + if(!issuer) { + if(strict) + failf(data, "SSL: Unable to read issuer cert (%s)", + SSL_SET_OPTION(issuercert)); + BIO_free(fp); + X509_free(issuer); + X509_free(backend->server_cert); + backend->server_cert = NULL; + return CURLE_SSL_ISSUER_ERROR; + } + + if(X509_check_issued(issuer, backend->server_cert) != X509_V_OK) { + if(strict) + failf(data, "SSL: Certificate issuer check failed (%s)", + SSL_SET_OPTION(issuercert)); + BIO_free(fp); + X509_free(issuer); + X509_free(backend->server_cert); + backend->server_cert = NULL; + return CURLE_SSL_ISSUER_ERROR; + } + + infof(data, " SSL certificate issuer check ok (%s)", + SSL_SET_OPTION(issuercert)); + BIO_free(fp); + X509_free(issuer); + } + + lerr = SSL_get_verify_result(backend->handle); + SSL_SET_OPTION_LVALUE(certverifyresult) = lerr; + if(lerr != X509_V_OK) { + if(SSL_CONN_CONFIG(verifypeer)) { + /* We probably never reach this, because SSL_connect() will fail + and we return earlier if verifypeer is set? */ + if(strict) + failf(data, "SSL certificate verify result: %s (%ld)", + X509_verify_cert_error_string(lerr), lerr); + result = CURLE_PEER_FAILED_VERIFICATION; + } + else + infof(data, " SSL certificate verify result: %s (%ld)," + " continuing anyway.", + X509_verify_cert_error_string(lerr), lerr); + } + else + infof(data, " SSL certificate verify ok."); + } + +#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ + !defined(OPENSSL_NO_OCSP) + if(SSL_CONN_CONFIG(verifystatus)) { + result = verifystatus(data, connssl); + if(result) { + X509_free(backend->server_cert); + backend->server_cert = NULL; + return result; + } + } +#endif + + if(!strict) + /* when not strict, we don't bother about the verify cert problems */ + result = CURLE_OK; + + ptr = SSL_PINNED_PUB_KEY(); + if(!result && ptr) { + result = pkp_pin_peer_pubkey(data, backend->server_cert, ptr); + if(result) + failf(data, "SSL: public key does not match pinned public key!"); + } + + X509_free(backend->server_cert); + backend->server_cert = NULL; + connssl->connecting_state = ssl_connect_done; + + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22924/fixed.c b/benchmarks/pairs/vfc/curl-cve-2021-22924/fixed.c new file mode 100644 index 0000000..193ee47 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22924/fixed.c @@ -0,0 +1,504 @@ +/* Provenance: curl/curl create_conn (fixed). + * repo: curl/curl + * commit: 5ea3145850ebff1dc2b13d17440300a01ca38161 + * parent: fd9b40bf8dfd43edcbc0d254d613d95a11061c05 + * commit_url: https://github.com/curl/curl/commit/5ea3145850ebff1dc2b13d17440300a01ca38161 + * cve: CVE-2021-22924 + * license: curl + * function: create_conn + * relpath: lib/url.c + */ + +* create_conn() sets up a new connectdata struct, or re-uses an already + * existing one, and resolves host name. + * + * if this function returns CURLE_OK and *async is set to TRUE, the resolve + * response will be coming asynchronously. If *async is FALSE, the name is + * already resolved. + * + * @param data The sessionhandle pointer + * @param in_connect is set to the next connection data pointer + * @param async is set TRUE when an async DNS resolution is pending + * @see Curl_setup_conn() + * + */ + +static CURLcode create_conn(struct Curl_easy *data, + struct connectdata **in_connect, + bool *async) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn; + struct connectdata *conn_temp = NULL; + bool reuse; + bool connections_available = TRUE; + bool force_reuse = FALSE; + bool waitpipe = FALSE; + size_t max_host_connections = Curl_multi_max_host_connections(data->multi); + size_t max_total_connections = Curl_multi_max_total_connections(data->multi); + + *async = FALSE; + *in_connect = NULL; + + /************************************************************* + * Check input data + *************************************************************/ + if(!data->state.url) { + result = CURLE_URL_MALFORMAT; + goto out; + } + + /* First, split up the current URL in parts so that we can use the + parts for checking against the already present connections. In order + to not have to modify everything at once, we allocate a temporary + connection data struct and fill in for comparison purposes. */ + conn = allocate_conn(data); + + if(!conn) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + /* We must set the return variable as soon as possible, so that our + parent can cleanup any possible allocs we may have done before + any failure */ + *in_connect = conn; + + result = parseurlandfillconn(data, conn); + if(result) + goto out; + + if(data->set.str[STRING_SASL_AUTHZID]) { + conn->sasl_authzid = strdup(data->set.str[STRING_SASL_AUTHZID]); + if(!conn->sasl_authzid) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + } + +#ifdef USE_UNIX_SOCKETS + if(data->set.str[STRING_UNIX_SOCKET_PATH]) { + conn->unix_domain_socket = strdup(data->set.str[STRING_UNIX_SOCKET_PATH]); + if(!conn->unix_domain_socket) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + conn->bits.abstract_unix_socket = data->set.abstract_unix_socket; + } +#endif + + /* After the unix socket init but before the proxy vars are used, parse and + initialize the proxy vars */ +#ifndef CURL_DISABLE_PROXY + result = create_conn_helper_init_proxy(data, conn); + if(result) + goto out; + + /************************************************************* + * If the protocol is using SSL and HTTP proxy is used, we set + * the tunnel_proxy bit. + *************************************************************/ + if((conn->given->flags&PROTOPT_SSL) && conn->bits.httpproxy) + conn->bits.tunnel_proxy = TRUE; +#endif + + /************************************************************* + * Figure out the remote port number and fix it in the URL + *************************************************************/ + result = parse_remote_port(data, conn); + if(result) + goto out; + + /* Check for overridden login details and set them accordingly so that + they are known when protocol->setup_connection is called! */ + result = override_login(data, conn); + if(result) + goto out; + + result = set_login(conn); /* default credentials */ + if(result) + goto out; + + /************************************************************* + * Process the "connect to" linked list of hostname/port mappings. + * Do this after the remote port number has been fixed in the URL. + *************************************************************/ + result = parse_connect_to_slist(data, conn, data->set.connect_to); + if(result) + goto out; + + /************************************************************* + * IDN-convert the hostnames + *************************************************************/ + result = Curl_idnconvert_hostname(data, &conn->host); + if(result) + goto out; + if(conn->bits.conn_to_host) { + result = Curl_idnconvert_hostname(data, &conn->conn_to_host); + if(result) + goto out; + } +#ifndef CURL_DISABLE_PROXY + if(conn->bits.httpproxy) { + result = Curl_idnconvert_hostname(data, &conn->http_proxy.host); + if(result) + goto out; + } + if(conn->bits.socksproxy) { + result = Curl_idnconvert_hostname(data, &conn->socks_proxy.host); + if(result) + goto out; + } +#endif + + /************************************************************* + * Check whether the host and the "connect to host" are equal. + * Do this after the hostnames have been IDN-converted. + *************************************************************/ + if(conn->bits.conn_to_host && + strcasecompare(conn->conn_to_host.name, conn->host.name)) { + conn->bits.conn_to_host = FALSE; + } + + /************************************************************* + * Check whether the port and the "connect to port" are equal. + * Do this after the remote port number has been fixed in the URL. + *************************************************************/ + if(conn->bits.conn_to_port && conn->conn_to_port == conn->remote_port) { + conn->bits.conn_to_port = FALSE; + } + +#ifndef CURL_DISABLE_PROXY + /************************************************************* + * If the "connect to" feature is used with an HTTP proxy, + * we set the tunnel_proxy bit. + *************************************************************/ + if((conn->bits.conn_to_host || conn->bits.conn_to_port) && + conn->bits.httpproxy) + conn->bits.tunnel_proxy = TRUE; +#endif + + /************************************************************* + * Setup internals depending on protocol. Needs to be done after + * we figured out what/if proxy to use. + *************************************************************/ + result = setup_connection_internals(data, conn); + if(result) + goto out; + + conn->recv[FIRSTSOCKET] = Curl_recv_plain; + conn->send[FIRSTSOCKET] = Curl_send_plain; + conn->recv[SECONDARYSOCKET] = Curl_recv_plain; + conn->send[SECONDARYSOCKET] = Curl_send_plain; + + conn->bits.tcp_fastopen = data->set.tcp_fastopen; + + /*********************************************************************** + * file: is a special case in that it doesn't need a network connection + ***********************************************************************/ +#ifndef CURL_DISABLE_FILE + if(conn->handler->flags & PROTOPT_NONETWORK) { + bool done; + /* this is supposed to be the connect function so we better at least check + that the file is present here! */ + DEBUGASSERT(conn->handler->connect_it); + Curl_persistconninfo(data, conn, NULL, -1); + result = conn->handler->connect_it(data, &done); + + /* Setup a "faked" transfer that'll do nothing */ + if(!result) { + conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; /* we are "connected */ + + Curl_attach_connnection(data, conn); + result = Curl_conncache_add_conn(data); + if(result) + goto out; + + /* + * Setup whatever necessary for a resumed transfer + */ + result = setup_range(data); + if(result) { + DEBUGASSERT(conn->handler->done); + /* we ignore the return code for the protocol-specific DONE */ + (void)conn->handler->done(data, result, FALSE); + goto out; + } + Curl_setup_transfer(data, -1, -1, FALSE, -1); + } + + /* since we skip do_init() */ + Curl_init_do(data, conn); + + goto out; + } +#endif + + /* Get a cloned copy of the SSL config situation stored in the + connection struct. But to get this going nicely, we must first make + sure that the strings in the master copy are pointing to the correct + strings in the session handle strings array! + + Keep in mind that the pointers in the master copy are pointing to strings + that will be freed as part of the Curl_easy struct, but all cloned + copies will be separately allocated. + */ + data->set.ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH]; + data->set.ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE]; + data->set.ssl.primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT]; + data->set.ssl.primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT]; + data->set.ssl.primary.random_file = data->set.str[STRING_SSL_RANDOM_FILE]; + data->set.ssl.primary.egdsocket = data->set.str[STRING_SSL_EGDSOCKET]; + data->set.ssl.primary.cipher_list = + data->set.str[STRING_SSL_CIPHER_LIST]; + data->set.ssl.primary.cipher_list13 = + data->set.str[STRING_SSL_CIPHER13_LIST]; + data->set.ssl.primary.pinned_key = + data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + data->set.ssl.primary.cert_blob = data->set.blobs[BLOB_CERT]; + data->set.ssl.primary.ca_info_blob = data->set.blobs[BLOB_CAINFO]; + data->set.ssl.primary.curves = data->set.str[STRING_SSL_EC_CURVES]; + +#ifndef CURL_DISABLE_PROXY + data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY]; + data->set.proxy_ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY]; + data->set.proxy_ssl.primary.random_file = + data->set.str[STRING_SSL_RANDOM_FILE]; + data->set.proxy_ssl.primary.egdsocket = data->set.str[STRING_SSL_EGDSOCKET]; + data->set.proxy_ssl.primary.cipher_list = + data->set.str[STRING_SSL_CIPHER_LIST_PROXY]; + data->set.proxy_ssl.primary.cipher_list13 = + data->set.str[STRING_SSL_CIPHER13_LIST_PROXY]; + data->set.proxy_ssl.primary.pinned_key = + data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]; + data->set.proxy_ssl.primary.cert_blob = data->set.blobs[BLOB_CERT_PROXY]; + data->set.proxy_ssl.primary.ca_info_blob = + data->set.blobs[BLOB_CAINFO_PROXY]; + data->set.proxy_ssl.primary.issuercert = + data->set.str[STRING_SSL_ISSUERCERT_PROXY]; + data->set.proxy_ssl.primary.issuercert_blob = + data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY]; + data->set.proxy_ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY]; + data->set.proxy_ssl.cert_type = data->set.str[STRING_CERT_TYPE_PROXY]; + data->set.proxy_ssl.key = data->set.str[STRING_KEY_PROXY]; + data->set.proxy_ssl.key_type = data->set.str[STRING_KEY_TYPE_PROXY]; + data->set.proxy_ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY]; + data->set.proxy_ssl.primary.clientcert = data->set.str[STRING_CERT_PROXY]; + data->set.proxy_ssl.key_blob = data->set.blobs[BLOB_KEY_PROXY]; +#endif + data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE]; + data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE]; + data->set.ssl.key = data->set.str[STRING_KEY]; + data->set.ssl.key_type = data->set.str[STRING_KEY_TYPE]; + data->set.ssl.key_passwd = data->set.str[STRING_KEY_PASSWD]; + data->set.ssl.primary.clientcert = data->set.str[STRING_CERT]; +#ifdef USE_TLS_SRP + data->set.ssl.username = data->set.str[STRING_TLSAUTH_USERNAME]; + data->set.ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD]; +#ifndef CURL_DISABLE_PROXY + data->set.proxy_ssl.username = data->set.str[STRING_TLSAUTH_USERNAME_PROXY]; + data->set.proxy_ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_PROXY]; +#endif +#endif + data->set.ssl.key_blob = data->set.blobs[BLOB_KEY]; + + if(!Curl_clone_primary_ssl_config(&data->set.ssl.primary, + &conn->ssl_config)) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + +#ifndef CURL_DISABLE_PROXY + if(!Curl_clone_primary_ssl_config(&data->set.proxy_ssl.primary, + &conn->proxy_ssl_config)) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } +#endif + + prune_dead_connections(data); + + /************************************************************* + * Check the current list of connections to see if we can + * re-use an already existing one or if we have to create a + * new one. + *************************************************************/ + + DEBUGASSERT(conn->user); + DEBUGASSERT(conn->passwd); + + /* reuse_fresh is TRUE if we are told to use a new connection by force, but + we only acknowledge this option if this is not a re-used connection + already (which happens due to follow-location or during a HTTP + authentication phase). CONNECT_ONLY transfers also refuse reuse. */ + if((data->set.reuse_fresh && !data->state.this_is_a_follow) || + data->set.connect_only) + reuse = FALSE; + else + reuse = ConnectionExists(data, conn, &conn_temp, &force_reuse, &waitpipe); + + if(reuse) { + /* + * We already have a connection for this, we got the former connection in + * the conn_temp variable and thus we need to cleanup the one we just + * allocated before we can move along and use the previously existing one. + */ + reuse_conn(data, conn, conn_temp); +#ifdef USE_SSL + free(conn->ssl_extra); +#endif + free(conn); /* we don't need this anymore */ + conn = conn_temp; + *in_connect = conn; + +#ifndef CURL_DISABLE_PROXY + infof(data, "Re-using existing connection! (#%ld) with %s %s", + conn->connection_id, + conn->bits.proxy?"proxy":"host", + conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname : + conn->http_proxy.host.name ? conn->http_proxy.host.dispname : + conn->host.dispname); +#else + infof(data, "Re-using existing connection! (#%ld) with host %s", + conn->connection_id, conn->host.dispname); +#endif + } + else { + /* We have decided that we want a new connection. However, we may not + be able to do that if we have reached the limit of how many + connections we are allowed to open. */ + + if(conn->handler->flags & PROTOPT_ALPN_NPN) { + /* The protocol wants it, so set the bits if enabled in the easy handle + (default) */ + if(data->set.ssl_enable_alpn) + conn->bits.tls_enable_alpn = TRUE; + if(data->set.ssl_enable_npn) + conn->bits.tls_enable_npn = TRUE; + } + + if(waitpipe) + /* There is a connection that *might* become usable for multiplexing + "soon", and we wait for that */ + connections_available = FALSE; + else { + /* this gets a lock on the conncache */ + const char *bundlehost; + struct connectbundle *bundle = + Curl_conncache_find_bundle(data, conn, data->state.conn_cache, + &bundlehost); + + if(max_host_connections > 0 && bundle && + (bundle->num_connections >= max_host_connections)) { + struct connectdata *conn_candidate; + + /* The bundle is full. Extract the oldest connection. */ + conn_candidate = Curl_conncache_extract_bundle(data, bundle); + CONNCACHE_UNLOCK(data); + + if(conn_candidate) + (void)Curl_disconnect(data, conn_candidate, FALSE); + else { + infof(data, "No more connections allowed to host %s: %zu", + bundlehost, max_host_connections); + connections_available = FALSE; + } + } + else + CONNCACHE_UNLOCK(data); + + } + + if(connections_available && + (max_total_connections > 0) && + (Curl_conncache_size(data) >= max_total_connections)) { + struct connectdata *conn_candidate; + + /* The cache is full. Let's see if we can kill a connection. */ + conn_candidate = Curl_conncache_extract_oldest(data); + if(conn_candidate) + (void)Curl_disconnect(data, conn_candidate, FALSE); + else { + infof(data, "No connections available in cache"); + connections_available = FALSE; + } + } + + if(!connections_available) { + infof(data, "No connections available."); + + conn_free(conn); + *in_connect = NULL; + + result = CURLE_NO_CONNECTION_AVAILABLE; + goto out; + } + else { + /* + * This is a brand new connection, so let's store it in the connection + * cache of ours! + */ + Curl_attach_connnection(data, conn); + result = Curl_conncache_add_conn(data); + if(result) + goto out; + } + +#if defined(USE_NTLM) + /* If NTLM is requested in a part of this connection, make sure we don't + assume the state is fine as this is a fresh connection and NTLM is + connection based. */ + if((data->state.authhost.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && + data->state.authhost.done) { + infof(data, "NTLM picked AND auth done set, clear picked!"); + data->state.authhost.picked = CURLAUTH_NONE; + data->state.authhost.done = FALSE; + } + + if((data->state.authproxy.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && + data->state.authproxy.done) { + infof(data, "NTLM-proxy picked AND auth done set, clear picked!"); + data->state.authproxy.picked = CURLAUTH_NONE; + data->state.authproxy.done = FALSE; + } +#endif + } + + /* Setup and init stuff before DO starts, in preparing for the transfer. */ + Curl_init_do(data, conn); + + /* + * Setup whatever necessary for a resumed transfer + */ + result = setup_range(data); + if(result) + goto out; + + /* Continue connectdata initialization here. */ + + /* + * Inherit the proper values from the urldata struct AFTER we have arranged + * the persistent connection stuff + */ + conn->seek_func = data->set.seek_func; + conn->seek_client = data->set.seek_client; + + /************************************************************* + * Resolve the address of the server or proxy + *************************************************************/ + result = resolve_server(data, conn, async); + + /* Strip trailing dots. resolve_server copied the name. */ + strip_trailing_dot(&conn->host); +#ifndef CURL_DISABLE_PROXY + if(conn->bits.httpproxy) + strip_trailing_dot(&conn->http_proxy.host); + if(conn->bits.socksproxy) + strip_trailing_dot(&conn->socks_proxy.host); +#endif + if(conn->bits.conn_to_host) + strip_trailing_dot(&conn->conn_to_host); + +out: + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22924/vuln.c b/benchmarks/pairs/vfc/curl-cve-2021-22924/vuln.c new file mode 100644 index 0000000..c1aeb7e --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22924/vuln.c @@ -0,0 +1,502 @@ +/* Provenance: curl/curl create_conn (vuln). + * repo: curl/curl + * commit: fd9b40bf8dfd43edcbc0d254d613d95a11061c05 + * parent: fd9b40bf8dfd43edcbc0d254d613d95a11061c05 + * commit_url: https://github.com/curl/curl/commit/5ea3145850ebff1dc2b13d17440300a01ca38161 + * cve: CVE-2021-22924 + * license: curl + * function: create_conn + * relpath: lib/url.c + */ + +* create_conn() sets up a new connectdata struct, or re-uses an already + * existing one, and resolves host name. + * + * if this function returns CURLE_OK and *async is set to TRUE, the resolve + * response will be coming asynchronously. If *async is FALSE, the name is + * already resolved. + * + * @param data The sessionhandle pointer + * @param in_connect is set to the next connection data pointer + * @param async is set TRUE when an async DNS resolution is pending + * @see Curl_setup_conn() + * + */ + +static CURLcode create_conn(struct Curl_easy *data, + struct connectdata **in_connect, + bool *async) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn; + struct connectdata *conn_temp = NULL; + bool reuse; + bool connections_available = TRUE; + bool force_reuse = FALSE; + bool waitpipe = FALSE; + size_t max_host_connections = Curl_multi_max_host_connections(data->multi); + size_t max_total_connections = Curl_multi_max_total_connections(data->multi); + + *async = FALSE; + *in_connect = NULL; + + /************************************************************* + * Check input data + *************************************************************/ + if(!data->state.url) { + result = CURLE_URL_MALFORMAT; + goto out; + } + + /* First, split up the current URL in parts so that we can use the + parts for checking against the already present connections. In order + to not have to modify everything at once, we allocate a temporary + connection data struct and fill in for comparison purposes. */ + conn = allocate_conn(data); + + if(!conn) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + /* We must set the return variable as soon as possible, so that our + parent can cleanup any possible allocs we may have done before + any failure */ + *in_connect = conn; + + result = parseurlandfillconn(data, conn); + if(result) + goto out; + + if(data->set.str[STRING_SASL_AUTHZID]) { + conn->sasl_authzid = strdup(data->set.str[STRING_SASL_AUTHZID]); + if(!conn->sasl_authzid) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + } + +#ifdef USE_UNIX_SOCKETS + if(data->set.str[STRING_UNIX_SOCKET_PATH]) { + conn->unix_domain_socket = strdup(data->set.str[STRING_UNIX_SOCKET_PATH]); + if(!conn->unix_domain_socket) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + conn->bits.abstract_unix_socket = data->set.abstract_unix_socket; + } +#endif + + /* After the unix socket init but before the proxy vars are used, parse and + initialize the proxy vars */ +#ifndef CURL_DISABLE_PROXY + result = create_conn_helper_init_proxy(data, conn); + if(result) + goto out; + + /************************************************************* + * If the protocol is using SSL and HTTP proxy is used, we set + * the tunnel_proxy bit. + *************************************************************/ + if((conn->given->flags&PROTOPT_SSL) && conn->bits.httpproxy) + conn->bits.tunnel_proxy = TRUE; +#endif + + /************************************************************* + * Figure out the remote port number and fix it in the URL + *************************************************************/ + result = parse_remote_port(data, conn); + if(result) + goto out; + + /* Check for overridden login details and set them accordingly so that + they are known when protocol->setup_connection is called! */ + result = override_login(data, conn); + if(result) + goto out; + + result = set_login(conn); /* default credentials */ + if(result) + goto out; + + /************************************************************* + * Process the "connect to" linked list of hostname/port mappings. + * Do this after the remote port number has been fixed in the URL. + *************************************************************/ + result = parse_connect_to_slist(data, conn, data->set.connect_to); + if(result) + goto out; + + /************************************************************* + * IDN-convert the hostnames + *************************************************************/ + result = Curl_idnconvert_hostname(data, &conn->host); + if(result) + goto out; + if(conn->bits.conn_to_host) { + result = Curl_idnconvert_hostname(data, &conn->conn_to_host); + if(result) + goto out; + } +#ifndef CURL_DISABLE_PROXY + if(conn->bits.httpproxy) { + result = Curl_idnconvert_hostname(data, &conn->http_proxy.host); + if(result) + goto out; + } + if(conn->bits.socksproxy) { + result = Curl_idnconvert_hostname(data, &conn->socks_proxy.host); + if(result) + goto out; + } +#endif + + /************************************************************* + * Check whether the host and the "connect to host" are equal. + * Do this after the hostnames have been IDN-converted. + *************************************************************/ + if(conn->bits.conn_to_host && + strcasecompare(conn->conn_to_host.name, conn->host.name)) { + conn->bits.conn_to_host = FALSE; + } + + /************************************************************* + * Check whether the port and the "connect to port" are equal. + * Do this after the remote port number has been fixed in the URL. + *************************************************************/ + if(conn->bits.conn_to_port && conn->conn_to_port == conn->remote_port) { + conn->bits.conn_to_port = FALSE; + } + +#ifndef CURL_DISABLE_PROXY + /************************************************************* + * If the "connect to" feature is used with an HTTP proxy, + * we set the tunnel_proxy bit. + *************************************************************/ + if((conn->bits.conn_to_host || conn->bits.conn_to_port) && + conn->bits.httpproxy) + conn->bits.tunnel_proxy = TRUE; +#endif + + /************************************************************* + * Setup internals depending on protocol. Needs to be done after + * we figured out what/if proxy to use. + *************************************************************/ + result = setup_connection_internals(data, conn); + if(result) + goto out; + + conn->recv[FIRSTSOCKET] = Curl_recv_plain; + conn->send[FIRSTSOCKET] = Curl_send_plain; + conn->recv[SECONDARYSOCKET] = Curl_recv_plain; + conn->send[SECONDARYSOCKET] = Curl_send_plain; + + conn->bits.tcp_fastopen = data->set.tcp_fastopen; + + /*********************************************************************** + * file: is a special case in that it doesn't need a network connection + ***********************************************************************/ +#ifndef CURL_DISABLE_FILE + if(conn->handler->flags & PROTOPT_NONETWORK) { + bool done; + /* this is supposed to be the connect function so we better at least check + that the file is present here! */ + DEBUGASSERT(conn->handler->connect_it); + Curl_persistconninfo(data, conn, NULL, -1); + result = conn->handler->connect_it(data, &done); + + /* Setup a "faked" transfer that'll do nothing */ + if(!result) { + conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; /* we are "connected */ + + Curl_attach_connnection(data, conn); + result = Curl_conncache_add_conn(data); + if(result) + goto out; + + /* + * Setup whatever necessary for a resumed transfer + */ + result = setup_range(data); + if(result) { + DEBUGASSERT(conn->handler->done); + /* we ignore the return code for the protocol-specific DONE */ + (void)conn->handler->done(data, result, FALSE); + goto out; + } + Curl_setup_transfer(data, -1, -1, FALSE, -1); + } + + /* since we skip do_init() */ + Curl_init_do(data, conn); + + goto out; + } +#endif + + /* Get a cloned copy of the SSL config situation stored in the + connection struct. But to get this going nicely, we must first make + sure that the strings in the master copy are pointing to the correct + strings in the session handle strings array! + + Keep in mind that the pointers in the master copy are pointing to strings + that will be freed as part of the Curl_easy struct, but all cloned + copies will be separately allocated. + */ + data->set.ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH]; + data->set.ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE]; + data->set.ssl.primary.random_file = data->set.str[STRING_SSL_RANDOM_FILE]; + data->set.ssl.primary.egdsocket = data->set.str[STRING_SSL_EGDSOCKET]; + data->set.ssl.primary.cipher_list = + data->set.str[STRING_SSL_CIPHER_LIST]; + data->set.ssl.primary.cipher_list13 = + data->set.str[STRING_SSL_CIPHER13_LIST]; + data->set.ssl.primary.pinned_key = + data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + data->set.ssl.primary.cert_blob = data->set.blobs[BLOB_CERT]; + data->set.ssl.primary.ca_info_blob = data->set.blobs[BLOB_CAINFO]; + data->set.ssl.primary.curves = data->set.str[STRING_SSL_EC_CURVES]; + +#ifndef CURL_DISABLE_PROXY + data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY]; + data->set.proxy_ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY]; + data->set.proxy_ssl.primary.random_file = + data->set.str[STRING_SSL_RANDOM_FILE]; + data->set.proxy_ssl.primary.egdsocket = data->set.str[STRING_SSL_EGDSOCKET]; + data->set.proxy_ssl.primary.cipher_list = + data->set.str[STRING_SSL_CIPHER_LIST_PROXY]; + data->set.proxy_ssl.primary.cipher_list13 = + data->set.str[STRING_SSL_CIPHER13_LIST_PROXY]; + data->set.proxy_ssl.primary.pinned_key = + data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]; + data->set.proxy_ssl.primary.cert_blob = data->set.blobs[BLOB_CERT_PROXY]; + data->set.proxy_ssl.primary.ca_info_blob = + data->set.blobs[BLOB_CAINFO_PROXY]; + data->set.proxy_ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY]; + data->set.proxy_ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_PROXY]; + data->set.proxy_ssl.cert_type = data->set.str[STRING_CERT_TYPE_PROXY]; + data->set.proxy_ssl.key = data->set.str[STRING_KEY_PROXY]; + data->set.proxy_ssl.key_type = data->set.str[STRING_KEY_TYPE_PROXY]; + data->set.proxy_ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY]; + data->set.proxy_ssl.primary.clientcert = data->set.str[STRING_CERT_PROXY]; + data->set.proxy_ssl.key_blob = data->set.blobs[BLOB_KEY_PROXY]; +#endif + data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE]; + data->set.ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT]; + data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE]; + data->set.ssl.key = data->set.str[STRING_KEY]; + data->set.ssl.key_type = data->set.str[STRING_KEY_TYPE]; + data->set.ssl.key_passwd = data->set.str[STRING_KEY_PASSWD]; + data->set.ssl.primary.clientcert = data->set.str[STRING_CERT]; +#ifdef USE_TLS_SRP + data->set.ssl.username = data->set.str[STRING_TLSAUTH_USERNAME]; + data->set.ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD]; +#ifndef CURL_DISABLE_PROXY + data->set.proxy_ssl.username = data->set.str[STRING_TLSAUTH_USERNAME_PROXY]; + data->set.proxy_ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_PROXY]; +#endif +#endif + + data->set.ssl.key_blob = data->set.blobs[BLOB_KEY]; + data->set.ssl.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT]; + + if(!Curl_clone_primary_ssl_config(&data->set.ssl.primary, + &conn->ssl_config)) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + +#ifndef CURL_DISABLE_PROXY + if(!Curl_clone_primary_ssl_config(&data->set.proxy_ssl.primary, + &conn->proxy_ssl_config)) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } +#endif + + prune_dead_connections(data); + + /************************************************************* + * Check the current list of connections to see if we can + * re-use an already existing one or if we have to create a + * new one. + *************************************************************/ + + DEBUGASSERT(conn->user); + DEBUGASSERT(conn->passwd); + + /* reuse_fresh is TRUE if we are told to use a new connection by force, but + we only acknowledge this option if this is not a re-used connection + already (which happens due to follow-location or during a HTTP + authentication phase). CONNECT_ONLY transfers also refuse reuse. */ + if((data->set.reuse_fresh && !data->state.this_is_a_follow) || + data->set.connect_only) + reuse = FALSE; + else + reuse = ConnectionExists(data, conn, &conn_temp, &force_reuse, &waitpipe); + + if(reuse) { + /* + * We already have a connection for this, we got the former connection in + * the conn_temp variable and thus we need to cleanup the one we just + * allocated before we can move along and use the previously existing one. + */ + reuse_conn(data, conn, conn_temp); +#ifdef USE_SSL + free(conn->ssl_extra); +#endif + free(conn); /* we don't need this anymore */ + conn = conn_temp; + *in_connect = conn; + +#ifndef CURL_DISABLE_PROXY + infof(data, "Re-using existing connection! (#%ld) with %s %s", + conn->connection_id, + conn->bits.proxy?"proxy":"host", + conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname : + conn->http_proxy.host.name ? conn->http_proxy.host.dispname : + conn->host.dispname); +#else + infof(data, "Re-using existing connection! (#%ld) with host %s", + conn->connection_id, conn->host.dispname); +#endif + } + else { + /* We have decided that we want a new connection. However, we may not + be able to do that if we have reached the limit of how many + connections we are allowed to open. */ + + if(conn->handler->flags & PROTOPT_ALPN_NPN) { + /* The protocol wants it, so set the bits if enabled in the easy handle + (default) */ + if(data->set.ssl_enable_alpn) + conn->bits.tls_enable_alpn = TRUE; + if(data->set.ssl_enable_npn) + conn->bits.tls_enable_npn = TRUE; + } + + if(waitpipe) + /* There is a connection that *might* become usable for multiplexing + "soon", and we wait for that */ + connections_available = FALSE; + else { + /* this gets a lock on the conncache */ + const char *bundlehost; + struct connectbundle *bundle = + Curl_conncache_find_bundle(data, conn, data->state.conn_cache, + &bundlehost); + + if(max_host_connections > 0 && bundle && + (bundle->num_connections >= max_host_connections)) { + struct connectdata *conn_candidate; + + /* The bundle is full. Extract the oldest connection. */ + conn_candidate = Curl_conncache_extract_bundle(data, bundle); + CONNCACHE_UNLOCK(data); + + if(conn_candidate) + (void)Curl_disconnect(data, conn_candidate, FALSE); + else { + infof(data, "No more connections allowed to host %s: %zu", + bundlehost, max_host_connections); + connections_available = FALSE; + } + } + else + CONNCACHE_UNLOCK(data); + + } + + if(connections_available && + (max_total_connections > 0) && + (Curl_conncache_size(data) >= max_total_connections)) { + struct connectdata *conn_candidate; + + /* The cache is full. Let's see if we can kill a connection. */ + conn_candidate = Curl_conncache_extract_oldest(data); + if(conn_candidate) + (void)Curl_disconnect(data, conn_candidate, FALSE); + else { + infof(data, "No connections available in cache"); + connections_available = FALSE; + } + } + + if(!connections_available) { + infof(data, "No connections available."); + + conn_free(conn); + *in_connect = NULL; + + result = CURLE_NO_CONNECTION_AVAILABLE; + goto out; + } + else { + /* + * This is a brand new connection, so let's store it in the connection + * cache of ours! + */ + Curl_attach_connnection(data, conn); + result = Curl_conncache_add_conn(data); + if(result) + goto out; + } + +#if defined(USE_NTLM) + /* If NTLM is requested in a part of this connection, make sure we don't + assume the state is fine as this is a fresh connection and NTLM is + connection based. */ + if((data->state.authhost.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && + data->state.authhost.done) { + infof(data, "NTLM picked AND auth done set, clear picked!"); + data->state.authhost.picked = CURLAUTH_NONE; + data->state.authhost.done = FALSE; + } + + if((data->state.authproxy.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && + data->state.authproxy.done) { + infof(data, "NTLM-proxy picked AND auth done set, clear picked!"); + data->state.authproxy.picked = CURLAUTH_NONE; + data->state.authproxy.done = FALSE; + } +#endif + } + + /* Setup and init stuff before DO starts, in preparing for the transfer. */ + Curl_init_do(data, conn); + + /* + * Setup whatever necessary for a resumed transfer + */ + result = setup_range(data); + if(result) + goto out; + + /* Continue connectdata initialization here. */ + + /* + * Inherit the proper values from the urldata struct AFTER we have arranged + * the persistent connection stuff + */ + conn->seek_func = data->set.seek_func; + conn->seek_client = data->set.seek_client; + + /************************************************************* + * Resolve the address of the server or proxy + *************************************************************/ + result = resolve_server(data, conn, async); + + /* Strip trailing dots. resolve_server copied the name. */ + strip_trailing_dot(&conn->host); +#ifndef CURL_DISABLE_PROXY + if(conn->bits.httpproxy) + strip_trailing_dot(&conn->http_proxy.host); + if(conn->bits.socksproxy) + strip_trailing_dot(&conn->socks_proxy.host); +#endif + if(conn->bits.conn_to_host) + strip_trailing_dot(&conn->conn_to_host); + +out: + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22925/fixed.c b/benchmarks/pairs/vfc/curl-cve-2021-22925/fixed.c new file mode 100644 index 0000000..7115eed --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22925/fixed.c @@ -0,0 +1,91 @@ +/* Provenance: curl/curl suboption (fixed). + * repo: curl/curl + * commit: 894f6ec730597eb243618d33cc84d71add8d6a8a + * parent: 12284e008bad5156b67d0ac253331a96d77201d1 + * commit_url: https://github.com/curl/curl/commit/894f6ec730597eb243618d33cc84d71add8d6a8a + * cve: CVE-2021-22925 + * license: curl + * function: suboption + * relpath: lib/telnet.c + */ + +* suboption() + * + * Look at the sub-option buffer, and try to be helpful to the other + * side. + */ + +static void suboption(struct Curl_easy *data) +{ + struct curl_slist *v; + unsigned char temp[2048]; + ssize_t bytes_written; + size_t len; + int err; + char varname[128] = ""; + char varval[128] = ""; + struct TELNET *tn = data->req.p.telnet; + struct connectdata *conn = data->conn; + + printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn) + 2); + switch(CURL_SB_GET(tn)) { + case CURL_TELOPT_TTYPE: + len = strlen(tn->subopt_ttype) + 4 + 2; + msnprintf((char *)temp, sizeof(temp), + "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE, + CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE); + bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); + if(bytes_written < 0) { + err = SOCKERRNO; + failf(data,"Sending data failed (%d)",err); + } + printsub(data, '>', &temp[2], len-2); + break; + case CURL_TELOPT_XDISPLOC: + len = strlen(tn->subopt_xdisploc) + 4 + 2; + msnprintf((char *)temp, sizeof(temp), + "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC, + CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE); + bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); + if(bytes_written < 0) { + err = SOCKERRNO; + failf(data,"Sending data failed (%d)",err); + } + printsub(data, '>', &temp[2], len-2); + break; + case CURL_TELOPT_NEW_ENVIRON: + msnprintf((char *)temp, sizeof(temp), + "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON, + CURL_TELQUAL_IS); + len = 4; + + for(v = tn->telnet_vars; v; v = v->next) { + size_t tmplen = (strlen(v->data) + 1); + /* Add the variable only if it fits */ + if(len + tmplen < (int)sizeof(temp)-6) { + int rv; + char sep[2] = ""; + varval[0] = 0; + rv = sscanf(v->data, "%127[^,]%1[,]%127s", varname, sep, varval); + if(rv == 1) + len += msnprintf((char *)&temp[len], sizeof(temp) - len, + "%c%s", CURL_NEW_ENV_VAR, varname); + else if(rv >= 2) + len += msnprintf((char *)&temp[len], sizeof(temp) - len, + "%c%s%c%s", CURL_NEW_ENV_VAR, varname, + CURL_NEW_ENV_VALUE, varval); + } + } + msnprintf((char *)&temp[len], sizeof(temp) - len, + "%c%c", CURL_IAC, CURL_SE); + len += 2; + bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); + if(bytes_written < 0) { + err = SOCKERRNO; + failf(data,"Sending data failed (%d)",err); + } + printsub(data, '>', &temp[2], len-2); + break; + } + return; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22925/vuln.c b/benchmarks/pairs/vfc/curl-cve-2021-22925/vuln.c new file mode 100644 index 0000000..1fe952b --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22925/vuln.c @@ -0,0 +1,86 @@ +/* Provenance: curl/curl suboption (vuln). + * repo: curl/curl + * commit: 12284e008bad5156b67d0ac253331a96d77201d1 + * parent: 12284e008bad5156b67d0ac253331a96d77201d1 + * commit_url: https://github.com/curl/curl/commit/894f6ec730597eb243618d33cc84d71add8d6a8a + * cve: CVE-2021-22925 + * license: curl + * function: suboption + * relpath: lib/telnet.c + */ + +* suboption() + * + * Look at the sub-option buffer, and try to be helpful to the other + * side. + */ + +static void suboption(struct Curl_easy *data) +{ + struct curl_slist *v; + unsigned char temp[2048]; + ssize_t bytes_written; + size_t len; + int err; + char varname[128] = ""; + char varval[128] = ""; + struct TELNET *tn = data->req.p.telnet; + struct connectdata *conn = data->conn; + + printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn) + 2); + switch(CURL_SB_GET(tn)) { + case CURL_TELOPT_TTYPE: + len = strlen(tn->subopt_ttype) + 4 + 2; + msnprintf((char *)temp, sizeof(temp), + "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE, + CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE); + bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); + if(bytes_written < 0) { + err = SOCKERRNO; + failf(data,"Sending data failed (%d)",err); + } + printsub(data, '>', &temp[2], len-2); + break; + case CURL_TELOPT_XDISPLOC: + len = strlen(tn->subopt_xdisploc) + 4 + 2; + msnprintf((char *)temp, sizeof(temp), + "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC, + CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE); + bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); + if(bytes_written < 0) { + err = SOCKERRNO; + failf(data,"Sending data failed (%d)",err); + } + printsub(data, '>', &temp[2], len-2); + break; + case CURL_TELOPT_NEW_ENVIRON: + msnprintf((char *)temp, sizeof(temp), + "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON, + CURL_TELQUAL_IS); + len = 4; + + for(v = tn->telnet_vars; v; v = v->next) { + size_t tmplen = (strlen(v->data) + 1); + /* Add the variable only if it fits */ + if(len + tmplen < (int)sizeof(temp)-6) { + if(sscanf(v->data, "%127[^,],%127s", varname, varval) == 2) { + msnprintf((char *)&temp[len], sizeof(temp) - len, + "%c%s%c%s", CURL_NEW_ENV_VAR, varname, + CURL_NEW_ENV_VALUE, varval); + len += tmplen; + } + } + } + msnprintf((char *)&temp[len], sizeof(temp) - len, + "%c%c", CURL_IAC, CURL_SE); + len += 2; + bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); + if(bytes_written < 0) { + err = SOCKERRNO; + failf(data,"Sending data failed (%d)",err); + } + printsub(data, '>', &temp[2], len-2); + break; + } + return; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22945/fixed.c b/benchmarks/pairs/vfc/curl-cve-2021-22945/fixed.c new file mode 100644 index 0000000..caa4512 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22945/fixed.c @@ -0,0 +1,36 @@ +/* Provenance: curl/curl mqtt_send (fixed). + * repo: curl/curl + * commit: 43157490a5054bd24256fe12876931e8abc9df49 + * parent: 409a4412409371db00af0a3fe987e517bfab3d19 + * commit_url: https://github.com/curl/curl/commit/43157490a5054bd24256fe12876931e8abc9df49 + * cve: CVE-2021-22945 + * license: curl + * function: mqtt_send + * relpath: lib/mqtt.c + */ + +static CURLcode mqtt_send(struct Curl_easy *data, + char *buf, size_t len) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; + struct MQTT *mq = data->req.p.mqtt; + ssize_t n; + result = Curl_write(data, sockfd, buf, len, &n); + if(!result) + Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)n); + if(len != (size_t)n) { + size_t nsend = len - n; + char *sendleftovers = Curl_memdup(&buf[n], nsend); + if(!sendleftovers) + return CURLE_OUT_OF_MEMORY; + mq->sendleftovers = sendleftovers; + mq->nsend = nsend; + } + else { + mq->sendleftovers = NULL; + mq->nsend = 0; + } + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22945/vuln.c b/benchmarks/pairs/vfc/curl-cve-2021-22945/vuln.c new file mode 100644 index 0000000..3c28322 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22945/vuln.c @@ -0,0 +1,32 @@ +/* Provenance: curl/curl mqtt_send (vuln). + * repo: curl/curl + * commit: 409a4412409371db00af0a3fe987e517bfab3d19 + * parent: 409a4412409371db00af0a3fe987e517bfab3d19 + * commit_url: https://github.com/curl/curl/commit/43157490a5054bd24256fe12876931e8abc9df49 + * cve: CVE-2021-22945 + * license: curl + * function: mqtt_send + * relpath: lib/mqtt.c + */ + +static CURLcode mqtt_send(struct Curl_easy *data, + char *buf, size_t len) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; + struct MQTT *mq = data->req.p.mqtt; + ssize_t n; + result = Curl_write(data, sockfd, buf, len, &n); + if(!result) + Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)n); + if(len != (size_t)n) { + size_t nsend = len - n; + char *sendleftovers = Curl_memdup(&buf[n], nsend); + if(!sendleftovers) + return CURLE_OUT_OF_MEMORY; + mq->sendleftovers = sendleftovers; + mq->nsend = nsend; + } + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22946-imap_state_capability_re/fixed.c b/benchmarks/pairs/vfc/curl-cve-2021-22946-imap_state_capability_re/fixed.c new file mode 100644 index 0000000..ccda973 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22946-imap_state_capability_re/fixed.c @@ -0,0 +1,92 @@ +/* Provenance: curl/curl imap_state_capability_resp (fixed). + * repo: curl/curl + * commit: 364f174724ef115c63d5e5dc1d3342c8a43b1cca + * parent: 43157490a5054bd24256fe12876931e8abc9df49 + * commit_url: https://github.com/curl/curl/commit/364f174724ef115c63d5e5dc1d3342c8a43b1cca + * cve: CVE-2021-22946 + * license: curl + * function: imap_state_capability_resp + * relpath: lib/imap.c + */ + +static CURLcode imap_state_capability_resp(struct Curl_easy *data, + int imapcode, + imapstate instate) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct imap_conn *imapc = &conn->proto.imapc; + const char *line = data->state.buffer; + + (void)instate; /* no use for this yet */ + + /* Do we have a untagged response? */ + if(imapcode == '*') { + line += 2; + + /* Loop through the data line */ + for(;;) { + size_t wordlen; + while(*line && + (*line == ' ' || *line == '\t' || + *line == '\r' || *line == '\n')) { + + line++; + } + + if(!*line) + break; + + /* Extract the word */ + for(wordlen = 0; line[wordlen] && line[wordlen] != ' ' && + line[wordlen] != '\t' && line[wordlen] != '\r' && + line[wordlen] != '\n';) + wordlen++; + + /* Does the server support the STARTTLS capability? */ + if(wordlen == 8 && !memcmp(line, "STARTTLS", 8)) + imapc->tls_supported = TRUE; + + /* Has the server explicitly disabled clear text authentication? */ + else if(wordlen == 13 && !memcmp(line, "LOGINDISABLED", 13)) + imapc->login_disabled = TRUE; + + /* Does the server support the SASL-IR capability? */ + else if(wordlen == 7 && !memcmp(line, "SASL-IR", 7)) + imapc->ir_supported = TRUE; + + /* Do we have a SASL based authentication mechanism? */ + else if(wordlen > 5 && !memcmp(line, "AUTH=", 5)) { + size_t llen; + unsigned short mechbit; + + line += 5; + wordlen -= 5; + + /* Test the word for a matching authentication mechanism */ + mechbit = Curl_sasl_decode_mech(line, wordlen, &llen); + if(mechbit && llen == wordlen) + imapc->sasl.authmechs |= mechbit; + } + + line += wordlen; + } + } + else if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { + /* PREAUTH is not compatible with STARTTLS. */ + if(imapcode == IMAP_RESP_OK && imapc->tls_supported && !imapc->preauth) { + /* Switch to TLS connection now */ + result = imap_perform_starttls(data, conn); + } + else if(data->set.use_ssl <= CURLUSESSL_TRY) + result = imap_perform_authentication(data, conn); + else { + failf(data, "STARTTLS not available."); + result = CURLE_USE_SSL_FAILED; + } + } + else + result = imap_perform_authentication(data, conn); + + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22946-imap_state_capability_re/vuln.c b/benchmarks/pairs/vfc/curl-cve-2021-22946-imap_state_capability_re/vuln.c new file mode 100644 index 0000000..78e5e87 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22946-imap_state_capability_re/vuln.c @@ -0,0 +1,96 @@ +/* Provenance: curl/curl imap_state_capability_resp (vuln). + * repo: curl/curl + * commit: 43157490a5054bd24256fe12876931e8abc9df49 + * parent: 43157490a5054bd24256fe12876931e8abc9df49 + * commit_url: https://github.com/curl/curl/commit/364f174724ef115c63d5e5dc1d3342c8a43b1cca + * cve: CVE-2021-22946 + * license: curl + * function: imap_state_capability_resp + * relpath: lib/imap.c + */ + +static CURLcode imap_state_capability_resp(struct Curl_easy *data, + int imapcode, + imapstate instate) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct imap_conn *imapc = &conn->proto.imapc; + const char *line = data->state.buffer; + + (void)instate; /* no use for this yet */ + + /* Do we have a untagged response? */ + if(imapcode == '*') { + line += 2; + + /* Loop through the data line */ + for(;;) { + size_t wordlen; + while(*line && + (*line == ' ' || *line == '\t' || + *line == '\r' || *line == '\n')) { + + line++; + } + + if(!*line) + break; + + /* Extract the word */ + for(wordlen = 0; line[wordlen] && line[wordlen] != ' ' && + line[wordlen] != '\t' && line[wordlen] != '\r' && + line[wordlen] != '\n';) + wordlen++; + + /* Does the server support the STARTTLS capability? */ + if(wordlen == 8 && !memcmp(line, "STARTTLS", 8)) + imapc->tls_supported = TRUE; + + /* Has the server explicitly disabled clear text authentication? */ + else if(wordlen == 13 && !memcmp(line, "LOGINDISABLED", 13)) + imapc->login_disabled = TRUE; + + /* Does the server support the SASL-IR capability? */ + else if(wordlen == 7 && !memcmp(line, "SASL-IR", 7)) + imapc->ir_supported = TRUE; + + /* Do we have a SASL based authentication mechanism? */ + else if(wordlen > 5 && !memcmp(line, "AUTH=", 5)) { + size_t llen; + unsigned short mechbit; + + line += 5; + wordlen -= 5; + + /* Test the word for a matching authentication mechanism */ + mechbit = Curl_sasl_decode_mech(line, wordlen, &llen); + if(mechbit && llen == wordlen) + imapc->sasl.authmechs |= mechbit; + } + + line += wordlen; + } + } + else if(imapcode == IMAP_RESP_OK) { + if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { + /* We don't have a SSL/TLS connection yet, but SSL is requested */ + if(imapc->tls_supported) + /* Switch to TLS connection now */ + result = imap_perform_starttls(data, conn); + else if(data->set.use_ssl == CURLUSESSL_TRY) + /* Fallback and carry on with authentication */ + result = imap_perform_authentication(data, conn); + else { + failf(data, "STARTTLS not supported."); + result = CURLE_USE_SSL_FAILED; + } + } + else + result = imap_perform_authentication(data, conn); + } + else + result = imap_perform_authentication(data, conn); + + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22946-pop3_state_capa_resp/fixed.c b/benchmarks/pairs/vfc/curl-cve-2021-22946-pop3_state_capa_resp/fixed.c new file mode 100644 index 0000000..690acd8 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22946-pop3_state_capa_resp/fixed.c @@ -0,0 +1,94 @@ +/* Provenance: curl/curl pop3_state_capa_resp (fixed). + * repo: curl/curl + * commit: 364f174724ef115c63d5e5dc1d3342c8a43b1cca + * parent: 43157490a5054bd24256fe12876931e8abc9df49 + * commit_url: https://github.com/curl/curl/commit/364f174724ef115c63d5e5dc1d3342c8a43b1cca + * cve: CVE-2021-22946 + * license: curl + * function: pop3_state_capa_resp + * relpath: lib/pop3.c + */ + +static CURLcode pop3_state_capa_resp(struct Curl_easy *data, int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct pop3_conn *pop3c = &conn->proto.pop3c; + const char *line = data->state.buffer; + size_t len = strlen(line); + + (void)instate; /* no use for this yet */ + + /* Do we have a untagged continuation response? */ + if(pop3code == '*') { + /* Does the server support the STLS capability? */ + if(len >= 4 && !memcmp(line, "STLS", 4)) + pop3c->tls_supported = TRUE; + + /* Does the server support clear text authentication? */ + else if(len >= 4 && !memcmp(line, "USER", 4)) + pop3c->authtypes |= POP3_TYPE_CLEARTEXT; + + /* Does the server support SASL based authentication? */ + else if(len >= 5 && !memcmp(line, "SASL ", 5)) { + pop3c->authtypes |= POP3_TYPE_SASL; + + /* Advance past the SASL keyword */ + line += 5; + len -= 5; + + /* Loop through the data line */ + for(;;) { + size_t llen; + size_t wordlen; + unsigned short mechbit; + + while(len && + (*line == ' ' || *line == '\t' || + *line == '\r' || *line == '\n')) { + + line++; + len--; + } + + if(!len) + break; + + /* Extract the word */ + for(wordlen = 0; wordlen < len && line[wordlen] != ' ' && + line[wordlen] != '\t' && line[wordlen] != '\r' && + line[wordlen] != '\n';) + wordlen++; + + /* Test the word for a matching authentication mechanism */ + mechbit = Curl_sasl_decode_mech(line, wordlen, &llen); + if(mechbit && llen == wordlen) + pop3c->sasl.authmechs |= mechbit; + + line += wordlen; + len -= wordlen; + } + } + } + else { + /* Clear text is supported when CAPA isn't recognised */ + if(pop3code != '+') + pop3c->authtypes |= POP3_TYPE_CLEARTEXT; + + if(!data->set.use_ssl || conn->ssl[FIRSTSOCKET].use) + result = pop3_perform_authentication(data, conn); + else if(pop3code == '+' && pop3c->tls_supported) + /* Switch to TLS connection now */ + result = pop3_perform_starttls(data, conn); + else if(data->set.use_ssl <= CURLUSESSL_TRY) + /* Fallback and carry on with authentication */ + result = pop3_perform_authentication(data, conn); + else { + failf(data, "STLS not supported."); + result = CURLE_USE_SSL_FAILED; + } + } + + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22946-pop3_state_capa_resp/vuln.c b/benchmarks/pairs/vfc/curl-cve-2021-22946-pop3_state_capa_resp/vuln.c new file mode 100644 index 0000000..f5c5359 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22946-pop3_state_capa_resp/vuln.c @@ -0,0 +1,99 @@ +/* Provenance: curl/curl pop3_state_capa_resp (vuln). + * repo: curl/curl + * commit: 43157490a5054bd24256fe12876931e8abc9df49 + * parent: 43157490a5054bd24256fe12876931e8abc9df49 + * commit_url: https://github.com/curl/curl/commit/364f174724ef115c63d5e5dc1d3342c8a43b1cca + * cve: CVE-2021-22946 + * license: curl + * function: pop3_state_capa_resp + * relpath: lib/pop3.c + */ + +static CURLcode pop3_state_capa_resp(struct Curl_easy *data, int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + struct pop3_conn *pop3c = &conn->proto.pop3c; + const char *line = data->state.buffer; + size_t len = strlen(line); + + (void)instate; /* no use for this yet */ + + /* Do we have a untagged continuation response? */ + if(pop3code == '*') { + /* Does the server support the STLS capability? */ + if(len >= 4 && !memcmp(line, "STLS", 4)) + pop3c->tls_supported = TRUE; + + /* Does the server support clear text authentication? */ + else if(len >= 4 && !memcmp(line, "USER", 4)) + pop3c->authtypes |= POP3_TYPE_CLEARTEXT; + + /* Does the server support SASL based authentication? */ + else if(len >= 5 && !memcmp(line, "SASL ", 5)) { + pop3c->authtypes |= POP3_TYPE_SASL; + + /* Advance past the SASL keyword */ + line += 5; + len -= 5; + + /* Loop through the data line */ + for(;;) { + size_t llen; + size_t wordlen; + unsigned short mechbit; + + while(len && + (*line == ' ' || *line == '\t' || + *line == '\r' || *line == '\n')) { + + line++; + len--; + } + + if(!len) + break; + + /* Extract the word */ + for(wordlen = 0; wordlen < len && line[wordlen] != ' ' && + line[wordlen] != '\t' && line[wordlen] != '\r' && + line[wordlen] != '\n';) + wordlen++; + + /* Test the word for a matching authentication mechanism */ + mechbit = Curl_sasl_decode_mech(line, wordlen, &llen); + if(mechbit && llen == wordlen) + pop3c->sasl.authmechs |= mechbit; + + line += wordlen; + len -= wordlen; + } + } + } + else if(pop3code == '+') { + if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { + /* We don't have a SSL/TLS connection yet, but SSL is requested */ + if(pop3c->tls_supported) + /* Switch to TLS connection now */ + result = pop3_perform_starttls(data, conn); + else if(data->set.use_ssl == CURLUSESSL_TRY) + /* Fallback and carry on with authentication */ + result = pop3_perform_authentication(data, conn); + else { + failf(data, "STLS not supported."); + result = CURLE_USE_SSL_FAILED; + } + } + else + result = pop3_perform_authentication(data, conn); + } + else { + /* Clear text is supported when CAPA isn't recognised */ + pop3c->authtypes |= POP3_TYPE_CLEARTEXT; + + result = pop3_perform_authentication(data, conn); + } + + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22946/fixed.c b/benchmarks/pairs/vfc/curl-cve-2021-22946/fixed.c new file mode 100644 index 0000000..6e511b9 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22946/fixed.c @@ -0,0 +1,449 @@ +/* Provenance: curl/curl ftp_statemachine (fixed). + * repo: curl/curl + * commit: 364f174724ef115c63d5e5dc1d3342c8a43b1cca + * parent: 43157490a5054bd24256fe12876931e8abc9df49 + * commit_url: https://github.com/curl/curl/commit/364f174724ef115c63d5e5dc1d3342c8a43b1cca + * cve: CVE-2021-22946 + * license: curl + * function: ftp_statemachine + * relpath: lib/ftp.c + */ + +static CURLcode ftp_statemachine(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result; + curl_socket_t sock = conn->sock[FIRSTSOCKET]; + int ftpcode; + struct ftp_conn *ftpc = &conn->proto.ftpc; + struct pingpong *pp = &ftpc->pp; + static const char ftpauth[][4] = { "SSL", "TLS" }; + size_t nread = 0; + + if(pp->sendleft) + return Curl_pp_flushsend(data, pp); + + result = ftp_readresp(data, sock, pp, &ftpcode, &nread); + if(result) + return result; + + if(ftpcode) { + /* we have now received a full FTP server response */ + switch(ftpc->state) { + case FTP_WAIT220: + if(ftpcode == 230) { + /* 230 User logged in - already! Take as 220 if TLS required. */ + if(data->set.use_ssl <= CURLUSESSL_TRY || + conn->bits.ftp_use_control_ssl) + return ftp_state_user_resp(data, ftpcode, ftpc->state); + } + else if(ftpcode != 220) { + failf(data, "Got a %03d ftp-server response when 220 was expected", + ftpcode); + return CURLE_WEIRD_SERVER_REPLY; + } + + /* We have received a 220 response fine, now we proceed. */ +#ifdef HAVE_GSSAPI + if(data->set.krb) { + /* If not anonymous login, try a secure login. Note that this + procedure is still BLOCKING. */ + + Curl_sec_request_prot(conn, "private"); + /* We set private first as default, in case the line below fails to + set a valid level */ + Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]); + + if(Curl_sec_login(data, conn)) + infof(data, "Logging in with password in cleartext!"); + else + infof(data, "Authentication successful"); + } +#endif + + if(data->set.use_ssl && !conn->bits.ftp_use_control_ssl) { + /* We don't have a SSL/TLS control connection yet, but FTPS is + requested. Try a FTPS connection now */ + + ftpc->count3 = 0; + switch(data->set.ftpsslauth) { + case CURLFTPAUTH_DEFAULT: + case CURLFTPAUTH_SSL: + ftpc->count2 = 1; /* add one to get next */ + ftpc->count1 = 0; + break; + case CURLFTPAUTH_TLS: + ftpc->count2 = -1; /* subtract one to get next */ + ftpc->count1 = 1; + break; + default: + failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d", + (int)data->set.ftpsslauth); + return CURLE_UNKNOWN_OPTION; /* we don't know what to do */ + } + result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s", + ftpauth[ftpc->count1]); + if(!result) + state(data, FTP_AUTH); + } + else + result = ftp_state_user(data, conn); + break; + + case FTP_AUTH: + /* we have gotten the response to a previous AUTH command */ + + /* RFC2228 (page 5) says: + * + * If the server is willing to accept the named security mechanism, + * and does not require any security data, it must respond with + * reply code 234/334. + */ + + if((ftpcode == 234) || (ftpcode == 334)) { + /* Curl_ssl_connect is BLOCKING */ + result = Curl_ssl_connect(data, conn, FIRSTSOCKET); + if(!result) { + conn->bits.ftp_use_data_ssl = FALSE; /* clear-text data */ + conn->bits.ftp_use_control_ssl = TRUE; /* SSL on control */ + result = ftp_state_user(data, conn); + } + } + else if(ftpc->count3 < 1) { + ftpc->count3++; + ftpc->count1 += ftpc->count2; /* get next attempt */ + result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s", + ftpauth[ftpc->count1]); + /* remain in this same state */ + } + else { + if(data->set.use_ssl > CURLUSESSL_TRY) + /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */ + result = CURLE_USE_SSL_FAILED; + else + /* ignore the failure and continue */ + result = ftp_state_user(data, conn); + } + break; + + case FTP_USER: + case FTP_PASS: + result = ftp_state_user_resp(data, ftpcode, ftpc->state); + break; + + case FTP_ACCT: + result = ftp_state_acct_resp(data, ftpcode); + break; + + case FTP_PBSZ: + result = + Curl_pp_sendf(data, &ftpc->pp, "PROT %c", + data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P'); + if(!result) + state(data, FTP_PROT); + break; + + case FTP_PROT: + if(ftpcode/100 == 2) + /* We have enabled SSL for the data connection! */ + conn->bits.ftp_use_data_ssl = + (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE; + /* FTP servers typically responds with 500 if they decide to reject + our 'P' request */ + else if(data->set.use_ssl > CURLUSESSL_CONTROL) + /* we failed and bails out */ + return CURLE_USE_SSL_FAILED; + + if(data->set.ftp_ccc) { + /* CCC - Clear Command Channel + */ + result = Curl_pp_sendf(data, &ftpc->pp, "%s", "CCC"); + if(!result) + state(data, FTP_CCC); + } + else + result = ftp_state_pwd(data, conn); + break; + + case FTP_CCC: + if(ftpcode < 500) { + /* First shut down the SSL layer (note: this call will block) */ + result = Curl_ssl_shutdown(data, conn, FIRSTSOCKET); + + if(result) + failf(data, "Failed to clear the command channel (CCC)"); + } + if(!result) + /* Then continue as normal */ + result = ftp_state_pwd(data, conn); + break; + + case FTP_PWD: + if(ftpcode == 257) { + char *ptr = &data->state.buffer[4]; /* start on the first letter */ + const size_t buf_size = data->set.buffer_size; + char *dir; + bool entry_extracted = FALSE; + + dir = malloc(nread + 1); + if(!dir) + return CURLE_OUT_OF_MEMORY; + + /* Reply format is like + 257[rubbish]"" and the + RFC959 says + + The directory name can contain any character; embedded + double-quotes should be escaped by double-quotes (the + "quote-doubling" convention). + */ + + /* scan for the first double-quote for non-standard responses */ + while(ptr < &data->state.buffer[buf_size] + && *ptr != '\n' && *ptr != '\0' && *ptr != '"') + ptr++; + + if('\"' == *ptr) { + /* it started good */ + char *store; + ptr++; + for(store = dir; *ptr;) { + if('\"' == *ptr) { + if('\"' == ptr[1]) { + /* "quote-doubling" */ + *store = ptr[1]; + ptr++; + } + else { + /* end of path */ + entry_extracted = TRUE; + break; /* get out of this loop */ + } + } + else + *store = *ptr; + store++; + ptr++; + } + *store = '\0'; /* null-terminate */ + } + if(entry_extracted) { + /* If the path name does not look like an absolute path (i.e.: it + does not start with a '/'), we probably need some server-dependent + adjustments. For example, this is the case when connecting to + an OS400 FTP server: this server supports two name syntaxes, + the default one being incompatible with standard paths. In + addition, this server switches automatically to the regular path + syntax when one is encountered in a command: this results in + having an entrypath in the wrong syntax when later used in CWD. + The method used here is to check the server OS: we do it only + if the path name looks strange to minimize overhead on other + systems. */ + + if(!ftpc->server_os && dir[0] != '/') { + result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SYST"); + if(result) { + free(dir); + return result; + } + Curl_safefree(ftpc->entrypath); + ftpc->entrypath = dir; /* remember this */ + infof(data, "Entry path is '%s'", ftpc->entrypath); + /* also save it where getinfo can access it: */ + data->state.most_recent_ftp_entrypath = ftpc->entrypath; + state(data, FTP_SYST); + break; + } + + Curl_safefree(ftpc->entrypath); + ftpc->entrypath = dir; /* remember this */ + infof(data, "Entry path is '%s'", ftpc->entrypath); + /* also save it where getinfo can access it: */ + data->state.most_recent_ftp_entrypath = ftpc->entrypath; + } + else { + /* couldn't get the path */ + free(dir); + infof(data, "Failed to figure out path"); + } + } + state(data, FTP_STOP); /* we are done with the CONNECT phase! */ + DEBUGF(infof(data, "protocol connect phase DONE")); + break; + + case FTP_SYST: + if(ftpcode == 215) { + char *ptr = &data->state.buffer[4]; /* start on the first letter */ + char *os; + char *store; + + os = malloc(nread + 1); + if(!os) + return CURLE_OUT_OF_MEMORY; + + /* Reply format is like + 215 + */ + while(*ptr == ' ') + ptr++; + for(store = os; *ptr && *ptr != ' ';) + *store++ = *ptr++; + *store = '\0'; /* null-terminate */ + + /* Check for special servers here. */ + + if(strcasecompare(os, "OS/400")) { + /* Force OS400 name format 1. */ + result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SITE NAMEFMT 1"); + if(result) { + free(os); + return result; + } + /* remember target server OS */ + Curl_safefree(ftpc->server_os); + ftpc->server_os = os; + state(data, FTP_NAMEFMT); + break; + } + /* Nothing special for the target server. */ + /* remember target server OS */ + Curl_safefree(ftpc->server_os); + ftpc->server_os = os; + } + else { + /* Cannot identify server OS. Continue anyway and cross fingers. */ + } + + state(data, FTP_STOP); /* we are done with the CONNECT phase! */ + DEBUGF(infof(data, "protocol connect phase DONE")); + break; + + case FTP_NAMEFMT: + if(ftpcode == 250) { + /* Name format change successful: reload initial path. */ + ftp_state_pwd(data, conn); + break; + } + + state(data, FTP_STOP); /* we are done with the CONNECT phase! */ + DEBUGF(infof(data, "protocol connect phase DONE")); + break; + + case FTP_QUOTE: + case FTP_POSTQUOTE: + case FTP_RETR_PREQUOTE: + case FTP_STOR_PREQUOTE: + if((ftpcode >= 400) && !ftpc->count2) { + /* failure response code, and not allowed to fail */ + failf(data, "QUOT command failed with %03d", ftpcode); + result = CURLE_QUOTE_ERROR; + } + else + result = ftp_state_quote(data, FALSE, ftpc->state); + break; + + case FTP_CWD: + if(ftpcode/100 != 2) { + /* failure to CWD there */ + if(data->set.ftp_create_missing_dirs && + ftpc->cwdcount && !ftpc->count2) { + /* try making it */ + ftpc->count2++; /* counter to prevent CWD-MKD loops */ + result = Curl_pp_sendf(data, &ftpc->pp, "MKD %s", + ftpc->dirs[ftpc->cwdcount - 1]); + if(!result) + state(data, FTP_MKD); + } + else { + /* return failure */ + failf(data, "Server denied you to change to the given directory"); + ftpc->cwdfail = TRUE; /* don't remember this path as we failed + to enter it */ + result = CURLE_REMOTE_ACCESS_DENIED; + } + } + else { + /* success */ + ftpc->count2 = 0; + if(++ftpc->cwdcount <= ftpc->dirdepth) + /* send next CWD */ + result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", + ftpc->dirs[ftpc->cwdcount - 1]); + else + result = ftp_state_mdtm(data); + } + break; + + case FTP_MKD: + if((ftpcode/100 != 2) && !ftpc->count3--) { + /* failure to MKD the dir */ + failf(data, "Failed to MKD dir: %03d", ftpcode); + result = CURLE_REMOTE_ACCESS_DENIED; + } + else { + state(data, FTP_CWD); + /* send CWD */ + result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", + ftpc->dirs[ftpc->cwdcount - 1]); + } + break; + + case FTP_MDTM: + result = ftp_state_mdtm_resp(data, ftpcode); + break; + + case FTP_TYPE: + case FTP_LIST_TYPE: + case FTP_RETR_TYPE: + case FTP_STOR_TYPE: + result = ftp_state_type_resp(data, ftpcode, ftpc->state); + break; + + case FTP_SIZE: + case FTP_RETR_SIZE: + case FTP_STOR_SIZE: + result = ftp_state_size_resp(data, ftpcode, ftpc->state); + break; + + case FTP_REST: + case FTP_RETR_REST: + result = ftp_state_rest_resp(data, conn, ftpcode, ftpc->state); + break; + + case FTP_PRET: + if(ftpcode != 200) { + /* there only is this one standard OK return code. */ + failf(data, "PRET command not accepted: %03d", ftpcode); + return CURLE_FTP_PRET_FAILED; + } + result = ftp_state_use_pasv(data, conn); + break; + + case FTP_PASV: + result = ftp_state_pasv_resp(data, ftpcode); + break; + + case FTP_PORT: + result = ftp_state_port_resp(data, ftpcode); + break; + + case FTP_LIST: + case FTP_RETR: + result = ftp_state_get_resp(data, ftpcode, ftpc->state); + break; + + case FTP_STOR: + result = ftp_state_stor_resp(data, ftpcode, ftpc->state); + break; + + case FTP_QUIT: + /* fallthrough, just stop! */ + default: + /* internal error */ + state(data, FTP_STOP); + break; + } + } /* if(ftpcode) */ + + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22946/vuln.c b/benchmarks/pairs/vfc/curl-cve-2021-22946/vuln.c new file mode 100644 index 0000000..ae0d14d --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22946/vuln.c @@ -0,0 +1,446 @@ +/* Provenance: curl/curl ftp_statemachine (vuln). + * repo: curl/curl + * commit: 43157490a5054bd24256fe12876931e8abc9df49 + * parent: 43157490a5054bd24256fe12876931e8abc9df49 + * commit_url: https://github.com/curl/curl/commit/364f174724ef115c63d5e5dc1d3342c8a43b1cca + * cve: CVE-2021-22946 + * license: curl + * function: ftp_statemachine + * relpath: lib/ftp.c + */ + +static CURLcode ftp_statemachine(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result; + curl_socket_t sock = conn->sock[FIRSTSOCKET]; + int ftpcode; + struct ftp_conn *ftpc = &conn->proto.ftpc; + struct pingpong *pp = &ftpc->pp; + static const char ftpauth[][4] = { "SSL", "TLS" }; + size_t nread = 0; + + if(pp->sendleft) + return Curl_pp_flushsend(data, pp); + + result = ftp_readresp(data, sock, pp, &ftpcode, &nread); + if(result) + return result; + + if(ftpcode) { + /* we have now received a full FTP server response */ + switch(ftpc->state) { + case FTP_WAIT220: + if(ftpcode == 230) + /* 230 User logged in - already! */ + return ftp_state_user_resp(data, ftpcode, ftpc->state); + else if(ftpcode != 220) { + failf(data, "Got a %03d ftp-server response when 220 was expected", + ftpcode); + return CURLE_WEIRD_SERVER_REPLY; + } + + /* We have received a 220 response fine, now we proceed. */ +#ifdef HAVE_GSSAPI + if(data->set.krb) { + /* If not anonymous login, try a secure login. Note that this + procedure is still BLOCKING. */ + + Curl_sec_request_prot(conn, "private"); + /* We set private first as default, in case the line below fails to + set a valid level */ + Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]); + + if(Curl_sec_login(data, conn)) + infof(data, "Logging in with password in cleartext!"); + else + infof(data, "Authentication successful"); + } +#endif + + if(data->set.use_ssl && !conn->bits.ftp_use_control_ssl) { + /* We don't have a SSL/TLS control connection yet, but FTPS is + requested. Try a FTPS connection now */ + + ftpc->count3 = 0; + switch(data->set.ftpsslauth) { + case CURLFTPAUTH_DEFAULT: + case CURLFTPAUTH_SSL: + ftpc->count2 = 1; /* add one to get next */ + ftpc->count1 = 0; + break; + case CURLFTPAUTH_TLS: + ftpc->count2 = -1; /* subtract one to get next */ + ftpc->count1 = 1; + break; + default: + failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d", + (int)data->set.ftpsslauth); + return CURLE_UNKNOWN_OPTION; /* we don't know what to do */ + } + result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s", + ftpauth[ftpc->count1]); + if(!result) + state(data, FTP_AUTH); + } + else + result = ftp_state_user(data, conn); + break; + + case FTP_AUTH: + /* we have gotten the response to a previous AUTH command */ + + /* RFC2228 (page 5) says: + * + * If the server is willing to accept the named security mechanism, + * and does not require any security data, it must respond with + * reply code 234/334. + */ + + if((ftpcode == 234) || (ftpcode == 334)) { + /* Curl_ssl_connect is BLOCKING */ + result = Curl_ssl_connect(data, conn, FIRSTSOCKET); + if(!result) { + conn->bits.ftp_use_data_ssl = FALSE; /* clear-text data */ + conn->bits.ftp_use_control_ssl = TRUE; /* SSL on control */ + result = ftp_state_user(data, conn); + } + } + else if(ftpc->count3 < 1) { + ftpc->count3++; + ftpc->count1 += ftpc->count2; /* get next attempt */ + result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s", + ftpauth[ftpc->count1]); + /* remain in this same state */ + } + else { + if(data->set.use_ssl > CURLUSESSL_TRY) + /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */ + result = CURLE_USE_SSL_FAILED; + else + /* ignore the failure and continue */ + result = ftp_state_user(data, conn); + } + break; + + case FTP_USER: + case FTP_PASS: + result = ftp_state_user_resp(data, ftpcode, ftpc->state); + break; + + case FTP_ACCT: + result = ftp_state_acct_resp(data, ftpcode); + break; + + case FTP_PBSZ: + result = + Curl_pp_sendf(data, &ftpc->pp, "PROT %c", + data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P'); + if(!result) + state(data, FTP_PROT); + break; + + case FTP_PROT: + if(ftpcode/100 == 2) + /* We have enabled SSL for the data connection! */ + conn->bits.ftp_use_data_ssl = + (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE; + /* FTP servers typically responds with 500 if they decide to reject + our 'P' request */ + else if(data->set.use_ssl > CURLUSESSL_CONTROL) + /* we failed and bails out */ + return CURLE_USE_SSL_FAILED; + + if(data->set.ftp_ccc) { + /* CCC - Clear Command Channel + */ + result = Curl_pp_sendf(data, &ftpc->pp, "%s", "CCC"); + if(!result) + state(data, FTP_CCC); + } + else + result = ftp_state_pwd(data, conn); + break; + + case FTP_CCC: + if(ftpcode < 500) { + /* First shut down the SSL layer (note: this call will block) */ + result = Curl_ssl_shutdown(data, conn, FIRSTSOCKET); + + if(result) + failf(data, "Failed to clear the command channel (CCC)"); + } + if(!result) + /* Then continue as normal */ + result = ftp_state_pwd(data, conn); + break; + + case FTP_PWD: + if(ftpcode == 257) { + char *ptr = &data->state.buffer[4]; /* start on the first letter */ + const size_t buf_size = data->set.buffer_size; + char *dir; + bool entry_extracted = FALSE; + + dir = malloc(nread + 1); + if(!dir) + return CURLE_OUT_OF_MEMORY; + + /* Reply format is like + 257[rubbish]"" and the + RFC959 says + + The directory name can contain any character; embedded + double-quotes should be escaped by double-quotes (the + "quote-doubling" convention). + */ + + /* scan for the first double-quote for non-standard responses */ + while(ptr < &data->state.buffer[buf_size] + && *ptr != '\n' && *ptr != '\0' && *ptr != '"') + ptr++; + + if('\"' == *ptr) { + /* it started good */ + char *store; + ptr++; + for(store = dir; *ptr;) { + if('\"' == *ptr) { + if('\"' == ptr[1]) { + /* "quote-doubling" */ + *store = ptr[1]; + ptr++; + } + else { + /* end of path */ + entry_extracted = TRUE; + break; /* get out of this loop */ + } + } + else + *store = *ptr; + store++; + ptr++; + } + *store = '\0'; /* null-terminate */ + } + if(entry_extracted) { + /* If the path name does not look like an absolute path (i.e.: it + does not start with a '/'), we probably need some server-dependent + adjustments. For example, this is the case when connecting to + an OS400 FTP server: this server supports two name syntaxes, + the default one being incompatible with standard paths. In + addition, this server switches automatically to the regular path + syntax when one is encountered in a command: this results in + having an entrypath in the wrong syntax when later used in CWD. + The method used here is to check the server OS: we do it only + if the path name looks strange to minimize overhead on other + systems. */ + + if(!ftpc->server_os && dir[0] != '/') { + result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SYST"); + if(result) { + free(dir); + return result; + } + Curl_safefree(ftpc->entrypath); + ftpc->entrypath = dir; /* remember this */ + infof(data, "Entry path is '%s'", ftpc->entrypath); + /* also save it where getinfo can access it: */ + data->state.most_recent_ftp_entrypath = ftpc->entrypath; + state(data, FTP_SYST); + break; + } + + Curl_safefree(ftpc->entrypath); + ftpc->entrypath = dir; /* remember this */ + infof(data, "Entry path is '%s'", ftpc->entrypath); + /* also save it where getinfo can access it: */ + data->state.most_recent_ftp_entrypath = ftpc->entrypath; + } + else { + /* couldn't get the path */ + free(dir); + infof(data, "Failed to figure out path"); + } + } + state(data, FTP_STOP); /* we are done with the CONNECT phase! */ + DEBUGF(infof(data, "protocol connect phase DONE")); + break; + + case FTP_SYST: + if(ftpcode == 215) { + char *ptr = &data->state.buffer[4]; /* start on the first letter */ + char *os; + char *store; + + os = malloc(nread + 1); + if(!os) + return CURLE_OUT_OF_MEMORY; + + /* Reply format is like + 215 + */ + while(*ptr == ' ') + ptr++; + for(store = os; *ptr && *ptr != ' ';) + *store++ = *ptr++; + *store = '\0'; /* null-terminate */ + + /* Check for special servers here. */ + + if(strcasecompare(os, "OS/400")) { + /* Force OS400 name format 1. */ + result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SITE NAMEFMT 1"); + if(result) { + free(os); + return result; + } + /* remember target server OS */ + Curl_safefree(ftpc->server_os); + ftpc->server_os = os; + state(data, FTP_NAMEFMT); + break; + } + /* Nothing special for the target server. */ + /* remember target server OS */ + Curl_safefree(ftpc->server_os); + ftpc->server_os = os; + } + else { + /* Cannot identify server OS. Continue anyway and cross fingers. */ + } + + state(data, FTP_STOP); /* we are done with the CONNECT phase! */ + DEBUGF(infof(data, "protocol connect phase DONE")); + break; + + case FTP_NAMEFMT: + if(ftpcode == 250) { + /* Name format change successful: reload initial path. */ + ftp_state_pwd(data, conn); + break; + } + + state(data, FTP_STOP); /* we are done with the CONNECT phase! */ + DEBUGF(infof(data, "protocol connect phase DONE")); + break; + + case FTP_QUOTE: + case FTP_POSTQUOTE: + case FTP_RETR_PREQUOTE: + case FTP_STOR_PREQUOTE: + if((ftpcode >= 400) && !ftpc->count2) { + /* failure response code, and not allowed to fail */ + failf(data, "QUOT command failed with %03d", ftpcode); + result = CURLE_QUOTE_ERROR; + } + else + result = ftp_state_quote(data, FALSE, ftpc->state); + break; + + case FTP_CWD: + if(ftpcode/100 != 2) { + /* failure to CWD there */ + if(data->set.ftp_create_missing_dirs && + ftpc->cwdcount && !ftpc->count2) { + /* try making it */ + ftpc->count2++; /* counter to prevent CWD-MKD loops */ + result = Curl_pp_sendf(data, &ftpc->pp, "MKD %s", + ftpc->dirs[ftpc->cwdcount - 1]); + if(!result) + state(data, FTP_MKD); + } + else { + /* return failure */ + failf(data, "Server denied you to change to the given directory"); + ftpc->cwdfail = TRUE; /* don't remember this path as we failed + to enter it */ + result = CURLE_REMOTE_ACCESS_DENIED; + } + } + else { + /* success */ + ftpc->count2 = 0; + if(++ftpc->cwdcount <= ftpc->dirdepth) + /* send next CWD */ + result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", + ftpc->dirs[ftpc->cwdcount - 1]); + else + result = ftp_state_mdtm(data); + } + break; + + case FTP_MKD: + if((ftpcode/100 != 2) && !ftpc->count3--) { + /* failure to MKD the dir */ + failf(data, "Failed to MKD dir: %03d", ftpcode); + result = CURLE_REMOTE_ACCESS_DENIED; + } + else { + state(data, FTP_CWD); + /* send CWD */ + result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", + ftpc->dirs[ftpc->cwdcount - 1]); + } + break; + + case FTP_MDTM: + result = ftp_state_mdtm_resp(data, ftpcode); + break; + + case FTP_TYPE: + case FTP_LIST_TYPE: + case FTP_RETR_TYPE: + case FTP_STOR_TYPE: + result = ftp_state_type_resp(data, ftpcode, ftpc->state); + break; + + case FTP_SIZE: + case FTP_RETR_SIZE: + case FTP_STOR_SIZE: + result = ftp_state_size_resp(data, ftpcode, ftpc->state); + break; + + case FTP_REST: + case FTP_RETR_REST: + result = ftp_state_rest_resp(data, conn, ftpcode, ftpc->state); + break; + + case FTP_PRET: + if(ftpcode != 200) { + /* there only is this one standard OK return code. */ + failf(data, "PRET command not accepted: %03d", ftpcode); + return CURLE_FTP_PRET_FAILED; + } + result = ftp_state_use_pasv(data, conn); + break; + + case FTP_PASV: + result = ftp_state_pasv_resp(data, ftpcode); + break; + + case FTP_PORT: + result = ftp_state_port_resp(data, ftpcode); + break; + + case FTP_LIST: + case FTP_RETR: + result = ftp_state_get_resp(data, ftpcode, ftpc->state); + break; + + case FTP_STOR: + result = ftp_state_stor_resp(data, ftpcode, ftpc->state); + break; + + case FTP_QUIT: + /* fallthrough, just stop! */ + default: + /* internal error */ + state(data, FTP_STOP); + break; + } + } /* if(ftpcode) */ + + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22947-imap_state_starttls_resp/fixed.c b/benchmarks/pairs/vfc/curl-cve-2021-22947-imap_state_starttls_resp/fixed.c new file mode 100644 index 0000000..7b764dc --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22947-imap_state_starttls_resp/fixed.c @@ -0,0 +1,37 @@ +/* Provenance: curl/curl imap_state_starttls_resp (fixed). + * repo: curl/curl + * commit: 8ef147c43646e91fdaad5d0e7b60351f842e5c68 + * parent: 364f174724ef115c63d5e5dc1d3342c8a43b1cca + * commit_url: https://github.com/curl/curl/commit/8ef147c43646e91fdaad5d0e7b60351f842e5c68 + * cve: CVE-2021-22947 + * license: curl + * function: imap_state_starttls_resp + * relpath: lib/imap.c + */ + +static CURLcode imap_state_starttls_resp(struct Curl_easy *data, + int imapcode, + imapstate instate) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + + (void)instate; /* no use for this yet */ + + /* Pipelining in response is forbidden. */ + if(data->conn->proto.imapc.pp.cache_size) + return CURLE_WEIRD_SERVER_REPLY; + + if(imapcode != IMAP_RESP_OK) { + if(data->set.use_ssl != CURLUSESSL_TRY) { + failf(data, "STARTTLS denied"); + result = CURLE_USE_SSL_FAILED; + } + else + result = imap_perform_authentication(data, conn); + } + else + result = imap_perform_upgrade_tls(data, conn); + + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22947-imap_state_starttls_resp/vuln.c b/benchmarks/pairs/vfc/curl-cve-2021-22947-imap_state_starttls_resp/vuln.c new file mode 100644 index 0000000..b89e9bd --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22947-imap_state_starttls_resp/vuln.c @@ -0,0 +1,33 @@ +/* Provenance: curl/curl imap_state_starttls_resp (vuln). + * repo: curl/curl + * commit: 364f174724ef115c63d5e5dc1d3342c8a43b1cca + * parent: 364f174724ef115c63d5e5dc1d3342c8a43b1cca + * commit_url: https://github.com/curl/curl/commit/8ef147c43646e91fdaad5d0e7b60351f842e5c68 + * cve: CVE-2021-22947 + * license: curl + * function: imap_state_starttls_resp + * relpath: lib/imap.c + */ + +static CURLcode imap_state_starttls_resp(struct Curl_easy *data, + int imapcode, + imapstate instate) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + + (void)instate; /* no use for this yet */ + + if(imapcode != IMAP_RESP_OK) { + if(data->set.use_ssl != CURLUSESSL_TRY) { + failf(data, "STARTTLS denied"); + result = CURLE_USE_SSL_FAILED; + } + else + result = imap_perform_authentication(data, conn); + } + else + result = imap_perform_upgrade_tls(data, conn); + + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22947-pop3_state_starttls_resp/fixed.c b/benchmarks/pairs/vfc/curl-cve-2021-22947-pop3_state_starttls_resp/fixed.c new file mode 100644 index 0000000..0706032 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22947-pop3_state_starttls_resp/fixed.c @@ -0,0 +1,36 @@ +/* Provenance: curl/curl pop3_state_starttls_resp (fixed). + * repo: curl/curl + * commit: 8ef147c43646e91fdaad5d0e7b60351f842e5c68 + * parent: 364f174724ef115c63d5e5dc1d3342c8a43b1cca + * commit_url: https://github.com/curl/curl/commit/8ef147c43646e91fdaad5d0e7b60351f842e5c68 + * cve: CVE-2021-22947 + * license: curl + * function: pop3_state_starttls_resp + * relpath: lib/pop3.c + */ + +static CURLcode pop3_state_starttls_resp(struct Curl_easy *data, + struct connectdata *conn, + int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + (void)instate; /* no use for this yet */ + + /* Pipelining in response is forbidden. */ + if(data->conn->proto.pop3c.pp.cache_size) + return CURLE_WEIRD_SERVER_REPLY; + + if(pop3code != '+') { + if(data->set.use_ssl != CURLUSESSL_TRY) { + failf(data, "STARTTLS denied"); + result = CURLE_USE_SSL_FAILED; + } + else + result = pop3_perform_authentication(data, conn); + } + else + result = pop3_perform_upgrade_tls(data, conn); + + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22947-pop3_state_starttls_resp/vuln.c b/benchmarks/pairs/vfc/curl-cve-2021-22947-pop3_state_starttls_resp/vuln.c new file mode 100644 index 0000000..5d0d58f --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22947-pop3_state_starttls_resp/vuln.c @@ -0,0 +1,32 @@ +/* Provenance: curl/curl pop3_state_starttls_resp (vuln). + * repo: curl/curl + * commit: 364f174724ef115c63d5e5dc1d3342c8a43b1cca + * parent: 364f174724ef115c63d5e5dc1d3342c8a43b1cca + * commit_url: https://github.com/curl/curl/commit/8ef147c43646e91fdaad5d0e7b60351f842e5c68 + * cve: CVE-2021-22947 + * license: curl + * function: pop3_state_starttls_resp + * relpath: lib/pop3.c + */ + +static CURLcode pop3_state_starttls_resp(struct Curl_easy *data, + struct connectdata *conn, + int pop3code, + pop3state instate) +{ + CURLcode result = CURLE_OK; + (void)instate; /* no use for this yet */ + + if(pop3code != '+') { + if(data->set.use_ssl != CURLUSESSL_TRY) { + failf(data, "STARTTLS denied"); + result = CURLE_USE_SSL_FAILED; + } + else + result = pop3_perform_authentication(data, conn); + } + else + result = pop3_perform_upgrade_tls(data, conn); + + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22947-smtp_state_starttls_resp/fixed.c b/benchmarks/pairs/vfc/curl-cve-2021-22947-smtp_state_starttls_resp/fixed.c new file mode 100644 index 0000000..d821c8e --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22947-smtp_state_starttls_resp/fixed.c @@ -0,0 +1,35 @@ +/* Provenance: curl/curl smtp_state_starttls_resp (fixed). + * repo: curl/curl + * commit: 8ef147c43646e91fdaad5d0e7b60351f842e5c68 + * parent: 364f174724ef115c63d5e5dc1d3342c8a43b1cca + * commit_url: https://github.com/curl/curl/commit/8ef147c43646e91fdaad5d0e7b60351f842e5c68 + * cve: CVE-2021-22947 + * license: curl + * function: smtp_state_starttls_resp + * relpath: lib/smtp.c + */ + +static CURLcode smtp_state_starttls_resp(struct Curl_easy *data, + int smtpcode, + smtpstate instate) +{ + CURLcode result = CURLE_OK; + (void)instate; /* no use for this yet */ + + /* Pipelining in response is forbidden. */ + if(data->conn->proto.smtpc.pp.cache_size) + return CURLE_WEIRD_SERVER_REPLY; + + if(smtpcode != 220) { + if(data->set.use_ssl != CURLUSESSL_TRY) { + failf(data, "STARTTLS denied, code %d", smtpcode); + result = CURLE_USE_SSL_FAILED; + } + else + result = smtp_perform_authentication(data); + } + else + result = smtp_perform_upgrade_tls(data); + + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22947-smtp_state_starttls_resp/vuln.c b/benchmarks/pairs/vfc/curl-cve-2021-22947-smtp_state_starttls_resp/vuln.c new file mode 100644 index 0000000..ff7cbce --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22947-smtp_state_starttls_resp/vuln.c @@ -0,0 +1,31 @@ +/* Provenance: curl/curl smtp_state_starttls_resp (vuln). + * repo: curl/curl + * commit: 364f174724ef115c63d5e5dc1d3342c8a43b1cca + * parent: 364f174724ef115c63d5e5dc1d3342c8a43b1cca + * commit_url: https://github.com/curl/curl/commit/8ef147c43646e91fdaad5d0e7b60351f842e5c68 + * cve: CVE-2021-22947 + * license: curl + * function: smtp_state_starttls_resp + * relpath: lib/smtp.c + */ + +static CURLcode smtp_state_starttls_resp(struct Curl_easy *data, + int smtpcode, + smtpstate instate) +{ + CURLcode result = CURLE_OK; + (void)instate; /* no use for this yet */ + + if(smtpcode != 220) { + if(data->set.use_ssl != CURLUSESSL_TRY) { + failf(data, "STARTTLS denied, code %d", smtpcode); + result = CURLE_USE_SSL_FAILED; + } + else + result = smtp_perform_authentication(data); + } + else + result = smtp_perform_upgrade_tls(data); + + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22947/fixed.c b/benchmarks/pairs/vfc/curl-cve-2021-22947/fixed.c new file mode 100644 index 0000000..c2b6734 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22947/fixed.c @@ -0,0 +1,452 @@ +/* Provenance: curl/curl ftp_statemachine (fixed). + * repo: curl/curl + * commit: 8ef147c43646e91fdaad5d0e7b60351f842e5c68 + * parent: 364f174724ef115c63d5e5dc1d3342c8a43b1cca + * commit_url: https://github.com/curl/curl/commit/8ef147c43646e91fdaad5d0e7b60351f842e5c68 + * cve: CVE-2021-22947 + * license: curl + * function: ftp_statemachine + * relpath: lib/ftp.c + */ + +static CURLcode ftp_statemachine(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result; + curl_socket_t sock = conn->sock[FIRSTSOCKET]; + int ftpcode; + struct ftp_conn *ftpc = &conn->proto.ftpc; + struct pingpong *pp = &ftpc->pp; + static const char ftpauth[][4] = { "SSL", "TLS" }; + size_t nread = 0; + + if(pp->sendleft) + return Curl_pp_flushsend(data, pp); + + result = ftp_readresp(data, sock, pp, &ftpcode, &nread); + if(result) + return result; + + if(ftpcode) { + /* we have now received a full FTP server response */ + switch(ftpc->state) { + case FTP_WAIT220: + if(ftpcode == 230) { + /* 230 User logged in - already! Take as 220 if TLS required. */ + if(data->set.use_ssl <= CURLUSESSL_TRY || + conn->bits.ftp_use_control_ssl) + return ftp_state_user_resp(data, ftpcode, ftpc->state); + } + else if(ftpcode != 220) { + failf(data, "Got a %03d ftp-server response when 220 was expected", + ftpcode); + return CURLE_WEIRD_SERVER_REPLY; + } + + /* We have received a 220 response fine, now we proceed. */ +#ifdef HAVE_GSSAPI + if(data->set.krb) { + /* If not anonymous login, try a secure login. Note that this + procedure is still BLOCKING. */ + + Curl_sec_request_prot(conn, "private"); + /* We set private first as default, in case the line below fails to + set a valid level */ + Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]); + + if(Curl_sec_login(data, conn)) + infof(data, "Logging in with password in cleartext!"); + else + infof(data, "Authentication successful"); + } +#endif + + if(data->set.use_ssl && !conn->bits.ftp_use_control_ssl) { + /* We don't have a SSL/TLS control connection yet, but FTPS is + requested. Try a FTPS connection now */ + + ftpc->count3 = 0; + switch(data->set.ftpsslauth) { + case CURLFTPAUTH_DEFAULT: + case CURLFTPAUTH_SSL: + ftpc->count2 = 1; /* add one to get next */ + ftpc->count1 = 0; + break; + case CURLFTPAUTH_TLS: + ftpc->count2 = -1; /* subtract one to get next */ + ftpc->count1 = 1; + break; + default: + failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d", + (int)data->set.ftpsslauth); + return CURLE_UNKNOWN_OPTION; /* we don't know what to do */ + } + result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s", + ftpauth[ftpc->count1]); + if(!result) + state(data, FTP_AUTH); + } + else + result = ftp_state_user(data, conn); + break; + + case FTP_AUTH: + /* we have gotten the response to a previous AUTH command */ + + if(pp->cache_size) + return CURLE_WEIRD_SERVER_REPLY; /* Forbid pipelining in response. */ + + /* RFC2228 (page 5) says: + * + * If the server is willing to accept the named security mechanism, + * and does not require any security data, it must respond with + * reply code 234/334. + */ + + if((ftpcode == 234) || (ftpcode == 334)) { + /* Curl_ssl_connect is BLOCKING */ + result = Curl_ssl_connect(data, conn, FIRSTSOCKET); + if(!result) { + conn->bits.ftp_use_data_ssl = FALSE; /* clear-text data */ + conn->bits.ftp_use_control_ssl = TRUE; /* SSL on control */ + result = ftp_state_user(data, conn); + } + } + else if(ftpc->count3 < 1) { + ftpc->count3++; + ftpc->count1 += ftpc->count2; /* get next attempt */ + result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s", + ftpauth[ftpc->count1]); + /* remain in this same state */ + } + else { + if(data->set.use_ssl > CURLUSESSL_TRY) + /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */ + result = CURLE_USE_SSL_FAILED; + else + /* ignore the failure and continue */ + result = ftp_state_user(data, conn); + } + break; + + case FTP_USER: + case FTP_PASS: + result = ftp_state_user_resp(data, ftpcode, ftpc->state); + break; + + case FTP_ACCT: + result = ftp_state_acct_resp(data, ftpcode); + break; + + case FTP_PBSZ: + result = + Curl_pp_sendf(data, &ftpc->pp, "PROT %c", + data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P'); + if(!result) + state(data, FTP_PROT); + break; + + case FTP_PROT: + if(ftpcode/100 == 2) + /* We have enabled SSL for the data connection! */ + conn->bits.ftp_use_data_ssl = + (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE; + /* FTP servers typically responds with 500 if they decide to reject + our 'P' request */ + else if(data->set.use_ssl > CURLUSESSL_CONTROL) + /* we failed and bails out */ + return CURLE_USE_SSL_FAILED; + + if(data->set.ftp_ccc) { + /* CCC - Clear Command Channel + */ + result = Curl_pp_sendf(data, &ftpc->pp, "%s", "CCC"); + if(!result) + state(data, FTP_CCC); + } + else + result = ftp_state_pwd(data, conn); + break; + + case FTP_CCC: + if(ftpcode < 500) { + /* First shut down the SSL layer (note: this call will block) */ + result = Curl_ssl_shutdown(data, conn, FIRSTSOCKET); + + if(result) + failf(data, "Failed to clear the command channel (CCC)"); + } + if(!result) + /* Then continue as normal */ + result = ftp_state_pwd(data, conn); + break; + + case FTP_PWD: + if(ftpcode == 257) { + char *ptr = &data->state.buffer[4]; /* start on the first letter */ + const size_t buf_size = data->set.buffer_size; + char *dir; + bool entry_extracted = FALSE; + + dir = malloc(nread + 1); + if(!dir) + return CURLE_OUT_OF_MEMORY; + + /* Reply format is like + 257[rubbish]"" and the + RFC959 says + + The directory name can contain any character; embedded + double-quotes should be escaped by double-quotes (the + "quote-doubling" convention). + */ + + /* scan for the first double-quote for non-standard responses */ + while(ptr < &data->state.buffer[buf_size] + && *ptr != '\n' && *ptr != '\0' && *ptr != '"') + ptr++; + + if('\"' == *ptr) { + /* it started good */ + char *store; + ptr++; + for(store = dir; *ptr;) { + if('\"' == *ptr) { + if('\"' == ptr[1]) { + /* "quote-doubling" */ + *store = ptr[1]; + ptr++; + } + else { + /* end of path */ + entry_extracted = TRUE; + break; /* get out of this loop */ + } + } + else + *store = *ptr; + store++; + ptr++; + } + *store = '\0'; /* null-terminate */ + } + if(entry_extracted) { + /* If the path name does not look like an absolute path (i.e.: it + does not start with a '/'), we probably need some server-dependent + adjustments. For example, this is the case when connecting to + an OS400 FTP server: this server supports two name syntaxes, + the default one being incompatible with standard paths. In + addition, this server switches automatically to the regular path + syntax when one is encountered in a command: this results in + having an entrypath in the wrong syntax when later used in CWD. + The method used here is to check the server OS: we do it only + if the path name looks strange to minimize overhead on other + systems. */ + + if(!ftpc->server_os && dir[0] != '/') { + result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SYST"); + if(result) { + free(dir); + return result; + } + Curl_safefree(ftpc->entrypath); + ftpc->entrypath = dir; /* remember this */ + infof(data, "Entry path is '%s'", ftpc->entrypath); + /* also save it where getinfo can access it: */ + data->state.most_recent_ftp_entrypath = ftpc->entrypath; + state(data, FTP_SYST); + break; + } + + Curl_safefree(ftpc->entrypath); + ftpc->entrypath = dir; /* remember this */ + infof(data, "Entry path is '%s'", ftpc->entrypath); + /* also save it where getinfo can access it: */ + data->state.most_recent_ftp_entrypath = ftpc->entrypath; + } + else { + /* couldn't get the path */ + free(dir); + infof(data, "Failed to figure out path"); + } + } + state(data, FTP_STOP); /* we are done with the CONNECT phase! */ + DEBUGF(infof(data, "protocol connect phase DONE")); + break; + + case FTP_SYST: + if(ftpcode == 215) { + char *ptr = &data->state.buffer[4]; /* start on the first letter */ + char *os; + char *store; + + os = malloc(nread + 1); + if(!os) + return CURLE_OUT_OF_MEMORY; + + /* Reply format is like + 215 + */ + while(*ptr == ' ') + ptr++; + for(store = os; *ptr && *ptr != ' ';) + *store++ = *ptr++; + *store = '\0'; /* null-terminate */ + + /* Check for special servers here. */ + + if(strcasecompare(os, "OS/400")) { + /* Force OS400 name format 1. */ + result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SITE NAMEFMT 1"); + if(result) { + free(os); + return result; + } + /* remember target server OS */ + Curl_safefree(ftpc->server_os); + ftpc->server_os = os; + state(data, FTP_NAMEFMT); + break; + } + /* Nothing special for the target server. */ + /* remember target server OS */ + Curl_safefree(ftpc->server_os); + ftpc->server_os = os; + } + else { + /* Cannot identify server OS. Continue anyway and cross fingers. */ + } + + state(data, FTP_STOP); /* we are done with the CONNECT phase! */ + DEBUGF(infof(data, "protocol connect phase DONE")); + break; + + case FTP_NAMEFMT: + if(ftpcode == 250) { + /* Name format change successful: reload initial path. */ + ftp_state_pwd(data, conn); + break; + } + + state(data, FTP_STOP); /* we are done with the CONNECT phase! */ + DEBUGF(infof(data, "protocol connect phase DONE")); + break; + + case FTP_QUOTE: + case FTP_POSTQUOTE: + case FTP_RETR_PREQUOTE: + case FTP_STOR_PREQUOTE: + if((ftpcode >= 400) && !ftpc->count2) { + /* failure response code, and not allowed to fail */ + failf(data, "QUOT command failed with %03d", ftpcode); + result = CURLE_QUOTE_ERROR; + } + else + result = ftp_state_quote(data, FALSE, ftpc->state); + break; + + case FTP_CWD: + if(ftpcode/100 != 2) { + /* failure to CWD there */ + if(data->set.ftp_create_missing_dirs && + ftpc->cwdcount && !ftpc->count2) { + /* try making it */ + ftpc->count2++; /* counter to prevent CWD-MKD loops */ + result = Curl_pp_sendf(data, &ftpc->pp, "MKD %s", + ftpc->dirs[ftpc->cwdcount - 1]); + if(!result) + state(data, FTP_MKD); + } + else { + /* return failure */ + failf(data, "Server denied you to change to the given directory"); + ftpc->cwdfail = TRUE; /* don't remember this path as we failed + to enter it */ + result = CURLE_REMOTE_ACCESS_DENIED; + } + } + else { + /* success */ + ftpc->count2 = 0; + if(++ftpc->cwdcount <= ftpc->dirdepth) + /* send next CWD */ + result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", + ftpc->dirs[ftpc->cwdcount - 1]); + else + result = ftp_state_mdtm(data); + } + break; + + case FTP_MKD: + if((ftpcode/100 != 2) && !ftpc->count3--) { + /* failure to MKD the dir */ + failf(data, "Failed to MKD dir: %03d", ftpcode); + result = CURLE_REMOTE_ACCESS_DENIED; + } + else { + state(data, FTP_CWD); + /* send CWD */ + result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", + ftpc->dirs[ftpc->cwdcount - 1]); + } + break; + + case FTP_MDTM: + result = ftp_state_mdtm_resp(data, ftpcode); + break; + + case FTP_TYPE: + case FTP_LIST_TYPE: + case FTP_RETR_TYPE: + case FTP_STOR_TYPE: + result = ftp_state_type_resp(data, ftpcode, ftpc->state); + break; + + case FTP_SIZE: + case FTP_RETR_SIZE: + case FTP_STOR_SIZE: + result = ftp_state_size_resp(data, ftpcode, ftpc->state); + break; + + case FTP_REST: + case FTP_RETR_REST: + result = ftp_state_rest_resp(data, conn, ftpcode, ftpc->state); + break; + + case FTP_PRET: + if(ftpcode != 200) { + /* there only is this one standard OK return code. */ + failf(data, "PRET command not accepted: %03d", ftpcode); + return CURLE_FTP_PRET_FAILED; + } + result = ftp_state_use_pasv(data, conn); + break; + + case FTP_PASV: + result = ftp_state_pasv_resp(data, ftpcode); + break; + + case FTP_PORT: + result = ftp_state_port_resp(data, ftpcode); + break; + + case FTP_LIST: + case FTP_RETR: + result = ftp_state_get_resp(data, ftpcode, ftpc->state); + break; + + case FTP_STOR: + result = ftp_state_stor_resp(data, ftpcode, ftpc->state); + break; + + case FTP_QUIT: + /* fallthrough, just stop! */ + default: + /* internal error */ + state(data, FTP_STOP); + break; + } + } /* if(ftpcode) */ + + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2021-22947/vuln.c b/benchmarks/pairs/vfc/curl-cve-2021-22947/vuln.c new file mode 100644 index 0000000..ba6219e --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2021-22947/vuln.c @@ -0,0 +1,449 @@ +/* Provenance: curl/curl ftp_statemachine (vuln). + * repo: curl/curl + * commit: 364f174724ef115c63d5e5dc1d3342c8a43b1cca + * parent: 364f174724ef115c63d5e5dc1d3342c8a43b1cca + * commit_url: https://github.com/curl/curl/commit/8ef147c43646e91fdaad5d0e7b60351f842e5c68 + * cve: CVE-2021-22947 + * license: curl + * function: ftp_statemachine + * relpath: lib/ftp.c + */ + +static CURLcode ftp_statemachine(struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result; + curl_socket_t sock = conn->sock[FIRSTSOCKET]; + int ftpcode; + struct ftp_conn *ftpc = &conn->proto.ftpc; + struct pingpong *pp = &ftpc->pp; + static const char ftpauth[][4] = { "SSL", "TLS" }; + size_t nread = 0; + + if(pp->sendleft) + return Curl_pp_flushsend(data, pp); + + result = ftp_readresp(data, sock, pp, &ftpcode, &nread); + if(result) + return result; + + if(ftpcode) { + /* we have now received a full FTP server response */ + switch(ftpc->state) { + case FTP_WAIT220: + if(ftpcode == 230) { + /* 230 User logged in - already! Take as 220 if TLS required. */ + if(data->set.use_ssl <= CURLUSESSL_TRY || + conn->bits.ftp_use_control_ssl) + return ftp_state_user_resp(data, ftpcode, ftpc->state); + } + else if(ftpcode != 220) { + failf(data, "Got a %03d ftp-server response when 220 was expected", + ftpcode); + return CURLE_WEIRD_SERVER_REPLY; + } + + /* We have received a 220 response fine, now we proceed. */ +#ifdef HAVE_GSSAPI + if(data->set.krb) { + /* If not anonymous login, try a secure login. Note that this + procedure is still BLOCKING. */ + + Curl_sec_request_prot(conn, "private"); + /* We set private first as default, in case the line below fails to + set a valid level */ + Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]); + + if(Curl_sec_login(data, conn)) + infof(data, "Logging in with password in cleartext!"); + else + infof(data, "Authentication successful"); + } +#endif + + if(data->set.use_ssl && !conn->bits.ftp_use_control_ssl) { + /* We don't have a SSL/TLS control connection yet, but FTPS is + requested. Try a FTPS connection now */ + + ftpc->count3 = 0; + switch(data->set.ftpsslauth) { + case CURLFTPAUTH_DEFAULT: + case CURLFTPAUTH_SSL: + ftpc->count2 = 1; /* add one to get next */ + ftpc->count1 = 0; + break; + case CURLFTPAUTH_TLS: + ftpc->count2 = -1; /* subtract one to get next */ + ftpc->count1 = 1; + break; + default: + failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d", + (int)data->set.ftpsslauth); + return CURLE_UNKNOWN_OPTION; /* we don't know what to do */ + } + result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s", + ftpauth[ftpc->count1]); + if(!result) + state(data, FTP_AUTH); + } + else + result = ftp_state_user(data, conn); + break; + + case FTP_AUTH: + /* we have gotten the response to a previous AUTH command */ + + /* RFC2228 (page 5) says: + * + * If the server is willing to accept the named security mechanism, + * and does not require any security data, it must respond with + * reply code 234/334. + */ + + if((ftpcode == 234) || (ftpcode == 334)) { + /* Curl_ssl_connect is BLOCKING */ + result = Curl_ssl_connect(data, conn, FIRSTSOCKET); + if(!result) { + conn->bits.ftp_use_data_ssl = FALSE; /* clear-text data */ + conn->bits.ftp_use_control_ssl = TRUE; /* SSL on control */ + result = ftp_state_user(data, conn); + } + } + else if(ftpc->count3 < 1) { + ftpc->count3++; + ftpc->count1 += ftpc->count2; /* get next attempt */ + result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s", + ftpauth[ftpc->count1]); + /* remain in this same state */ + } + else { + if(data->set.use_ssl > CURLUSESSL_TRY) + /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */ + result = CURLE_USE_SSL_FAILED; + else + /* ignore the failure and continue */ + result = ftp_state_user(data, conn); + } + break; + + case FTP_USER: + case FTP_PASS: + result = ftp_state_user_resp(data, ftpcode, ftpc->state); + break; + + case FTP_ACCT: + result = ftp_state_acct_resp(data, ftpcode); + break; + + case FTP_PBSZ: + result = + Curl_pp_sendf(data, &ftpc->pp, "PROT %c", + data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P'); + if(!result) + state(data, FTP_PROT); + break; + + case FTP_PROT: + if(ftpcode/100 == 2) + /* We have enabled SSL for the data connection! */ + conn->bits.ftp_use_data_ssl = + (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE; + /* FTP servers typically responds with 500 if they decide to reject + our 'P' request */ + else if(data->set.use_ssl > CURLUSESSL_CONTROL) + /* we failed and bails out */ + return CURLE_USE_SSL_FAILED; + + if(data->set.ftp_ccc) { + /* CCC - Clear Command Channel + */ + result = Curl_pp_sendf(data, &ftpc->pp, "%s", "CCC"); + if(!result) + state(data, FTP_CCC); + } + else + result = ftp_state_pwd(data, conn); + break; + + case FTP_CCC: + if(ftpcode < 500) { + /* First shut down the SSL layer (note: this call will block) */ + result = Curl_ssl_shutdown(data, conn, FIRSTSOCKET); + + if(result) + failf(data, "Failed to clear the command channel (CCC)"); + } + if(!result) + /* Then continue as normal */ + result = ftp_state_pwd(data, conn); + break; + + case FTP_PWD: + if(ftpcode == 257) { + char *ptr = &data->state.buffer[4]; /* start on the first letter */ + const size_t buf_size = data->set.buffer_size; + char *dir; + bool entry_extracted = FALSE; + + dir = malloc(nread + 1); + if(!dir) + return CURLE_OUT_OF_MEMORY; + + /* Reply format is like + 257[rubbish]"" and the + RFC959 says + + The directory name can contain any character; embedded + double-quotes should be escaped by double-quotes (the + "quote-doubling" convention). + */ + + /* scan for the first double-quote for non-standard responses */ + while(ptr < &data->state.buffer[buf_size] + && *ptr != '\n' && *ptr != '\0' && *ptr != '"') + ptr++; + + if('\"' == *ptr) { + /* it started good */ + char *store; + ptr++; + for(store = dir; *ptr;) { + if('\"' == *ptr) { + if('\"' == ptr[1]) { + /* "quote-doubling" */ + *store = ptr[1]; + ptr++; + } + else { + /* end of path */ + entry_extracted = TRUE; + break; /* get out of this loop */ + } + } + else + *store = *ptr; + store++; + ptr++; + } + *store = '\0'; /* null-terminate */ + } + if(entry_extracted) { + /* If the path name does not look like an absolute path (i.e.: it + does not start with a '/'), we probably need some server-dependent + adjustments. For example, this is the case when connecting to + an OS400 FTP server: this server supports two name syntaxes, + the default one being incompatible with standard paths. In + addition, this server switches automatically to the regular path + syntax when one is encountered in a command: this results in + having an entrypath in the wrong syntax when later used in CWD. + The method used here is to check the server OS: we do it only + if the path name looks strange to minimize overhead on other + systems. */ + + if(!ftpc->server_os && dir[0] != '/') { + result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SYST"); + if(result) { + free(dir); + return result; + } + Curl_safefree(ftpc->entrypath); + ftpc->entrypath = dir; /* remember this */ + infof(data, "Entry path is '%s'", ftpc->entrypath); + /* also save it where getinfo can access it: */ + data->state.most_recent_ftp_entrypath = ftpc->entrypath; + state(data, FTP_SYST); + break; + } + + Curl_safefree(ftpc->entrypath); + ftpc->entrypath = dir; /* remember this */ + infof(data, "Entry path is '%s'", ftpc->entrypath); + /* also save it where getinfo can access it: */ + data->state.most_recent_ftp_entrypath = ftpc->entrypath; + } + else { + /* couldn't get the path */ + free(dir); + infof(data, "Failed to figure out path"); + } + } + state(data, FTP_STOP); /* we are done with the CONNECT phase! */ + DEBUGF(infof(data, "protocol connect phase DONE")); + break; + + case FTP_SYST: + if(ftpcode == 215) { + char *ptr = &data->state.buffer[4]; /* start on the first letter */ + char *os; + char *store; + + os = malloc(nread + 1); + if(!os) + return CURLE_OUT_OF_MEMORY; + + /* Reply format is like + 215 + */ + while(*ptr == ' ') + ptr++; + for(store = os; *ptr && *ptr != ' ';) + *store++ = *ptr++; + *store = '\0'; /* null-terminate */ + + /* Check for special servers here. */ + + if(strcasecompare(os, "OS/400")) { + /* Force OS400 name format 1. */ + result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SITE NAMEFMT 1"); + if(result) { + free(os); + return result; + } + /* remember target server OS */ + Curl_safefree(ftpc->server_os); + ftpc->server_os = os; + state(data, FTP_NAMEFMT); + break; + } + /* Nothing special for the target server. */ + /* remember target server OS */ + Curl_safefree(ftpc->server_os); + ftpc->server_os = os; + } + else { + /* Cannot identify server OS. Continue anyway and cross fingers. */ + } + + state(data, FTP_STOP); /* we are done with the CONNECT phase! */ + DEBUGF(infof(data, "protocol connect phase DONE")); + break; + + case FTP_NAMEFMT: + if(ftpcode == 250) { + /* Name format change successful: reload initial path. */ + ftp_state_pwd(data, conn); + break; + } + + state(data, FTP_STOP); /* we are done with the CONNECT phase! */ + DEBUGF(infof(data, "protocol connect phase DONE")); + break; + + case FTP_QUOTE: + case FTP_POSTQUOTE: + case FTP_RETR_PREQUOTE: + case FTP_STOR_PREQUOTE: + if((ftpcode >= 400) && !ftpc->count2) { + /* failure response code, and not allowed to fail */ + failf(data, "QUOT command failed with %03d", ftpcode); + result = CURLE_QUOTE_ERROR; + } + else + result = ftp_state_quote(data, FALSE, ftpc->state); + break; + + case FTP_CWD: + if(ftpcode/100 != 2) { + /* failure to CWD there */ + if(data->set.ftp_create_missing_dirs && + ftpc->cwdcount && !ftpc->count2) { + /* try making it */ + ftpc->count2++; /* counter to prevent CWD-MKD loops */ + result = Curl_pp_sendf(data, &ftpc->pp, "MKD %s", + ftpc->dirs[ftpc->cwdcount - 1]); + if(!result) + state(data, FTP_MKD); + } + else { + /* return failure */ + failf(data, "Server denied you to change to the given directory"); + ftpc->cwdfail = TRUE; /* don't remember this path as we failed + to enter it */ + result = CURLE_REMOTE_ACCESS_DENIED; + } + } + else { + /* success */ + ftpc->count2 = 0; + if(++ftpc->cwdcount <= ftpc->dirdepth) + /* send next CWD */ + result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", + ftpc->dirs[ftpc->cwdcount - 1]); + else + result = ftp_state_mdtm(data); + } + break; + + case FTP_MKD: + if((ftpcode/100 != 2) && !ftpc->count3--) { + /* failure to MKD the dir */ + failf(data, "Failed to MKD dir: %03d", ftpcode); + result = CURLE_REMOTE_ACCESS_DENIED; + } + else { + state(data, FTP_CWD); + /* send CWD */ + result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", + ftpc->dirs[ftpc->cwdcount - 1]); + } + break; + + case FTP_MDTM: + result = ftp_state_mdtm_resp(data, ftpcode); + break; + + case FTP_TYPE: + case FTP_LIST_TYPE: + case FTP_RETR_TYPE: + case FTP_STOR_TYPE: + result = ftp_state_type_resp(data, ftpcode, ftpc->state); + break; + + case FTP_SIZE: + case FTP_RETR_SIZE: + case FTP_STOR_SIZE: + result = ftp_state_size_resp(data, ftpcode, ftpc->state); + break; + + case FTP_REST: + case FTP_RETR_REST: + result = ftp_state_rest_resp(data, conn, ftpcode, ftpc->state); + break; + + case FTP_PRET: + if(ftpcode != 200) { + /* there only is this one standard OK return code. */ + failf(data, "PRET command not accepted: %03d", ftpcode); + return CURLE_FTP_PRET_FAILED; + } + result = ftp_state_use_pasv(data, conn); + break; + + case FTP_PASV: + result = ftp_state_pasv_resp(data, ftpcode); + break; + + case FTP_PORT: + result = ftp_state_port_resp(data, ftpcode); + break; + + case FTP_LIST: + case FTP_RETR: + result = ftp_state_get_resp(data, ftpcode, ftpc->state); + break; + + case FTP_STOR: + result = ftp_state_stor_resp(data, ftpcode, ftpc->state); + break; + + case FTP_QUIT: + /* fallthrough, just stop! */ + default: + /* internal error */ + state(data, FTP_STOP); + break; + } + } /* if(ftpcode) */ + + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-22576-conn_free/fixed.c b/benchmarks/pairs/vfc/curl-cve-2022-22576-conn_free/fixed.c new file mode 100644 index 0000000..c95938b --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-22576-conn_free/fixed.c @@ -0,0 +1,54 @@ +/* Provenance: curl/curl conn_free (fixed). + * repo: curl/curl + * commit: 852aa5ad351ea53e5f01d2f44b5b4370c2bf5425 + * parent: ff2f3e836702daa82e2356195482fcc95f4257dc + * commit_url: https://github.com/curl/curl/commit/852aa5ad351ea53e5f01d2f44b5b4370c2bf5425 + * cve: CVE-2022-22576 + * license: curl + * function: conn_free + * relpath: lib/url.c + */ + +static void conn_free(struct connectdata *conn) +{ + DEBUGASSERT(conn); + + Curl_free_idnconverted_hostname(&conn->host); + Curl_free_idnconverted_hostname(&conn->conn_to_host); +#ifndef CURL_DISABLE_PROXY + Curl_free_idnconverted_hostname(&conn->http_proxy.host); + Curl_free_idnconverted_hostname(&conn->socks_proxy.host); + Curl_safefree(conn->http_proxy.user); + Curl_safefree(conn->socks_proxy.user); + Curl_safefree(conn->http_proxy.passwd); + Curl_safefree(conn->socks_proxy.passwd); + Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */ + Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */ + Curl_free_primary_ssl_config(&conn->proxy_ssl_config); +#endif + Curl_safefree(conn->user); + Curl_safefree(conn->passwd); + Curl_safefree(conn->sasl_authzid); + Curl_safefree(conn->options); + Curl_safefree(conn->oauth_bearer); + Curl_dyn_free(&conn->trailer); + Curl_safefree(conn->host.rawalloc); /* host name buffer */ + Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */ + Curl_safefree(conn->hostname_resolve); + Curl_safefree(conn->secondaryhostname); + Curl_safefree(conn->connect_state); + + conn_reset_all_postponed_data(conn); + Curl_llist_destroy(&conn->easyq, NULL); + Curl_safefree(conn->localdev); + Curl_free_primary_ssl_config(&conn->ssl_config); + +#ifdef USE_UNIX_SOCKETS + Curl_safefree(conn->unix_domain_socket); +#endif + +#ifdef USE_SSL + Curl_safefree(conn->ssl_extra); +#endif + free(conn); /* free all the connection oriented data */ +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-22576-conn_free/vuln.c b/benchmarks/pairs/vfc/curl-cve-2022-22576-conn_free/vuln.c new file mode 100644 index 0000000..a722efb --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-22576-conn_free/vuln.c @@ -0,0 +1,53 @@ +/* Provenance: curl/curl conn_free (vuln). + * repo: curl/curl + * commit: ff2f3e836702daa82e2356195482fcc95f4257dc + * parent: ff2f3e836702daa82e2356195482fcc95f4257dc + * commit_url: https://github.com/curl/curl/commit/852aa5ad351ea53e5f01d2f44b5b4370c2bf5425 + * cve: CVE-2022-22576 + * license: curl + * function: conn_free + * relpath: lib/url.c + */ + +static void conn_free(struct connectdata *conn) +{ + DEBUGASSERT(conn); + + Curl_free_idnconverted_hostname(&conn->host); + Curl_free_idnconverted_hostname(&conn->conn_to_host); +#ifndef CURL_DISABLE_PROXY + Curl_free_idnconverted_hostname(&conn->http_proxy.host); + Curl_free_idnconverted_hostname(&conn->socks_proxy.host); + Curl_safefree(conn->http_proxy.user); + Curl_safefree(conn->socks_proxy.user); + Curl_safefree(conn->http_proxy.passwd); + Curl_safefree(conn->socks_proxy.passwd); + Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */ + Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */ + Curl_free_primary_ssl_config(&conn->proxy_ssl_config); +#endif + Curl_safefree(conn->user); + Curl_safefree(conn->passwd); + Curl_safefree(conn->sasl_authzid); + Curl_safefree(conn->options); + Curl_dyn_free(&conn->trailer); + Curl_safefree(conn->host.rawalloc); /* host name buffer */ + Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */ + Curl_safefree(conn->hostname_resolve); + Curl_safefree(conn->secondaryhostname); + Curl_safefree(conn->connect_state); + + conn_reset_all_postponed_data(conn); + Curl_llist_destroy(&conn->easyq, NULL); + Curl_safefree(conn->localdev); + Curl_free_primary_ssl_config(&conn->ssl_config); + +#ifdef USE_UNIX_SOCKETS + Curl_safefree(conn->unix_domain_socket); +#endif + +#ifdef USE_SSL + Curl_safefree(conn->ssl_extra); +#endif + free(conn); /* free all the connection oriented data */ +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-27774/fixed.c b/benchmarks/pairs/vfc/curl-cve-2022-27774/fixed.c new file mode 100644 index 0000000..424f9fd --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-27774/fixed.c @@ -0,0 +1,297 @@ +/* Provenance: curl/curl Curl_follow (fixed). + * repo: curl/curl + * commit: 620ea21410030a9977396b4661806bc187231b79 + * parent: 08b8ef4e726ba10f45081ecda5b3cea788d3c839 + * commit_url: https://github.com/curl/curl/commit/620ea21410030a9977396b4661806bc187231b79 + * cve: CVE-2022-27774 + * license: curl + * function: Curl_follow + * relpath: lib/transfer.c + */ + +* Curl_follow() handles the URL redirect magic. Pass in the 'newurl' string + * as given by the remote server and set up the new URL to request. + * + * This function DOES NOT FREE the given url. + */ +CURLcode Curl_follow(struct Curl_easy *data, + char *newurl, /* the Location: string */ + followtype type) /* see transfer.h */ +{ +#ifdef CURL_DISABLE_HTTP + (void)data; + (void)newurl; + (void)type; + /* Location: following will not happen when HTTP is disabled */ + return CURLE_TOO_MANY_REDIRECTS; +#else + + /* Location: redirect */ + bool disallowport = FALSE; + bool reachedmax = FALSE; + CURLUcode uc; + + DEBUGASSERT(type != FOLLOW_NONE); + + if(type != FOLLOW_FAKE) + data->state.requests++; /* count all real follows */ + if(type == FOLLOW_REDIR) { + if((data->set.maxredirs != -1) && + (data->state.followlocation >= data->set.maxredirs)) { + reachedmax = TRUE; + type = FOLLOW_FAKE; /* switch to fake to store the would-be-redirected + to URL */ + } + else { + /* mark the next request as a followed location: */ + data->state.this_is_a_follow = TRUE; + + data->state.followlocation++; /* count location-followers */ + + if(data->set.http_auto_referer) { + CURLU *u; + char *referer = NULL; + + /* We are asked to automatically set the previous URL as the referer + when we get the next URL. We pick the ->url field, which may or may + not be 100% correct */ + + if(data->state.referer_alloc) { + Curl_safefree(data->state.referer); + data->state.referer_alloc = FALSE; + } + + /* Make a copy of the URL without crenditals and fragment */ + u = curl_url(); + if(!u) + return CURLE_OUT_OF_MEMORY; + + uc = curl_url_set(u, CURLUPART_URL, data->state.url, 0); + if(!uc) + uc = curl_url_set(u, CURLUPART_FRAGMENT, NULL, 0); + if(!uc) + uc = curl_url_set(u, CURLUPART_USER, NULL, 0); + if(!uc) + uc = curl_url_set(u, CURLUPART_PASSWORD, NULL, 0); + if(!uc) + uc = curl_url_get(u, CURLUPART_URL, &referer, 0); + + curl_url_cleanup(u); + + if(uc || !referer) + return CURLE_OUT_OF_MEMORY; + + data->state.referer = referer; + data->state.referer_alloc = TRUE; /* yes, free this later */ + } + } + } + + if((type != FOLLOW_RETRY) && + (data->req.httpcode != 401) && (data->req.httpcode != 407) && + Curl_is_absolute_url(newurl, NULL, 0)) + /* If this is not redirect due to a 401 or 407 response and an absolute + URL: don't allow a custom port number */ + disallowport = TRUE; + + DEBUGASSERT(data->state.uh); + uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl, + (type == FOLLOW_FAKE) ? CURLU_NON_SUPPORT_SCHEME : + ((type == FOLLOW_REDIR) ? CURLU_URLENCODE : 0) | + CURLU_ALLOW_SPACE); + if(uc) { + if(type != FOLLOW_FAKE) + return Curl_uc_to_curlcode(uc); + + /* the URL could not be parsed for some reason, but since this is FAKE + mode, just duplicate the field as-is */ + newurl = strdup(newurl); + if(!newurl) + return CURLE_OUT_OF_MEMORY; + } + else { + uc = curl_url_get(data->state.uh, CURLUPART_URL, &newurl, 0); + if(uc) + return Curl_uc_to_curlcode(uc); + + /* Clear auth if this redirects to a different port number or protocol, + unless permitted */ + if(!data->set.allow_auth_to_other_hosts && (type != FOLLOW_FAKE)) { + char *portnum; + int port; + bool clear = FALSE; + + if(data->set.use_port && data->state.allow_port) + /* a custom port is used */ + port = (int)data->set.use_port; + else { + uc = curl_url_get(data->state.uh, CURLUPART_PORT, &portnum, + CURLU_DEFAULT_PORT); + if(uc) { + free(newurl); + return Curl_uc_to_curlcode(uc); + } + port = atoi(portnum); + free(portnum); + } + if(port != data->info.conn_remote_port) { + infof(data, "Clear auth, redirects to port from %u to %u", + data->info.conn_remote_port, port); + clear = TRUE; + } + else { + char *scheme; + const struct Curl_handler *p; + uc = curl_url_get(data->state.uh, CURLUPART_SCHEME, &scheme, 0); + if(uc) { + free(newurl); + return Curl_uc_to_curlcode(uc); + } + + p = Curl_builtin_scheme(scheme); + if(p && (p->protocol != data->info.conn_protocol)) { + infof(data, "Clear auth, redirects scheme from %s to %s", + data->info.conn_scheme, scheme); + clear = TRUE; + } + free(scheme); + } + if(clear) { + Curl_safefree(data->state.aptr.user); + Curl_safefree(data->state.aptr.passwd); + } + } + } + + if(type == FOLLOW_FAKE) { + /* we're only figuring out the new url if we would've followed locations + but now we're done so we can get out! */ + data->info.wouldredirect = newurl; + + if(reachedmax) { + failf(data, "Maximum (%ld) redirects followed", data->set.maxredirs); + return CURLE_TOO_MANY_REDIRECTS; + } + return CURLE_OK; + } + + if(disallowport) + data->state.allow_port = FALSE; + + if(data->state.url_alloc) + Curl_safefree(data->state.url); + + data->state.url = newurl; + data->state.url_alloc = TRUE; + + infof(data, "Issue another request to this URL: '%s'", data->state.url); + + /* + * We get here when the HTTP code is 300-399 (and 401). We need to perform + * differently based on exactly what return code there was. + * + * News from 7.10.6: we can also get here on a 401 or 407, in case we act on + * a HTTP (proxy-) authentication scheme other than Basic. + */ + switch(data->info.httpcode) { + /* 401 - Act on a WWW-Authenticate, we keep on moving and do the + Authorization: XXXX header in the HTTP request code snippet */ + /* 407 - Act on a Proxy-Authenticate, we keep on moving and do the + Proxy-Authorization: XXXX header in the HTTP request code snippet */ + /* 300 - Multiple Choices */ + /* 306 - Not used */ + /* 307 - Temporary Redirect */ + default: /* for all above (and the unknown ones) */ + /* Some codes are explicitly mentioned since I've checked RFC2616 and they + * seem to be OK to POST to. + */ + break; + case 301: /* Moved Permanently */ + /* (quote from RFC7231, section 6.4.2) + * + * Note: For historical reasons, a user agent MAY change the request + * method from POST to GET for the subsequent request. If this + * behavior is undesired, the 307 (Temporary Redirect) status code + * can be used instead. + * + * ---- + * + * Many webservers expect this, so these servers often answers to a POST + * request with an error page. To be sure that libcurl gets the page that + * most user agents would get, libcurl has to force GET. + * + * This behavior is forbidden by RFC1945 and the obsolete RFC2616, and + * can be overridden with CURLOPT_POSTREDIR. + */ + if((data->state.httpreq == HTTPREQ_POST + || data->state.httpreq == HTTPREQ_POST_FORM + || data->state.httpreq == HTTPREQ_POST_MIME) + && !(data->set.keep_post & CURL_REDIR_POST_301)) { + infof(data, "Switch from POST to GET"); + data->state.httpreq = HTTPREQ_GET; + } + break; + case 302: /* Found */ + /* (quote from RFC7231, section 6.4.3) + * + * Note: For historical reasons, a user agent MAY change the request + * method from POST to GET for the subsequent request. If this + * behavior is undesired, the 307 (Temporary Redirect) status code + * can be used instead. + * + * ---- + * + * Many webservers expect this, so these servers often answers to a POST + * request with an error page. To be sure that libcurl gets the page that + * most user agents would get, libcurl has to force GET. + * + * This behavior is forbidden by RFC1945 and the obsolete RFC2616, and + * can be overridden with CURLOPT_POSTREDIR. + */ + if((data->state.httpreq == HTTPREQ_POST + || data->state.httpreq == HTTPREQ_POST_FORM + || data->state.httpreq == HTTPREQ_POST_MIME) + && !(data->set.keep_post & CURL_REDIR_POST_302)) { + infof(data, "Switch from POST to GET"); + data->state.httpreq = HTTPREQ_GET; + } + break; + + case 303: /* See Other */ + /* 'See Other' location is not the resource but a substitute for the + * resource. In this case we switch the method to GET/HEAD, unless the + * method is POST and the user specified to keep it as POST. + * https://github.com/curl/curl/issues/5237#issuecomment-614641049 + */ + if(data->state.httpreq != HTTPREQ_GET && + ((data->state.httpreq != HTTPREQ_POST && + data->state.httpreq != HTTPREQ_POST_FORM && + data->state.httpreq != HTTPREQ_POST_MIME) || + !(data->set.keep_post & CURL_REDIR_POST_303))) { + data->state.httpreq = HTTPREQ_GET; + data->set.upload = false; + infof(data, "Switch to %s", + data->set.opt_no_body?"HEAD":"GET"); + } + break; + case 304: /* Not Modified */ + /* 304 means we did a conditional request and it was "Not modified". + * We shouldn't get any Location: header in this response! + */ + break; + case 305: /* Use Proxy */ + /* (quote from RFC2616, section 10.3.6): + * "The requested resource MUST be accessed through the proxy given + * by the Location field. The Location field gives the URI of the + * proxy. The recipient is expected to repeat this single request + * via the proxy. 305 responses MUST only be generated by origin + * servers." + */ + break; + } + Curl_pgrsTime(data, TIMER_REDIRECT); + Curl_pgrsResetTransferSizes(data); + + return CURLE_OK; +#endif /* CURL_DISABLE_HTTP */ +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-27774/vuln.c b/benchmarks/pairs/vfc/curl-cve-2022-27774/vuln.c new file mode 100644 index 0000000..0bb2168 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-27774/vuln.c @@ -0,0 +1,250 @@ +/* Provenance: curl/curl Curl_follow (vuln). + * repo: curl/curl + * commit: 08b8ef4e726ba10f45081ecda5b3cea788d3c839 + * parent: 08b8ef4e726ba10f45081ecda5b3cea788d3c839 + * commit_url: https://github.com/curl/curl/commit/620ea21410030a9977396b4661806bc187231b79 + * cve: CVE-2022-27774 + * license: curl + * function: Curl_follow + * relpath: lib/transfer.c + */ + +* Curl_follow() handles the URL redirect magic. Pass in the 'newurl' string + * as given by the remote server and set up the new URL to request. + * + * This function DOES NOT FREE the given url. + */ +CURLcode Curl_follow(struct Curl_easy *data, + char *newurl, /* the Location: string */ + followtype type) /* see transfer.h */ +{ +#ifdef CURL_DISABLE_HTTP + (void)data; + (void)newurl; + (void)type; + /* Location: following will not happen when HTTP is disabled */ + return CURLE_TOO_MANY_REDIRECTS; +#else + + /* Location: redirect */ + bool disallowport = FALSE; + bool reachedmax = FALSE; + CURLUcode uc; + + DEBUGASSERT(type != FOLLOW_NONE); + + if(type != FOLLOW_FAKE) + data->state.requests++; /* count all real follows */ + if(type == FOLLOW_REDIR) { + if((data->set.maxredirs != -1) && + (data->state.followlocation >= data->set.maxredirs)) { + reachedmax = TRUE; + type = FOLLOW_FAKE; /* switch to fake to store the would-be-redirected + to URL */ + } + else { + /* mark the next request as a followed location: */ + data->state.this_is_a_follow = TRUE; + + data->state.followlocation++; /* count location-followers */ + + if(data->set.http_auto_referer) { + CURLU *u; + char *referer = NULL; + + /* We are asked to automatically set the previous URL as the referer + when we get the next URL. We pick the ->url field, which may or may + not be 100% correct */ + + if(data->state.referer_alloc) { + Curl_safefree(data->state.referer); + data->state.referer_alloc = FALSE; + } + + /* Make a copy of the URL without crenditals and fragment */ + u = curl_url(); + if(!u) + return CURLE_OUT_OF_MEMORY; + + uc = curl_url_set(u, CURLUPART_URL, data->state.url, 0); + if(!uc) + uc = curl_url_set(u, CURLUPART_FRAGMENT, NULL, 0); + if(!uc) + uc = curl_url_set(u, CURLUPART_USER, NULL, 0); + if(!uc) + uc = curl_url_set(u, CURLUPART_PASSWORD, NULL, 0); + if(!uc) + uc = curl_url_get(u, CURLUPART_URL, &referer, 0); + + curl_url_cleanup(u); + + if(uc || !referer) + return CURLE_OUT_OF_MEMORY; + + data->state.referer = referer; + data->state.referer_alloc = TRUE; /* yes, free this later */ + } + } + } + + if((type != FOLLOW_RETRY) && + (data->req.httpcode != 401) && (data->req.httpcode != 407) && + Curl_is_absolute_url(newurl, NULL, 0)) + /* If this is not redirect due to a 401 or 407 response and an absolute + URL: don't allow a custom port number */ + disallowport = TRUE; + + DEBUGASSERT(data->state.uh); + uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl, + (type == FOLLOW_FAKE) ? CURLU_NON_SUPPORT_SCHEME : + ((type == FOLLOW_REDIR) ? CURLU_URLENCODE : 0) | + CURLU_ALLOW_SPACE); + if(uc) { + if(type != FOLLOW_FAKE) + return Curl_uc_to_curlcode(uc); + + /* the URL could not be parsed for some reason, but since this is FAKE + mode, just duplicate the field as-is */ + newurl = strdup(newurl); + if(!newurl) + return CURLE_OUT_OF_MEMORY; + } + else { + + uc = curl_url_get(data->state.uh, CURLUPART_URL, &newurl, 0); + if(uc) + return Curl_uc_to_curlcode(uc); + } + + if(type == FOLLOW_FAKE) { + /* we're only figuring out the new url if we would've followed locations + but now we're done so we can get out! */ + data->info.wouldredirect = newurl; + + if(reachedmax) { + failf(data, "Maximum (%ld) redirects followed", data->set.maxredirs); + return CURLE_TOO_MANY_REDIRECTS; + } + return CURLE_OK; + } + + if(disallowport) + data->state.allow_port = FALSE; + + if(data->state.url_alloc) + Curl_safefree(data->state.url); + + data->state.url = newurl; + data->state.url_alloc = TRUE; + + infof(data, "Issue another request to this URL: '%s'", data->state.url); + + /* + * We get here when the HTTP code is 300-399 (and 401). We need to perform + * differently based on exactly what return code there was. + * + * News from 7.10.6: we can also get here on a 401 or 407, in case we act on + * a HTTP (proxy-) authentication scheme other than Basic. + */ + switch(data->info.httpcode) { + /* 401 - Act on a WWW-Authenticate, we keep on moving and do the + Authorization: XXXX header in the HTTP request code snippet */ + /* 407 - Act on a Proxy-Authenticate, we keep on moving and do the + Proxy-Authorization: XXXX header in the HTTP request code snippet */ + /* 300 - Multiple Choices */ + /* 306 - Not used */ + /* 307 - Temporary Redirect */ + default: /* for all above (and the unknown ones) */ + /* Some codes are explicitly mentioned since I've checked RFC2616 and they + * seem to be OK to POST to. + */ + break; + case 301: /* Moved Permanently */ + /* (quote from RFC7231, section 6.4.2) + * + * Note: For historical reasons, a user agent MAY change the request + * method from POST to GET for the subsequent request. If this + * behavior is undesired, the 307 (Temporary Redirect) status code + * can be used instead. + * + * ---- + * + * Many webservers expect this, so these servers often answers to a POST + * request with an error page. To be sure that libcurl gets the page that + * most user agents would get, libcurl has to force GET. + * + * This behavior is forbidden by RFC1945 and the obsolete RFC2616, and + * can be overridden with CURLOPT_POSTREDIR. + */ + if((data->state.httpreq == HTTPREQ_POST + || data->state.httpreq == HTTPREQ_POST_FORM + || data->state.httpreq == HTTPREQ_POST_MIME) + && !(data->set.keep_post & CURL_REDIR_POST_301)) { + infof(data, "Switch from POST to GET"); + data->state.httpreq = HTTPREQ_GET; + } + break; + case 302: /* Found */ + /* (quote from RFC7231, section 6.4.3) + * + * Note: For historical reasons, a user agent MAY change the request + * method from POST to GET for the subsequent request. If this + * behavior is undesired, the 307 (Temporary Redirect) status code + * can be used instead. + * + * ---- + * + * Many webservers expect this, so these servers often answers to a POST + * request with an error page. To be sure that libcurl gets the page that + * most user agents would get, libcurl has to force GET. + * + * This behavior is forbidden by RFC1945 and the obsolete RFC2616, and + * can be overridden with CURLOPT_POSTREDIR. + */ + if((data->state.httpreq == HTTPREQ_POST + || data->state.httpreq == HTTPREQ_POST_FORM + || data->state.httpreq == HTTPREQ_POST_MIME) + && !(data->set.keep_post & CURL_REDIR_POST_302)) { + infof(data, "Switch from POST to GET"); + data->state.httpreq = HTTPREQ_GET; + } + break; + + case 303: /* See Other */ + /* 'See Other' location is not the resource but a substitute for the + * resource. In this case we switch the method to GET/HEAD, unless the + * method is POST and the user specified to keep it as POST. + * https://github.com/curl/curl/issues/5237#issuecomment-614641049 + */ + if(data->state.httpreq != HTTPREQ_GET && + ((data->state.httpreq != HTTPREQ_POST && + data->state.httpreq != HTTPREQ_POST_FORM && + data->state.httpreq != HTTPREQ_POST_MIME) || + !(data->set.keep_post & CURL_REDIR_POST_303))) { + data->state.httpreq = HTTPREQ_GET; + data->set.upload = false; + infof(data, "Switch to %s", + data->set.opt_no_body?"HEAD":"GET"); + } + break; + case 304: /* Not Modified */ + /* 304 means we did a conditional request and it was "Not modified". + * We shouldn't get any Location: header in this response! + */ + break; + case 305: /* Use Proxy */ + /* (quote from RFC2616, section 10.3.6): + * "The requested resource MUST be accessed through the proxy given + * by the Location field. The Location field gives the URI of the + * proxy. The recipient is expected to repeat this single request + * via the proxy. 305 responses MUST only be generated by origin + * servers." + */ + break; + } + Curl_pgrsTime(data, TIMER_REDIRECT); + Curl_pgrsResetTransferSizes(data); + + return CURLE_OK; +#endif /* CURL_DISABLE_HTTP */ +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-27775/fixed.c b/benchmarks/pairs/vfc/curl-cve-2022-27775/fixed.c new file mode 100644 index 0000000..9657d48 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-27775/fixed.c @@ -0,0 +1,42 @@ +/* Provenance: curl/curl hashkey (fixed). + * repo: curl/curl + * commit: 058f98dc3fe595f21dc26a5b9b1699e519ba5705 + * parent: 852aa5ad351ea53e5f01d2f44b5b4370c2bf5425 + * commit_url: https://github.com/curl/curl/commit/058f98dc3fe595f21dc26a5b9b1699e519ba5705 + * cve: CVE-2022-27775 + * license: curl + * function: hashkey + * relpath: lib/conncache.c + */ + +static void hashkey(struct connectdata *conn, char *buf, + size_t len, /* something like 128 is fine */ + const char **hostp) +{ + const char *hostname; + long port = conn->remote_port; + +#ifndef CURL_DISABLE_PROXY + if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { + hostname = conn->http_proxy.host.name; + port = conn->port; + } + else +#endif + if(conn->bits.conn_to_host) + hostname = conn->conn_to_host.name; + else + hostname = conn->host.name; + + if(hostp) + /* report back which name we used */ + *hostp = hostname; + + /* put the numbers first so that the hostname gets cut off if too long */ +#ifdef ENABLE_IPV6 + msnprintf(buf, len, "%u/%ld/%s", conn->scope_id, port, hostname); +#else + msnprintf(buf, len, "%ld/%s", port, hostname); +#endif + Curl_strntolower(buf, buf, len); +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-27775/vuln.c b/benchmarks/pairs/vfc/curl-cve-2022-27775/vuln.c new file mode 100644 index 0000000..69a9c1e --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-27775/vuln.c @@ -0,0 +1,38 @@ +/* Provenance: curl/curl hashkey (vuln). + * repo: curl/curl + * commit: 852aa5ad351ea53e5f01d2f44b5b4370c2bf5425 + * parent: 852aa5ad351ea53e5f01d2f44b5b4370c2bf5425 + * commit_url: https://github.com/curl/curl/commit/058f98dc3fe595f21dc26a5b9b1699e519ba5705 + * cve: CVE-2022-27775 + * license: curl + * function: hashkey + * relpath: lib/conncache.c + */ + +static void hashkey(struct connectdata *conn, char *buf, + size_t len, /* something like 128 is fine */ + const char **hostp) +{ + const char *hostname; + long port = conn->remote_port; + +#ifndef CURL_DISABLE_PROXY + if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { + hostname = conn->http_proxy.host.name; + port = conn->port; + } + else +#endif + if(conn->bits.conn_to_host) + hostname = conn->conn_to_host.name; + else + hostname = conn->host.name; + + if(hostp) + /* report back which name we used */ + *hostp = hostname; + + /* put the number first so that the hostname gets cut off if too long */ + msnprintf(buf, len, "%ld%s", port, hostname); + Curl_strntolower(buf, buf, len); +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-27776/fixed.c b/benchmarks/pairs/vfc/curl-cve-2022-27776/fixed.c new file mode 100644 index 0000000..929e55b --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-27776/fixed.c @@ -0,0 +1,163 @@ +/* Provenance: curl/curl Curl_add_custom_headers (fixed). + * repo: curl/curl + * commit: 6e659993952aa5f90f48864be84a1bbb047fc258 + * parent: 8f2079154f80561ccffcaa954268798b658e66b6 + * commit_url: https://github.com/curl/curl/commit/6e659993952aa5f90f48864be84a1bbb047fc258 + * cve: CVE-2022-27776 + * license: curl + * function: Curl_add_custom_headers + * relpath: lib/http.c + */ + +CURLcode Curl_add_custom_headers(struct Curl_easy *data, + bool is_connect, +#ifndef USE_HYPER + struct dynbuf *req +#else + void *req +#endif + ) +{ + struct connectdata *conn = data->conn; + char *ptr; + struct curl_slist *h[2]; + struct curl_slist *headers; + int numlists = 1; /* by default */ + int i; + +#ifndef CURL_DISABLE_PROXY + enum proxy_use proxy; + + if(is_connect) + proxy = HEADER_CONNECT; + else + proxy = conn->bits.httpproxy && !conn->bits.tunnel_proxy? + HEADER_PROXY:HEADER_SERVER; + + switch(proxy) { + case HEADER_SERVER: + h[0] = data->set.headers; + break; + case HEADER_PROXY: + h[0] = data->set.headers; + if(data->set.sep_headers) { + h[1] = data->set.proxyheaders; + numlists++; + } + break; + case HEADER_CONNECT: + if(data->set.sep_headers) + h[0] = data->set.proxyheaders; + else + h[0] = data->set.headers; + break; + } +#else + (void)is_connect; + h[0] = data->set.headers; +#endif + + /* loop through one or two lists */ + for(i = 0; i < numlists; i++) { + headers = h[i]; + + while(headers) { + char *semicolonp = NULL; + ptr = strchr(headers->data, ':'); + if(!ptr) { + char *optr; + /* no colon, semicolon? */ + ptr = strchr(headers->data, ';'); + if(ptr) { + optr = ptr; + ptr++; /* pass the semicolon */ + while(*ptr && ISSPACE(*ptr)) + ptr++; + + if(*ptr) { + /* this may be used for something else in the future */ + optr = NULL; + } + else { + if(*(--ptr) == ';') { + /* copy the source */ + semicolonp = strdup(headers->data); + if(!semicolonp) { +#ifndef USE_HYPER + Curl_dyn_free(req); +#endif + return CURLE_OUT_OF_MEMORY; + } + /* put a colon where the semicolon is */ + semicolonp[ptr - headers->data] = ':'; + /* point at the colon */ + optr = &semicolonp [ptr - headers->data]; + } + } + ptr = optr; + } + } + if(ptr && (ptr != headers->data)) { + /* we require a colon for this to be a true header */ + + ptr++; /* pass the colon */ + while(*ptr && ISSPACE(*ptr)) + ptr++; + + if(*ptr || semicolonp) { + /* only send this if the contents was non-blank or done special */ + CURLcode result = CURLE_OK; + char *compare = semicolonp ? semicolonp : headers->data; + + if(data->state.aptr.host && + /* a Host: header was sent already, don't pass on any custom Host: + header as that will produce *two* in the same request! */ + checkprefix("Host:", compare)) + ; + else if(data->state.httpreq == HTTPREQ_POST_FORM && + /* this header (extended by formdata.c) is sent later */ + checkprefix("Content-Type:", compare)) + ; + else if(data->state.httpreq == HTTPREQ_POST_MIME && + /* this header is sent later */ + checkprefix("Content-Type:", compare)) + ; + else if(conn->bits.authneg && + /* while doing auth neg, don't allow the custom length since + we will force length zero then */ + checkprefix("Content-Length:", compare)) + ; + else if(data->state.aptr.te && + /* when asking for Transfer-Encoding, don't pass on a custom + Connection: */ + checkprefix("Connection:", compare)) + ; + else if((conn->httpversion >= 20) && + checkprefix("Transfer-Encoding:", compare)) + /* HTTP/2 doesn't support chunked requests */ + ; + else if((checkprefix("Authorization:", compare) || + checkprefix("Cookie:", compare)) && + /* be careful of sending this potentially sensitive header to + other hosts */ + !allow_auth_to_host(data)) + ; + else { +#ifdef USE_HYPER + result = Curl_hyper_header(data, req, compare); +#else + result = Curl_dyn_addf(req, "%s\r\n", compare); +#endif + } + if(semicolonp) + free(semicolonp); + if(result) + return result; + } + } + headers = headers->next; + } + } + + return CURLE_OK; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-27776/vuln.c b/benchmarks/pairs/vfc/curl-cve-2022-27776/vuln.c new file mode 100644 index 0000000..bb6ae8e --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-27776/vuln.c @@ -0,0 +1,166 @@ +/* Provenance: curl/curl Curl_add_custom_headers (vuln). + * repo: curl/curl + * commit: 8f2079154f80561ccffcaa954268798b658e66b6 + * parent: 8f2079154f80561ccffcaa954268798b658e66b6 + * commit_url: https://github.com/curl/curl/commit/6e659993952aa5f90f48864be84a1bbb047fc258 + * cve: CVE-2022-27776 + * license: curl + * function: Curl_add_custom_headers + * relpath: lib/http.c + */ + +CURLcode Curl_add_custom_headers(struct Curl_easy *data, + bool is_connect, +#ifndef USE_HYPER + struct dynbuf *req +#else + void *req +#endif + ) +{ + struct connectdata *conn = data->conn; + char *ptr; + struct curl_slist *h[2]; + struct curl_slist *headers; + int numlists = 1; /* by default */ + int i; + +#ifndef CURL_DISABLE_PROXY + enum proxy_use proxy; + + if(is_connect) + proxy = HEADER_CONNECT; + else + proxy = conn->bits.httpproxy && !conn->bits.tunnel_proxy? + HEADER_PROXY:HEADER_SERVER; + + switch(proxy) { + case HEADER_SERVER: + h[0] = data->set.headers; + break; + case HEADER_PROXY: + h[0] = data->set.headers; + if(data->set.sep_headers) { + h[1] = data->set.proxyheaders; + numlists++; + } + break; + case HEADER_CONNECT: + if(data->set.sep_headers) + h[0] = data->set.proxyheaders; + else + h[0] = data->set.headers; + break; + } +#else + (void)is_connect; + h[0] = data->set.headers; +#endif + + /* loop through one or two lists */ + for(i = 0; i < numlists; i++) { + headers = h[i]; + + while(headers) { + char *semicolonp = NULL; + ptr = strchr(headers->data, ':'); + if(!ptr) { + char *optr; + /* no colon, semicolon? */ + ptr = strchr(headers->data, ';'); + if(ptr) { + optr = ptr; + ptr++; /* pass the semicolon */ + while(*ptr && ISSPACE(*ptr)) + ptr++; + + if(*ptr) { + /* this may be used for something else in the future */ + optr = NULL; + } + else { + if(*(--ptr) == ';') { + /* copy the source */ + semicolonp = strdup(headers->data); + if(!semicolonp) { +#ifndef USE_HYPER + Curl_dyn_free(req); +#endif + return CURLE_OUT_OF_MEMORY; + } + /* put a colon where the semicolon is */ + semicolonp[ptr - headers->data] = ':'; + /* point at the colon */ + optr = &semicolonp [ptr - headers->data]; + } + } + ptr = optr; + } + } + if(ptr && (ptr != headers->data)) { + /* we require a colon for this to be a true header */ + + ptr++; /* pass the colon */ + while(*ptr && ISSPACE(*ptr)) + ptr++; + + if(*ptr || semicolonp) { + /* only send this if the contents was non-blank or done special */ + CURLcode result = CURLE_OK; + char *compare = semicolonp ? semicolonp : headers->data; + + if(data->state.aptr.host && + /* a Host: header was sent already, don't pass on any custom Host: + header as that will produce *two* in the same request! */ + checkprefix("Host:", compare)) + ; + else if(data->state.httpreq == HTTPREQ_POST_FORM && + /* this header (extended by formdata.c) is sent later */ + checkprefix("Content-Type:", compare)) + ; + else if(data->state.httpreq == HTTPREQ_POST_MIME && + /* this header is sent later */ + checkprefix("Content-Type:", compare)) + ; + else if(conn->bits.authneg && + /* while doing auth neg, don't allow the custom length since + we will force length zero then */ + checkprefix("Content-Length:", compare)) + ; + else if(data->state.aptr.te && + /* when asking for Transfer-Encoding, don't pass on a custom + Connection: */ + checkprefix("Connection:", compare)) + ; + else if((conn->httpversion >= 20) && + checkprefix("Transfer-Encoding:", compare)) + /* HTTP/2 doesn't support chunked requests */ + ; + else if((checkprefix("Authorization:", compare) || + checkprefix("Cookie:", compare)) && + /* be careful of sending this potentially sensitive header to + other hosts */ + (data->state.this_is_a_follow && + data->state.first_host && + !data->set.allow_auth_to_other_hosts && + !strcasecompare(data->state.first_host, conn->host.name))) + ; + else { +#ifdef USE_HYPER + result = Curl_hyper_header(data, req, compare); +#else + result = Curl_dyn_addf(req, "%s\r\n", compare); +#endif + } + if(semicolonp) + free(semicolonp); + if(result) + return result; + } + } + headers = headers->next; + } + } + + return CURLE_OK; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-27778/fixed.c b/benchmarks/pairs/vfc/curl-cve-2022-27778/fixed.c new file mode 100644 index 0000000..c2b28dd --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-27778/fixed.c @@ -0,0 +1,318 @@ +/* Provenance: curl/curl post_per_transfer (fixed). + * repo: curl/curl + * commit: 8c7ee9083d0d719d0a77ab20d9cc2ae84eeea7f3 + * parent: fae6fea209a2d4db1582f608bd8cc8000721733a + * commit_url: https://github.com/curl/curl/commit/8c7ee9083d0d719d0a77ab20d9cc2ae84eeea7f3 + * cve: CVE-2022-27778 + * license: curl + * function: post_per_transfer + * relpath: src/tool_operate.c + */ + +static CURLcode post_per_transfer(struct GlobalConfig *global, + struct per_transfer *per, + CURLcode result, + bool *retryp, + long *delay) /* milliseconds! */ +{ + struct OutStruct *outs = &per->outs; + CURL *curl = per->curl; + struct OperationConfig *config = per->config; + + if(!curl || !config) + return result; + + *retryp = FALSE; + *delay = 0; /* for no retry, keep it zero */ + + if(per->infdopen) + close(per->infd); + +#ifdef __VMS + if(is_vms_shell()) { + /* VMS DCL shell behavior */ + if(!global->showerror) + vms_show = VMSSTS_HIDE; + } + else +#endif + if(!config->synthetic_error && result && global->showerror) { + fprintf(global->errors, "curl: (%d) %s\n", result, + (per->errorbuffer[0]) ? per->errorbuffer : + curl_easy_strerror(result)); + if(result == CURLE_PEER_FAILED_VERIFICATION) + fputs(CURL_CA_CERT_ERRORMSG, global->errors); + } + else if(config->failwithbody) { + /* if HTTP response >= 400, return error */ + long code = 0; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code); + if(code >= 400) { + if(global->showerror) + fprintf(global->errors, + "curl: (%d) The requested URL returned error: %ld\n", + CURLE_HTTP_RETURNED_ERROR, code); + result = CURLE_HTTP_RETURNED_ERROR; + } + } + /* Set file extended attributes */ + if(!result && config->xattr && outs->fopened && outs->stream) { + int rc = fwrite_xattr(curl, fileno(outs->stream)); + if(rc) + warnf(config->global, "Error setting extended attributes on '%s': %s\n", + outs->filename, strerror(errno)); + } + + if(!result && !outs->stream && !outs->bytes) { + /* we have received no data despite the transfer was successful + ==> force creation of an empty output file (if an output file + was specified) */ + long cond_unmet = 0L; + /* do not create (or even overwrite) the file in case we get no + data because of unmet condition */ + curl_easy_getinfo(curl, CURLINFO_CONDITION_UNMET, &cond_unmet); + if(!cond_unmet && !tool_create_output_file(outs, config)) + result = CURLE_WRITE_ERROR; + } + + if(!outs->s_isreg && outs->stream) { + /* Dump standard stream buffered data */ + int rc = fflush(outs->stream); + if(!result && rc) { + /* something went wrong in the writing process */ + result = CURLE_WRITE_ERROR; + if(global->showerror) + fprintf(global->errors, "curl: (%d) Failed writing body\n", result); + } + } + + /* if retry-max-time is non-zero, make sure we haven't exceeded the + time */ + if(per->retry_numretries && + (!config->retry_maxtime || + (tvdiff(tvnow(), per->retrystart) < + config->retry_maxtime*1000L)) ) { + enum { + RETRY_NO, + RETRY_ALL_ERRORS, + RETRY_TIMEOUT, + RETRY_CONNREFUSED, + RETRY_HTTP, + RETRY_FTP, + RETRY_LAST /* not used */ + } retry = RETRY_NO; + long response = 0; + if((CURLE_OPERATION_TIMEDOUT == result) || + (CURLE_COULDNT_RESOLVE_HOST == result) || + (CURLE_COULDNT_RESOLVE_PROXY == result) || + (CURLE_FTP_ACCEPT_TIMEOUT == result)) + /* retry timeout always */ + retry = RETRY_TIMEOUT; + else if(config->retry_connrefused && + (CURLE_COULDNT_CONNECT == result)) { + long oserrno = 0; + curl_easy_getinfo(curl, CURLINFO_OS_ERRNO, &oserrno); + if(ECONNREFUSED == oserrno) + retry = RETRY_CONNREFUSED; + } + else if((CURLE_OK == result) || + (config->failonerror && + (CURLE_HTTP_RETURNED_ERROR == result))) { + /* If it returned OK. _or_ failonerror was enabled and it + returned due to such an error, check for HTTP transient + errors to retry on. */ + long protocol = 0; + curl_easy_getinfo(curl, CURLINFO_PROTOCOL, &protocol); + if((protocol == CURLPROTO_HTTP) || (protocol == CURLPROTO_HTTPS)) { + /* This was HTTP(S) */ + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response); + + switch(response) { + case 408: /* Request Timeout */ + case 429: /* Too Many Requests (RFC6585) */ + case 500: /* Internal Server Error */ + case 502: /* Bad Gateway */ + case 503: /* Service Unavailable */ + case 504: /* Gateway Timeout */ + retry = RETRY_HTTP; + /* + * At this point, we have already written data to the output + * file (or terminal). If we write to a file, we must rewind + * or close/re-open the file so that the next attempt starts + * over from the beginning. + * + * TODO: similar action for the upload case. We might need + * to start over reading from a previous point if we have + * uploaded something when this was returned. + */ + break; + } + } + } /* if CURLE_OK */ + else if(result) { + long protocol = 0; + + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response); + curl_easy_getinfo(curl, CURLINFO_PROTOCOL, &protocol); + + if((protocol == CURLPROTO_FTP || protocol == CURLPROTO_FTPS) && + response / 100 == 4) + /* + * This is typically when the FTP server only allows a certain + * amount of users and we are not one of them. All 4xx codes + * are transient. + */ + retry = RETRY_FTP; + } + + if(result && !retry && config->retry_all_errors) + retry = RETRY_ALL_ERRORS; + + if(retry) { + long sleeptime = 0; + curl_off_t retry_after = 0; + static const char * const m[]={ + NULL, + "(retrying all errors)", + ": timeout", + ": connection refused", + ": HTTP error", + ": FTP error" + }; + + sleeptime = per->retry_sleep; + if(RETRY_HTTP == retry) { + curl_easy_getinfo(curl, CURLINFO_RETRY_AFTER, &retry_after); + if(retry_after) { + /* store in a 'long', make sure it doesn't overflow */ + if(retry_after > LONG_MAX/1000) + sleeptime = LONG_MAX; + else + sleeptime = (long)retry_after * 1000; /* milliseconds */ + + /* if adding retry_after seconds to the process would exceed the + maximum time allowed for retrying, then exit the retries right + away */ + if(config->retry_maxtime) { + curl_off_t seconds = tvdiff(tvnow(), per->retrystart)/1000; + + if((CURL_OFF_T_MAX - retry_after < seconds) || + (seconds + retry_after > config->retry_maxtime)) { + warnf(config->global, "The Retry-After: time would " + "make this command line exceed the maximum allowed time " + "for retries."); + goto noretry; + } + } + } + } + warnf(config->global, "Problem %s. " + "Will retry in %ld seconds. " + "%ld retries left.\n", + m[retry], sleeptime/1000L, per->retry_numretries); + + per->retry_numretries--; + if(!config->retry_delay) { + per->retry_sleep *= 2; + if(per->retry_sleep > RETRY_SLEEP_MAX) + per->retry_sleep = RETRY_SLEEP_MAX; + } + if(outs->bytes && outs->filename && outs->stream) { + int rc; + /* We have written data to an output file, we truncate file + */ + if(!global->mute) + fprintf(global->errors, "Throwing away %" + CURL_FORMAT_CURL_OFF_T " bytes\n", + outs->bytes); + fflush(outs->stream); + /* truncate file at the position where we started appending */ +#ifdef HAVE_FTRUNCATE + if(ftruncate(fileno(outs->stream), outs->init)) { + /* when truncate fails, we can't just append as then we'll + create something strange, bail out */ + if(global->showerror) + fprintf(global->errors, + "curl: (23) Failed to truncate file\n"); + return CURLE_WRITE_ERROR; + } + /* now seek to the end of the file, the position where we + just truncated the file in a large file-safe way */ + rc = fseek(outs->stream, 0, SEEK_END); +#else + /* ftruncate is not available, so just reposition the file + to the location we would have truncated it. This won't + work properly with large files on 32-bit systems, but + most of those will have ftruncate. */ + rc = fseek(outs->stream, (long)outs->init, SEEK_SET); +#endif + if(rc) { + if(global->showerror) + fprintf(global->errors, + "curl: (23) Failed seeking to end of file\n"); + return CURLE_WRITE_ERROR; + } + outs->bytes = 0; /* clear for next round */ + } + *retryp = TRUE; + *delay = sleeptime; + return CURLE_OK; + } + } /* if retry_numretries */ + noretry: + + if((global->progressmode == CURL_PROGRESS_BAR) && + per->progressbar.calls) + /* if the custom progress bar has been displayed, we output a + newline here */ + fputs("\n", per->progressbar.out); + + /* Close the outs file */ + if(outs->fopened && outs->stream) { + int rc = fclose(outs->stream); + if(!result && rc) { + /* something went wrong in the writing process */ + result = CURLE_WRITE_ERROR; + if(global->showerror) + fprintf(global->errors, "curl: (%d) Failed writing body\n", result); + } + if(result && config->rm_partial) { + notef(global, "Removing output file: %s\n", outs->filename); + unlink(outs->filename); + } + } + + /* File time can only be set _after_ the file has been closed */ + if(!result && config->remote_time && outs->s_isreg && outs->filename) { + /* Ask libcurl if we got a remote file time */ + curl_off_t filetime = -1; + curl_easy_getinfo(curl, CURLINFO_FILETIME_T, &filetime); + setfiletime(filetime, outs->filename, global); + } + + /* Write the --write-out data before cleanup but after result is final */ + if(config->writeout) + ourWriteOut(config->writeout, per, result); + + /* Close function-local opened file descriptors */ + if(per->heads.fopened && per->heads.stream) + fclose(per->heads.stream); + + if(per->heads.alloc_filename) + Curl_safefree(per->heads.filename); + + if(per->etag_save.fopened && per->etag_save.stream) + fclose(per->etag_save.stream); + + if(per->etag_save.alloc_filename) + Curl_safefree(per->etag_save.filename); + + curl_easy_cleanup(per->curl); + if(outs->alloc_filename) + free(outs->filename); + free(per->this_url); + free(per->outfile); + free(per->uploadfile); + + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-27778/vuln.c b/benchmarks/pairs/vfc/curl-cve-2022-27778/vuln.c new file mode 100644 index 0000000..0235733 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-27778/vuln.c @@ -0,0 +1,318 @@ +/* Provenance: curl/curl post_per_transfer (vuln). + * repo: curl/curl + * commit: fae6fea209a2d4db1582f608bd8cc8000721733a + * parent: fae6fea209a2d4db1582f608bd8cc8000721733a + * commit_url: https://github.com/curl/curl/commit/8c7ee9083d0d719d0a77ab20d9cc2ae84eeea7f3 + * cve: CVE-2022-27778 + * license: curl + * function: post_per_transfer + * relpath: src/tool_operate.c + */ + +static CURLcode post_per_transfer(struct GlobalConfig *global, + struct per_transfer *per, + CURLcode result, + bool *retryp, + long *delay) /* milliseconds! */ +{ + struct OutStruct *outs = &per->outs; + CURL *curl = per->curl; + struct OperationConfig *config = per->config; + + if(!curl || !config) + return result; + + *retryp = FALSE; + *delay = 0; /* for no retry, keep it zero */ + + if(per->infdopen) + close(per->infd); + +#ifdef __VMS + if(is_vms_shell()) { + /* VMS DCL shell behavior */ + if(!global->showerror) + vms_show = VMSSTS_HIDE; + } + else +#endif + if(!config->synthetic_error && result && global->showerror) { + fprintf(global->errors, "curl: (%d) %s\n", result, + (per->errorbuffer[0]) ? per->errorbuffer : + curl_easy_strerror(result)); + if(result == CURLE_PEER_FAILED_VERIFICATION) + fputs(CURL_CA_CERT_ERRORMSG, global->errors); + } + else if(config->failwithbody) { + /* if HTTP response >= 400, return error */ + long code = 0; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code); + if(code >= 400) { + if(global->showerror) + fprintf(global->errors, + "curl: (%d) The requested URL returned error: %ld\n", + CURLE_HTTP_RETURNED_ERROR, code); + result = CURLE_HTTP_RETURNED_ERROR; + } + } + /* Set file extended attributes */ + if(!result && config->xattr && outs->fopened && outs->stream) { + int rc = fwrite_xattr(curl, fileno(outs->stream)); + if(rc) + warnf(config->global, "Error setting extended attributes on '%s': %s\n", + outs->filename, strerror(errno)); + } + + if(!result && !outs->stream && !outs->bytes) { + /* we have received no data despite the transfer was successful + ==> force creation of an empty output file (if an output file + was specified) */ + long cond_unmet = 0L; + /* do not create (or even overwrite) the file in case we get no + data because of unmet condition */ + curl_easy_getinfo(curl, CURLINFO_CONDITION_UNMET, &cond_unmet); + if(!cond_unmet && !tool_create_output_file(outs, config)) + result = CURLE_WRITE_ERROR; + } + + if(!outs->s_isreg && outs->stream) { + /* Dump standard stream buffered data */ + int rc = fflush(outs->stream); + if(!result && rc) { + /* something went wrong in the writing process */ + result = CURLE_WRITE_ERROR; + if(global->showerror) + fprintf(global->errors, "curl: (%d) Failed writing body\n", result); + } + } + + /* if retry-max-time is non-zero, make sure we haven't exceeded the + time */ + if(per->retry_numretries && + (!config->retry_maxtime || + (tvdiff(tvnow(), per->retrystart) < + config->retry_maxtime*1000L)) ) { + enum { + RETRY_NO, + RETRY_ALL_ERRORS, + RETRY_TIMEOUT, + RETRY_CONNREFUSED, + RETRY_HTTP, + RETRY_FTP, + RETRY_LAST /* not used */ + } retry = RETRY_NO; + long response = 0; + if((CURLE_OPERATION_TIMEDOUT == result) || + (CURLE_COULDNT_RESOLVE_HOST == result) || + (CURLE_COULDNT_RESOLVE_PROXY == result) || + (CURLE_FTP_ACCEPT_TIMEOUT == result)) + /* retry timeout always */ + retry = RETRY_TIMEOUT; + else if(config->retry_connrefused && + (CURLE_COULDNT_CONNECT == result)) { + long oserrno = 0; + curl_easy_getinfo(curl, CURLINFO_OS_ERRNO, &oserrno); + if(ECONNREFUSED == oserrno) + retry = RETRY_CONNREFUSED; + } + else if((CURLE_OK == result) || + (config->failonerror && + (CURLE_HTTP_RETURNED_ERROR == result))) { + /* If it returned OK. _or_ failonerror was enabled and it + returned due to such an error, check for HTTP transient + errors to retry on. */ + long protocol = 0; + curl_easy_getinfo(curl, CURLINFO_PROTOCOL, &protocol); + if((protocol == CURLPROTO_HTTP) || (protocol == CURLPROTO_HTTPS)) { + /* This was HTTP(S) */ + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response); + + switch(response) { + case 408: /* Request Timeout */ + case 429: /* Too Many Requests (RFC6585) */ + case 500: /* Internal Server Error */ + case 502: /* Bad Gateway */ + case 503: /* Service Unavailable */ + case 504: /* Gateway Timeout */ + retry = RETRY_HTTP; + /* + * At this point, we have already written data to the output + * file (or terminal). If we write to a file, we must rewind + * or close/re-open the file so that the next attempt starts + * over from the beginning. + * + * TODO: similar action for the upload case. We might need + * to start over reading from a previous point if we have + * uploaded something when this was returned. + */ + break; + } + } + } /* if CURLE_OK */ + else if(result) { + long protocol = 0; + + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response); + curl_easy_getinfo(curl, CURLINFO_PROTOCOL, &protocol); + + if((protocol == CURLPROTO_FTP || protocol == CURLPROTO_FTPS) && + response / 100 == 4) + /* + * This is typically when the FTP server only allows a certain + * amount of users and we are not one of them. All 4xx codes + * are transient. + */ + retry = RETRY_FTP; + } + + if(result && !retry && config->retry_all_errors) + retry = RETRY_ALL_ERRORS; + + if(retry) { + long sleeptime = 0; + curl_off_t retry_after = 0; + static const char * const m[]={ + NULL, + "(retrying all errors)", + ": timeout", + ": connection refused", + ": HTTP error", + ": FTP error" + }; + + sleeptime = per->retry_sleep; + if(RETRY_HTTP == retry) { + curl_easy_getinfo(curl, CURLINFO_RETRY_AFTER, &retry_after); + if(retry_after) { + /* store in a 'long', make sure it doesn't overflow */ + if(retry_after > LONG_MAX/1000) + sleeptime = LONG_MAX; + else + sleeptime = (long)retry_after * 1000; /* milliseconds */ + + /* if adding retry_after seconds to the process would exceed the + maximum time allowed for retrying, then exit the retries right + away */ + if(config->retry_maxtime) { + curl_off_t seconds = tvdiff(tvnow(), per->retrystart)/1000; + + if((CURL_OFF_T_MAX - retry_after < seconds) || + (seconds + retry_after > config->retry_maxtime)) { + warnf(config->global, "The Retry-After: time would " + "make this command line exceed the maximum allowed time " + "for retries."); + goto noretry; + } + } + } + } + warnf(config->global, "Problem %s. " + "Will retry in %ld seconds. " + "%ld retries left.\n", + m[retry], sleeptime/1000L, per->retry_numretries); + + per->retry_numretries--; + if(!config->retry_delay) { + per->retry_sleep *= 2; + if(per->retry_sleep > RETRY_SLEEP_MAX) + per->retry_sleep = RETRY_SLEEP_MAX; + } + if(outs->bytes && outs->filename && outs->stream) { + int rc; + /* We have written data to an output file, we truncate file + */ + if(!global->mute) + fprintf(global->errors, "Throwing away %" + CURL_FORMAT_CURL_OFF_T " bytes\n", + outs->bytes); + fflush(outs->stream); + /* truncate file at the position where we started appending */ +#ifdef HAVE_FTRUNCATE + if(ftruncate(fileno(outs->stream), outs->init)) { + /* when truncate fails, we can't just append as then we'll + create something strange, bail out */ + if(global->showerror) + fprintf(global->errors, + "curl: (23) Failed to truncate file\n"); + return CURLE_WRITE_ERROR; + } + /* now seek to the end of the file, the position where we + just truncated the file in a large file-safe way */ + rc = fseek(outs->stream, 0, SEEK_END); +#else + /* ftruncate is not available, so just reposition the file + to the location we would have truncated it. This won't + work properly with large files on 32-bit systems, but + most of those will have ftruncate. */ + rc = fseek(outs->stream, (long)outs->init, SEEK_SET); +#endif + if(rc) { + if(global->showerror) + fprintf(global->errors, + "curl: (23) Failed seeking to end of file\n"); + return CURLE_WRITE_ERROR; + } + outs->bytes = 0; /* clear for next round */ + } + *retryp = TRUE; + *delay = sleeptime; + return CURLE_OK; + } + } /* if retry_numretries */ + noretry: + + if((global->progressmode == CURL_PROGRESS_BAR) && + per->progressbar.calls) + /* if the custom progress bar has been displayed, we output a + newline here */ + fputs("\n", per->progressbar.out); + + /* Close the outs file */ + if(outs->fopened && outs->stream) { + int rc = fclose(outs->stream); + if(!result && rc) { + /* something went wrong in the writing process */ + result = CURLE_WRITE_ERROR; + if(global->showerror) + fprintf(global->errors, "curl: (%d) Failed writing body\n", result); + } + if(result && config->rm_partial) { + notef(global, "Removing output file: %s", per->outfile); + unlink(per->outfile); + } + } + + /* File time can only be set _after_ the file has been closed */ + if(!result && config->remote_time && outs->s_isreg && outs->filename) { + /* Ask libcurl if we got a remote file time */ + curl_off_t filetime = -1; + curl_easy_getinfo(curl, CURLINFO_FILETIME_T, &filetime); + setfiletime(filetime, outs->filename, global); + } + + /* Write the --write-out data before cleanup but after result is final */ + if(config->writeout) + ourWriteOut(config->writeout, per, result); + + /* Close function-local opened file descriptors */ + if(per->heads.fopened && per->heads.stream) + fclose(per->heads.stream); + + if(per->heads.alloc_filename) + Curl_safefree(per->heads.filename); + + if(per->etag_save.fopened && per->etag_save.stream) + fclose(per->etag_save.stream); + + if(per->etag_save.alloc_filename) + Curl_safefree(per->etag_save.filename); + + curl_easy_cleanup(per->curl); + if(outs->alloc_filename) + free(outs->filename); + free(per->this_url); + free(per->outfile); + free(per->uploadfile); + + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-27780/fixed.c b/benchmarks/pairs/vfc/curl-cve-2022-27780/fixed.c new file mode 100644 index 0000000..0af8299 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-27780/fixed.c @@ -0,0 +1,84 @@ +/* Provenance: curl/curl hostname_check (fixed). + * repo: curl/curl + * commit: 914aaab9153764ef8fa4178215b8ad89d3ac263a + * parent: 5c7da89d404bf59c8dd82a001119a16d18365917 + * commit_url: https://github.com/curl/curl/commit/914aaab9153764ef8fa4178215b8ad89d3ac263a + * cve: CVE-2022-27780 + * license: curl + * function: hostname_check + * relpath: lib/urlapi.c + */ + +static CURLUcode hostname_check(struct Curl_URL *u, char *hostname) +{ + size_t len; + size_t hlen = strlen(hostname); + + if(hostname[0] == '[') { + const char *l = "0123456789abcdefABCDEF:."; + if(hlen < 4) /* '[::]' is the shortest possible valid string */ + return CURLUE_BAD_IPV6; + hostname++; + hlen -= 2; + + if(hostname[hlen] != ']') + return CURLUE_BAD_IPV6; + + /* only valid letters are ok */ + len = strspn(hostname, l); + if(hlen != len) { + hlen = len; + if(hostname[len] == '%') { + /* this could now be '%[zone id]' */ + char zoneid[16]; + int i = 0; + char *h = &hostname[len + 1]; + /* pass '25' if present and is a url encoded percent sign */ + if(!strncmp(h, "25", 2) && h[2] && (h[2] != ']')) + h += 2; + while(*h && (*h != ']') && (i < 15)) + zoneid[i++] = *h++; + if(!i || (']' != *h)) + /* impossible to reach? */ + return CURLUE_MALFORMED_INPUT; + zoneid[i] = 0; + u->zoneid = strdup(zoneid); + if(!u->zoneid) + return CURLUE_OUT_OF_MEMORY; + hostname[len] = ']'; /* insert end bracket */ + hostname[len + 1] = 0; /* terminate the hostname */ + } + else + return CURLUE_BAD_IPV6; + /* hostname is fine */ + } +#ifdef ENABLE_IPV6 + { + char dest[16]; /* fits a binary IPv6 address */ + char norm[MAX_IPADR_LEN]; + hostname[hlen] = 0; /* end the address there */ + if(1 != Curl_inet_pton(AF_INET6, hostname, dest)) + return CURLUE_BAD_IPV6; + + /* check if it can be done shorter */ + if(Curl_inet_ntop(AF_INET6, dest, norm, sizeof(norm)) && + (strlen(norm) < hlen)) { + strcpy(hostname, norm); + hlen = strlen(norm); + hostname[hlen + 1] = 0; + } + hostname[hlen] = ']'; /* restore ending bracket */ + } +#endif + } + else { + /* letters from the second string are not ok */ + len = strcspn(hostname, " \r\n\t/:#?!@"); + if(hlen != len) + /* hostname with bad content */ + return CURLUE_BAD_HOSTNAME; + } + if(!hostname[0]) + return CURLUE_NO_HOST; + return CURLUE_OK; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-27780/vuln.c b/benchmarks/pairs/vfc/curl-cve-2022-27780/vuln.c new file mode 100644 index 0000000..0debc09 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-27780/vuln.c @@ -0,0 +1,84 @@ +/* Provenance: curl/curl hostname_check (vuln). + * repo: curl/curl + * commit: 5c7da89d404bf59c8dd82a001119a16d18365917 + * parent: 5c7da89d404bf59c8dd82a001119a16d18365917 + * commit_url: https://github.com/curl/curl/commit/914aaab9153764ef8fa4178215b8ad89d3ac263a + * cve: CVE-2022-27780 + * license: curl + * function: hostname_check + * relpath: lib/urlapi.c + */ + +static CURLUcode hostname_check(struct Curl_URL *u, char *hostname) +{ + size_t len; + size_t hlen = strlen(hostname); + + if(hostname[0] == '[') { + const char *l = "0123456789abcdefABCDEF:."; + if(hlen < 4) /* '[::]' is the shortest possible valid string */ + return CURLUE_BAD_IPV6; + hostname++; + hlen -= 2; + + if(hostname[hlen] != ']') + return CURLUE_BAD_IPV6; + + /* only valid letters are ok */ + len = strspn(hostname, l); + if(hlen != len) { + hlen = len; + if(hostname[len] == '%') { + /* this could now be '%[zone id]' */ + char zoneid[16]; + int i = 0; + char *h = &hostname[len + 1]; + /* pass '25' if present and is a url encoded percent sign */ + if(!strncmp(h, "25", 2) && h[2] && (h[2] != ']')) + h += 2; + while(*h && (*h != ']') && (i < 15)) + zoneid[i++] = *h++; + if(!i || (']' != *h)) + /* impossible to reach? */ + return CURLUE_MALFORMED_INPUT; + zoneid[i] = 0; + u->zoneid = strdup(zoneid); + if(!u->zoneid) + return CURLUE_OUT_OF_MEMORY; + hostname[len] = ']'; /* insert end bracket */ + hostname[len + 1] = 0; /* terminate the hostname */ + } + else + return CURLUE_BAD_IPV6; + /* hostname is fine */ + } +#ifdef ENABLE_IPV6 + { + char dest[16]; /* fits a binary IPv6 address */ + char norm[MAX_IPADR_LEN]; + hostname[hlen] = 0; /* end the address there */ + if(1 != Curl_inet_pton(AF_INET6, hostname, dest)) + return CURLUE_BAD_IPV6; + + /* check if it can be done shorter */ + if(Curl_inet_ntop(AF_INET6, dest, norm, sizeof(norm)) && + (strlen(norm) < hlen)) { + strcpy(hostname, norm); + hlen = strlen(norm); + hostname[hlen + 1] = 0; + } + hostname[hlen] = ']'; /* restore ending bracket */ + } +#endif + } + else { + /* letters from the second string is not ok */ + len = strcspn(hostname, " \r\n"); + if(hlen != len) + /* hostname with bad content */ + return CURLUE_BAD_HOSTNAME; + } + if(!hostname[0]) + return CURLUE_NO_HOST; + return CURLUE_OK; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-27782-curl_free_primary_ssl_co/fixed.c b/benchmarks/pairs/vfc/curl-cve-2022-27782-curl_free_primary_ssl_co/fixed.c new file mode 100644 index 0000000..4db16b3 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-27782-curl_free_primary_ssl_co/fixed.c @@ -0,0 +1,32 @@ +/* Provenance: curl/curl Curl_free_primary_ssl_config (fixed). + * repo: curl/curl + * commit: f18af4f874cecab82a9797e8c7541e0990c7a64c + * parent: 7e92d12b4e6911f424678a133b19de670e183a59 + * commit_url: https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c + * cve: CVE-2022-27782 + * license: curl + * function: Curl_free_primary_ssl_config + * relpath: lib/vtls/vtls.c + */ + +void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc) +{ + Curl_safefree(sslc->CApath); + Curl_safefree(sslc->CAfile); + Curl_safefree(sslc->issuercert); + Curl_safefree(sslc->clientcert); + Curl_safefree(sslc->random_file); + Curl_safefree(sslc->egdsocket); + Curl_safefree(sslc->cipher_list); + Curl_safefree(sslc->cipher_list13); + Curl_safefree(sslc->pinned_key); + Curl_safefree(sslc->cert_blob); + Curl_safefree(sslc->ca_info_blob); + Curl_safefree(sslc->issuercert_blob); + Curl_safefree(sslc->curves); + Curl_safefree(sslc->CRLfile); +#ifdef USE_TLS_SRP + Curl_safefree(sslc->username); + Curl_safefree(sslc->password); +#endif +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-27782-curl_free_primary_ssl_co/vuln.c b/benchmarks/pairs/vfc/curl-cve-2022-27782-curl_free_primary_ssl_co/vuln.c new file mode 100644 index 0000000..f757801 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-27782-curl_free_primary_ssl_co/vuln.c @@ -0,0 +1,27 @@ +/* Provenance: curl/curl Curl_free_primary_ssl_config (vuln). + * repo: curl/curl + * commit: 7e92d12b4e6911f424678a133b19de670e183a59 + * parent: 7e92d12b4e6911f424678a133b19de670e183a59 + * commit_url: https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c + * cve: CVE-2022-27782 + * license: curl + * function: Curl_free_primary_ssl_config + * relpath: lib/vtls/vtls.c + */ + +void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc) +{ + Curl_safefree(sslc->CApath); + Curl_safefree(sslc->CAfile); + Curl_safefree(sslc->issuercert); + Curl_safefree(sslc->clientcert); + Curl_safefree(sslc->random_file); + Curl_safefree(sslc->egdsocket); + Curl_safefree(sslc->cipher_list); + Curl_safefree(sslc->cipher_list13); + Curl_safefree(sslc->pinned_key); + Curl_safefree(sslc->cert_blob); + Curl_safefree(sslc->ca_info_blob); + Curl_safefree(sslc->issuercert_blob); + Curl_safefree(sslc->curves); +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-27782-curl_init_userdefined/fixed.c b/benchmarks/pairs/vfc/curl-cve-2022-27782-curl_init_userdefined/fixed.c new file mode 100644 index 0000000..072bdd4 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-27782-curl_init_userdefined/fixed.c @@ -0,0 +1,160 @@ +/* Provenance: curl/curl Curl_init_userdefined (fixed). + * repo: curl/curl + * commit: f18af4f874cecab82a9797e8c7541e0990c7a64c + * parent: 7e92d12b4e6911f424678a133b19de670e183a59 + * commit_url: https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c + * cve: CVE-2022-27782 + * license: curl + * function: Curl_init_userdefined + * relpath: lib/url.c + */ + +CURLcode Curl_init_userdefined(struct Curl_easy *data) +{ + struct UserDefined *set = &data->set; + CURLcode result = CURLE_OK; + + set->out = stdout; /* default output to stdout */ + set->in_set = stdin; /* default input from stdin */ + set->err = stderr; /* default stderr to stderr */ + + /* use fwrite as default function to store output */ + set->fwrite_func = (curl_write_callback)fwrite; + + /* use fread as default function to read input */ + set->fread_func_set = (curl_read_callback)fread; + set->is_fread_set = 0; + set->is_fwrite_set = 0; + + set->seek_func = ZERO_NULL; + set->seek_client = ZERO_NULL; + + set->filesize = -1; /* we don't know the size */ + set->postfieldsize = -1; /* unknown size */ + set->maxredirs = -1; /* allow any amount by default */ + + set->method = HTTPREQ_GET; /* Default HTTP request */ + set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */ +#ifndef CURL_DISABLE_FTP + set->ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */ + set->ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */ + set->ftp_use_pret = FALSE; /* mainly useful for drftpd servers */ + set->ftp_filemethod = FTPFILE_MULTICWD; + set->ftp_skip_ip = TRUE; /* skip PASV IP by default */ +#endif + set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */ + + /* Set the default size of the SSL session ID cache */ + set->general_ssl.max_ssl_sessions = 5; + + set->proxyport = 0; + set->proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */ + set->httpauth = CURLAUTH_BASIC; /* defaults to basic */ + set->proxyauth = CURLAUTH_BASIC; /* defaults to basic */ + + /* SOCKS5 proxy auth defaults to username/password + GSS-API */ + set->socks5auth = CURLAUTH_BASIC | CURLAUTH_GSSAPI; + + /* make libcurl quiet by default: */ + set->hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */ + + Curl_mime_initpart(&set->mimepost, data); + + /* + * libcurl 7.10 introduced SSL verification *by default*! This needs to be + * switched off unless wanted. + */ +#ifndef CURL_DISABLE_DOH + set->doh_verifyhost = TRUE; + set->doh_verifypeer = TRUE; +#endif + set->ssl.primary.verifypeer = TRUE; + set->ssl.primary.verifyhost = TRUE; +#ifdef USE_TLS_SRP + set->ssl.primary.authtype = CURL_TLSAUTH_NONE; +#endif + set->ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth + type */ + set->ssl.primary.sessionid = TRUE; /* session ID caching enabled by + default */ +#ifndef CURL_DISABLE_PROXY + set->proxy_ssl = set->ssl; +#endif + + set->new_file_perms = 0644; /* Default permissions */ + set->new_directory_perms = 0755; /* Default permissions */ + + /* for the *protocols fields we don't use the CURLPROTO_ALL convenience + define since we internally only use the lower 16 bits for the passed + in bitmask to not conflict with the private bits */ + set->allowed_protocols = CURLPROTO_ALL; + set->redir_protocols = CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FTP | + CURLPROTO_FTPS; + +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + /* + * disallow unprotected protection negotiation NEC reference implementation + * seem not to follow rfc1961 section 4.3/4.4 + */ + set->socks5_gssapi_nec = FALSE; +#endif + + /* Set the default CA cert bundle/path detected/specified at build time. + * + * If Schannel is the selected SSL backend then these locations are + * ignored. We allow setting CA location for schannel only when explicitly + * specified by the user via CURLOPT_CAINFO / --cacert. + */ + if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) { +#if defined(CURL_CA_BUNDLE) + result = Curl_setstropt(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE); + if(result) + return result; + + result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PROXY], + CURL_CA_BUNDLE); + if(result) + return result; +#endif +#if defined(CURL_CA_PATH) + result = Curl_setstropt(&set->str[STRING_SSL_CAPATH], CURL_CA_PATH); + if(result) + return result; + + result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_PROXY], CURL_CA_PATH); + if(result) + return result; +#endif + } + + set->wildcard_enabled = FALSE; + set->chunk_bgn = ZERO_NULL; + set->chunk_end = ZERO_NULL; + set->tcp_keepalive = FALSE; + set->tcp_keepintvl = 60; + set->tcp_keepidle = 60; + set->tcp_fastopen = FALSE; + set->tcp_nodelay = TRUE; + set->ssl_enable_npn = TRUE; + set->ssl_enable_alpn = TRUE; + set->expect_100_timeout = 1000L; /* Wait for a second by default. */ + set->sep_headers = TRUE; /* separated header lists by default */ + set->buffer_size = READBUFFER_SIZE; + set->upload_buffer_size = UPLOADBUFFER_DEFAULT; + set->happy_eyeballs_timeout = CURL_HET_DEFAULT; + set->fnmatch = ZERO_NULL; + set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT; + set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */ + set->maxage_conn = 118; + set->maxlifetime_conn = 0; + set->http09_allowed = FALSE; + set->httpwant = +#ifdef USE_HTTP2 + CURL_HTTP_VERSION_2TLS +#else + CURL_HTTP_VERSION_1_1 +#endif + ; + Curl_http2_init_userset(set); + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-27782-curl_init_userdefined/vuln.c b/benchmarks/pairs/vfc/curl-cve-2022-27782-curl_init_userdefined/vuln.c new file mode 100644 index 0000000..a4b2b48 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-27782-curl_init_userdefined/vuln.c @@ -0,0 +1,160 @@ +/* Provenance: curl/curl Curl_init_userdefined (vuln). + * repo: curl/curl + * commit: 7e92d12b4e6911f424678a133b19de670e183a59 + * parent: 7e92d12b4e6911f424678a133b19de670e183a59 + * commit_url: https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c + * cve: CVE-2022-27782 + * license: curl + * function: Curl_init_userdefined + * relpath: lib/url.c + */ + +CURLcode Curl_init_userdefined(struct Curl_easy *data) +{ + struct UserDefined *set = &data->set; + CURLcode result = CURLE_OK; + + set->out = stdout; /* default output to stdout */ + set->in_set = stdin; /* default input from stdin */ + set->err = stderr; /* default stderr to stderr */ + + /* use fwrite as default function to store output */ + set->fwrite_func = (curl_write_callback)fwrite; + + /* use fread as default function to read input */ + set->fread_func_set = (curl_read_callback)fread; + set->is_fread_set = 0; + set->is_fwrite_set = 0; + + set->seek_func = ZERO_NULL; + set->seek_client = ZERO_NULL; + + set->filesize = -1; /* we don't know the size */ + set->postfieldsize = -1; /* unknown size */ + set->maxredirs = -1; /* allow any amount by default */ + + set->method = HTTPREQ_GET; /* Default HTTP request */ + set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */ +#ifndef CURL_DISABLE_FTP + set->ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */ + set->ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */ + set->ftp_use_pret = FALSE; /* mainly useful for drftpd servers */ + set->ftp_filemethod = FTPFILE_MULTICWD; + set->ftp_skip_ip = TRUE; /* skip PASV IP by default */ +#endif + set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */ + + /* Set the default size of the SSL session ID cache */ + set->general_ssl.max_ssl_sessions = 5; + + set->proxyport = 0; + set->proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */ + set->httpauth = CURLAUTH_BASIC; /* defaults to basic */ + set->proxyauth = CURLAUTH_BASIC; /* defaults to basic */ + + /* SOCKS5 proxy auth defaults to username/password + GSS-API */ + set->socks5auth = CURLAUTH_BASIC | CURLAUTH_GSSAPI; + + /* make libcurl quiet by default: */ + set->hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */ + + Curl_mime_initpart(&set->mimepost, data); + + /* + * libcurl 7.10 introduced SSL verification *by default*! This needs to be + * switched off unless wanted. + */ +#ifndef CURL_DISABLE_DOH + set->doh_verifyhost = TRUE; + set->doh_verifypeer = TRUE; +#endif + set->ssl.primary.verifypeer = TRUE; + set->ssl.primary.verifyhost = TRUE; +#ifdef USE_TLS_SRP + set->ssl.authtype = CURL_TLSAUTH_NONE; +#endif + set->ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth + type */ + set->ssl.primary.sessionid = TRUE; /* session ID caching enabled by + default */ +#ifndef CURL_DISABLE_PROXY + set->proxy_ssl = set->ssl; +#endif + + set->new_file_perms = 0644; /* Default permissions */ + set->new_directory_perms = 0755; /* Default permissions */ + + /* for the *protocols fields we don't use the CURLPROTO_ALL convenience + define since we internally only use the lower 16 bits for the passed + in bitmask to not conflict with the private bits */ + set->allowed_protocols = CURLPROTO_ALL; + set->redir_protocols = CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FTP | + CURLPROTO_FTPS; + +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + /* + * disallow unprotected protection negotiation NEC reference implementation + * seem not to follow rfc1961 section 4.3/4.4 + */ + set->socks5_gssapi_nec = FALSE; +#endif + + /* Set the default CA cert bundle/path detected/specified at build time. + * + * If Schannel is the selected SSL backend then these locations are + * ignored. We allow setting CA location for schannel only when explicitly + * specified by the user via CURLOPT_CAINFO / --cacert. + */ + if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) { +#if defined(CURL_CA_BUNDLE) + result = Curl_setstropt(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE); + if(result) + return result; + + result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PROXY], + CURL_CA_BUNDLE); + if(result) + return result; +#endif +#if defined(CURL_CA_PATH) + result = Curl_setstropt(&set->str[STRING_SSL_CAPATH], CURL_CA_PATH); + if(result) + return result; + + result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_PROXY], CURL_CA_PATH); + if(result) + return result; +#endif + } + + set->wildcard_enabled = FALSE; + set->chunk_bgn = ZERO_NULL; + set->chunk_end = ZERO_NULL; + set->tcp_keepalive = FALSE; + set->tcp_keepintvl = 60; + set->tcp_keepidle = 60; + set->tcp_fastopen = FALSE; + set->tcp_nodelay = TRUE; + set->ssl_enable_npn = TRUE; + set->ssl_enable_alpn = TRUE; + set->expect_100_timeout = 1000L; /* Wait for a second by default. */ + set->sep_headers = TRUE; /* separated header lists by default */ + set->buffer_size = READBUFFER_SIZE; + set->upload_buffer_size = UPLOADBUFFER_DEFAULT; + set->happy_eyeballs_timeout = CURL_HET_DEFAULT; + set->fnmatch = ZERO_NULL; + set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT; + set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */ + set->maxage_conn = 118; + set->maxlifetime_conn = 0; + set->http09_allowed = FALSE; + set->httpwant = +#ifdef USE_HTTP2 + CURL_HTTP_VERSION_2TLS +#else + CURL_HTTP_VERSION_1_1 +#endif + ; + Curl_http2_init_userset(set); + return result; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-27782-gtls_shutdown/fixed.c b/benchmarks/pairs/vfc/curl-cve-2022-27782-gtls_shutdown/fixed.c new file mode 100644 index 0000000..c0968d8 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-27782-gtls_shutdown/fixed.c @@ -0,0 +1,86 @@ +/* Provenance: curl/curl gtls_shutdown (fixed). + * repo: curl/curl + * commit: f18af4f874cecab82a9797e8c7541e0990c7a64c + * parent: 7e92d12b4e6911f424678a133b19de670e183a59 + * commit_url: https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c + * cve: CVE-2022-27782 + * license: curl + * function: gtls_shutdown + * relpath: lib/vtls/gtls.c + */ + +static int gtls_shutdown(struct Curl_easy *data, struct connectdata *conn, + int sockindex) +{ + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; + int retval = 0; + + DEBUGASSERT(backend); + +#ifndef CURL_DISABLE_FTP + /* This has only been tested on the proftpd server, and the mod_tls code + sends a close notify alert without waiting for a close notify alert in + response. Thus we wait for a close notify alert from the server, but + we do not send one. Let's hope other servers do the same... */ + + if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE) + gnutls_bye(backend->session, GNUTLS_SHUT_WR); +#endif + + if(backend->session) { + ssize_t result; + bool done = FALSE; + char buf[120]; + + while(!done) { + int what = SOCKET_READABLE(conn->sock[sockindex], + SSL_SHUTDOWN_TIMEOUT); + if(what > 0) { + /* Something to read, let's do it and hope that it is the close + notify alert from the server */ + result = gnutls_record_recv(backend->session, + buf, sizeof(buf)); + switch(result) { + case 0: + /* This is the expected response. There was no data but only + the close notify alert */ + done = TRUE; + break; + case GNUTLS_E_AGAIN: + case GNUTLS_E_INTERRUPTED: + infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED"); + break; + default: + retval = -1; + done = TRUE; + break; + } + } + else if(0 == what) { + /* timeout */ + failf(data, "SSL shutdown timeout"); + done = TRUE; + } + else { + /* anything that gets here is fatally bad */ + failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); + retval = -1; + done = TRUE; + } + } + gnutls_deinit(backend->session); + } + gnutls_certificate_free_credentials(backend->cred); + +#ifdef USE_GNUTLS_SRP + if(SSL_SET_OPTION(primary.authtype) == CURL_TLSAUTH_SRP + && SSL_SET_OPTION(primary.username) != NULL) + gnutls_srp_free_client_credentials(backend->srp_client_cred); +#endif + + backend->cred = NULL; + backend->session = NULL; + + return retval; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-27782-gtls_shutdown/vuln.c b/benchmarks/pairs/vfc/curl-cve-2022-27782-gtls_shutdown/vuln.c new file mode 100644 index 0000000..730ed5b --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-27782-gtls_shutdown/vuln.c @@ -0,0 +1,86 @@ +/* Provenance: curl/curl gtls_shutdown (vuln). + * repo: curl/curl + * commit: 7e92d12b4e6911f424678a133b19de670e183a59 + * parent: 7e92d12b4e6911f424678a133b19de670e183a59 + * commit_url: https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c + * cve: CVE-2022-27782 + * license: curl + * function: gtls_shutdown + * relpath: lib/vtls/gtls.c + */ + +static int gtls_shutdown(struct Curl_easy *data, struct connectdata *conn, + int sockindex) +{ + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; + int retval = 0; + + DEBUGASSERT(backend); + +#ifndef CURL_DISABLE_FTP + /* This has only been tested on the proftpd server, and the mod_tls code + sends a close notify alert without waiting for a close notify alert in + response. Thus we wait for a close notify alert from the server, but + we do not send one. Let's hope other servers do the same... */ + + if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE) + gnutls_bye(backend->session, GNUTLS_SHUT_WR); +#endif + + if(backend->session) { + ssize_t result; + bool done = FALSE; + char buf[120]; + + while(!done) { + int what = SOCKET_READABLE(conn->sock[sockindex], + SSL_SHUTDOWN_TIMEOUT); + if(what > 0) { + /* Something to read, let's do it and hope that it is the close + notify alert from the server */ + result = gnutls_record_recv(backend->session, + buf, sizeof(buf)); + switch(result) { + case 0: + /* This is the expected response. There was no data but only + the close notify alert */ + done = TRUE; + break; + case GNUTLS_E_AGAIN: + case GNUTLS_E_INTERRUPTED: + infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED"); + break; + default: + retval = -1; + done = TRUE; + break; + } + } + else if(0 == what) { + /* timeout */ + failf(data, "SSL shutdown timeout"); + done = TRUE; + } + else { + /* anything that gets here is fatally bad */ + failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); + retval = -1; + done = TRUE; + } + } + gnutls_deinit(backend->session); + } + gnutls_certificate_free_credentials(backend->cred); + +#ifdef USE_GNUTLS_SRP + if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP + && SSL_SET_OPTION(username) != NULL) + gnutls_srp_free_client_credentials(backend->srp_client_cred); +#endif + + backend->cred = NULL; + backend->session = NULL; + + return retval; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-27782-nss_setup_connect/fixed.c b/benchmarks/pairs/vfc/curl-cve-2022-27782-nss_setup_connect/fixed.c new file mode 100644 index 0000000..c7a9d39 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-27782-nss_setup_connect/fixed.c @@ -0,0 +1,324 @@ +/* Provenance: curl/curl nss_setup_connect (fixed). + * repo: curl/curl + * commit: f18af4f874cecab82a9797e8c7541e0990c7a64c + * parent: 7e92d12b4e6911f424678a133b19de670e183a59 + * commit_url: https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c + * cve: CVE-2022-27782 + * license: curl + * function: nss_setup_connect + * relpath: lib/vtls/nss.c + */ + +static CURLcode nss_setup_connect(struct Curl_easy *data, + struct connectdata *conn, int sockindex) +{ + PRFileDesc *model = NULL; + PRFileDesc *nspr_io = NULL; + PRFileDesc *nspr_io_stub = NULL; + PRBool ssl_no_cache; + PRBool ssl_cbc_random_iv; + curl_socket_t sockfd = conn->sock[sockindex]; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; + CURLcode result; + bool second_layer = FALSE; + SSLVersionRange sslver_supported; + SSLVersionRange sslver = { + SSL_LIBRARY_VERSION_TLS_1_0, /* min */ +#ifdef SSL_LIBRARY_VERSION_TLS_1_3 + SSL_LIBRARY_VERSION_TLS_1_3 /* max */ +#elif defined SSL_LIBRARY_VERSION_TLS_1_2 + SSL_LIBRARY_VERSION_TLS_1_2 +#elif defined SSL_LIBRARY_VERSION_TLS_1_1 + SSL_LIBRARY_VERSION_TLS_1_1 +#else + SSL_LIBRARY_VERSION_TLS_1_0 +#endif + }; + char *snihost = Curl_ssl_snihost(data, SSL_HOST_NAME(), NULL); + if(!snihost) { + failf(data, "Failed to set SNI"); + return CURLE_SSL_CONNECT_ERROR; + } + + DEBUGASSERT(backend); + + backend->data = data; + + /* list of all NSS objects we need to destroy in nss_do_close() */ + Curl_llist_init(&backend->obj_list, nss_destroy_object); + + PR_Lock(nss_initlock); + result = nss_setup(data); + if(result) { + PR_Unlock(nss_initlock); + goto error; + } + + PK11_SetPasswordFunc(nss_get_password); + + result = nss_load_module(&pem_module, pem_library, "PEM"); + PR_Unlock(nss_initlock); + if(result == CURLE_FAILED_INIT) + infof(data, "WARNING: failed to load NSS PEM library %s. Using " + "OpenSSL PEM certificates will not work.", pem_library); + else if(result) + goto error; + + result = CURLE_SSL_CONNECT_ERROR; + + model = PR_NewTCPSocket(); + if(!model) + goto error; + model = SSL_ImportFD(NULL, model); + + if(SSL_OptionSet(model, SSL_SECURITY, PR_TRUE) != SECSuccess) + goto error; + if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) != SECSuccess) + goto error; + if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != SECSuccess) + goto error; + + /* do not use SSL cache if disabled or we are not going to verify peer */ + ssl_no_cache = (SSL_SET_OPTION(primary.sessionid) + && SSL_CONN_CONFIG(verifypeer)) ? PR_FALSE : PR_TRUE; + if(SSL_OptionSet(model, SSL_NO_CACHE, ssl_no_cache) != SECSuccess) + goto error; + + /* enable/disable the requested SSL version(s) */ + if(nss_init_sslver(&sslver, data, conn) != CURLE_OK) + goto error; + if(SSL_VersionRangeGetSupported(ssl_variant_stream, + &sslver_supported) != SECSuccess) + goto error; + if(sslver_supported.max < sslver.max && sslver_supported.max >= sslver.min) { + char *sslver_req_str, *sslver_supp_str; + sslver_req_str = nss_sslver_to_name(sslver.max); + sslver_supp_str = nss_sslver_to_name(sslver_supported.max); + if(sslver_req_str && sslver_supp_str) + infof(data, "Falling back from %s to max supported SSL version (%s)", + sslver_req_str, sslver_supp_str); + free(sslver_req_str); + free(sslver_supp_str); + sslver.max = sslver_supported.max; + } + if(SSL_VersionRangeSet(model, &sslver) != SECSuccess) + goto error; + + ssl_cbc_random_iv = !SSL_SET_OPTION(enable_beast); +#ifdef SSL_CBC_RANDOM_IV + /* unless the user explicitly asks to allow the protocol vulnerability, we + use the work-around */ + if(SSL_OptionSet(model, SSL_CBC_RANDOM_IV, ssl_cbc_random_iv) != SECSuccess) + infof(data, "WARNING: failed to set SSL_CBC_RANDOM_IV = %d", + ssl_cbc_random_iv); +#else + if(ssl_cbc_random_iv) + infof(data, "WARNING: support for SSL_CBC_RANDOM_IV not compiled in"); +#endif + + if(SSL_CONN_CONFIG(cipher_list)) { + if(set_ciphers(data, model, SSL_CONN_CONFIG(cipher_list)) != SECSuccess) { + result = CURLE_SSL_CIPHER; + goto error; + } + } + + if(!SSL_CONN_CONFIG(verifypeer) && SSL_CONN_CONFIG(verifyhost)) + infof(data, "WARNING: ignoring value of ssl.verifyhost"); + + /* bypass the default SSL_AuthCertificate() hook in case we do not want to + * verify peer */ + if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, data) != SECSuccess) + goto error; + + /* not checked yet */ + SSL_SET_OPTION_LVALUE(certverifyresult) = 0; + + if(SSL_BadCertHook(model, BadCertHandler, data) != SECSuccess) + goto error; + + if(SSL_HandshakeCallback(model, HandshakeCallback, data) != SECSuccess) + goto error; + + { + const CURLcode rv = nss_load_ca_certificates(data, conn, sockindex); + if((rv == CURLE_SSL_CACERT_BADFILE) && !SSL_CONN_CONFIG(verifypeer)) + /* not a fatal error because we are not going to verify the peer */ + infof(data, "WARNING: CA certificates failed to load"); + else if(rv) { + result = rv; + goto error; + } + } + + if(SSL_SET_OPTION(primary.CRLfile)) { + const CURLcode rv = nss_load_crl(SSL_SET_OPTION(primary.CRLfile)); + if(rv) { + result = rv; + goto error; + } + infof(data, " CRLfile: %s", SSL_SET_OPTION(primary.CRLfile)); + } + + if(SSL_SET_OPTION(primary.clientcert)) { + char *nickname = dup_nickname(data, SSL_SET_OPTION(primary.clientcert)); + if(nickname) { + /* we are not going to use libnsspem.so to read the client cert */ + backend->obj_clicert = NULL; + } + else { + CURLcode rv = cert_stuff(data, conn, sockindex, + SSL_SET_OPTION(primary.clientcert), + SSL_SET_OPTION(key)); + if(rv) { + /* failf() is already done in cert_stuff() */ + result = rv; + goto error; + } + } + + /* store the nickname for SelectClientCert() called during handshake */ + backend->client_nickname = nickname; + } + else + backend->client_nickname = NULL; + + if(SSL_GetClientAuthDataHook(model, SelectClientCert, + (void *)connssl) != SECSuccess) { + result = CURLE_SSL_CERTPROBLEM; + goto error; + } + +#ifndef CURL_DISABLE_PROXY + if(conn->proxy_ssl[sockindex].use) { + struct ssl_backend_data *proxy_backend; + proxy_backend = conn->proxy_ssl[sockindex].backend; + DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state); + DEBUGASSERT(proxy_backend); + DEBUGASSERT(proxy_backend->handle); + nspr_io = proxy_backend->handle; + second_layer = TRUE; + } +#endif + else { + /* wrap OS file descriptor by NSPR's file descriptor abstraction */ + nspr_io = PR_ImportTCPSocket(sockfd); + if(!nspr_io) + goto error; + } + + /* create our own NSPR I/O layer */ + nspr_io_stub = PR_CreateIOLayerStub(nspr_io_identity, &nspr_io_methods); + if(!nspr_io_stub) { + if(!second_layer) + PR_Close(nspr_io); + goto error; + } + + /* make the per-connection data accessible from NSPR I/O callbacks */ + nspr_io_stub->secret = (void *)connssl; + + /* push our new layer to the NSPR I/O stack */ + if(PR_PushIOLayer(nspr_io, PR_TOP_IO_LAYER, nspr_io_stub) != PR_SUCCESS) { + if(!second_layer) + PR_Close(nspr_io); + PR_Close(nspr_io_stub); + goto error; + } + + /* import our model socket onto the current I/O stack */ + backend->handle = SSL_ImportFD(model, nspr_io); + if(!backend->handle) { + if(!second_layer) + PR_Close(nspr_io); + goto error; + } + + PR_Close(model); /* We don't need this any more */ + model = NULL; + + /* This is the password associated with the cert that we're using */ + if(SSL_SET_OPTION(key_passwd)) { + SSL_SetPKCS11PinArg(backend->handle, SSL_SET_OPTION(key_passwd)); + } + +#ifdef SSL_ENABLE_OCSP_STAPLING + if(SSL_CONN_CONFIG(verifystatus)) { + if(SSL_OptionSet(backend->handle, SSL_ENABLE_OCSP_STAPLING, PR_TRUE) + != SECSuccess) + goto error; + } +#endif + +#ifdef SSL_ENABLE_NPN + if(SSL_OptionSet(backend->handle, SSL_ENABLE_NPN, conn->bits.tls_enable_npn + ? PR_TRUE : PR_FALSE) != SECSuccess) + goto error; +#endif + +#ifdef SSL_ENABLE_ALPN + if(SSL_OptionSet(backend->handle, SSL_ENABLE_ALPN, conn->bits.tls_enable_alpn + ? PR_TRUE : PR_FALSE) != SECSuccess) + goto error; +#endif + +#if NSSVERNUM >= 0x030f04 /* 3.15.4 */ + if(data->set.ssl.falsestart) { + if(SSL_OptionSet(backend->handle, SSL_ENABLE_FALSE_START, PR_TRUE) + != SECSuccess) + goto error; + + if(SSL_SetCanFalseStartCallback(backend->handle, CanFalseStartCallback, + data) != SECSuccess) + goto error; + } +#endif + +#if defined(SSL_ENABLE_NPN) || defined(SSL_ENABLE_ALPN) + if(conn->bits.tls_enable_npn || conn->bits.tls_enable_alpn) { + int cur = 0; + unsigned char protocols[128]; + +#ifdef USE_HTTP2 + if(data->state.httpwant >= CURL_HTTP_VERSION_2 +#ifndef CURL_DISABLE_PROXY + && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy) +#endif + ) { + protocols[cur++] = ALPN_H2_LENGTH; + memcpy(&protocols[cur], ALPN_H2, ALPN_H2_LENGTH); + cur += ALPN_H2_LENGTH; + } +#endif + protocols[cur++] = ALPN_HTTP_1_1_LENGTH; + memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); + cur += ALPN_HTTP_1_1_LENGTH; + + if(SSL_SetNextProtoNego(backend->handle, protocols, cur) != SECSuccess) + goto error; + } +#endif + + + /* Force handshake on next I/O */ + if(SSL_ResetHandshake(backend->handle, /* asServer */ PR_FALSE) + != SECSuccess) + goto error; + + /* propagate hostname to the TLS layer */ + if(SSL_SetURL(backend->handle, snihost) != SECSuccess) + goto error; + + /* prevent NSS from re-using the session for a different hostname */ + if(SSL_SetSockPeerID(backend->handle, snihost) != SECSuccess) + goto error; + + return CURLE_OK; + +error: + if(model) + PR_Close(model); + + return nss_fail_connect(connssl, data, result); +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-27782-nss_setup_connect/vuln.c b/benchmarks/pairs/vfc/curl-cve-2022-27782-nss_setup_connect/vuln.c new file mode 100644 index 0000000..1b113fb --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-27782-nss_setup_connect/vuln.c @@ -0,0 +1,324 @@ +/* Provenance: curl/curl nss_setup_connect (vuln). + * repo: curl/curl + * commit: 7e92d12b4e6911f424678a133b19de670e183a59 + * parent: 7e92d12b4e6911f424678a133b19de670e183a59 + * commit_url: https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c + * cve: CVE-2022-27782 + * license: curl + * function: nss_setup_connect + * relpath: lib/vtls/nss.c + */ + +static CURLcode nss_setup_connect(struct Curl_easy *data, + struct connectdata *conn, int sockindex) +{ + PRFileDesc *model = NULL; + PRFileDesc *nspr_io = NULL; + PRFileDesc *nspr_io_stub = NULL; + PRBool ssl_no_cache; + PRBool ssl_cbc_random_iv; + curl_socket_t sockfd = conn->sock[sockindex]; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_backend_data *backend = connssl->backend; + CURLcode result; + bool second_layer = FALSE; + SSLVersionRange sslver_supported; + SSLVersionRange sslver = { + SSL_LIBRARY_VERSION_TLS_1_0, /* min */ +#ifdef SSL_LIBRARY_VERSION_TLS_1_3 + SSL_LIBRARY_VERSION_TLS_1_3 /* max */ +#elif defined SSL_LIBRARY_VERSION_TLS_1_2 + SSL_LIBRARY_VERSION_TLS_1_2 +#elif defined SSL_LIBRARY_VERSION_TLS_1_1 + SSL_LIBRARY_VERSION_TLS_1_1 +#else + SSL_LIBRARY_VERSION_TLS_1_0 +#endif + }; + char *snihost = Curl_ssl_snihost(data, SSL_HOST_NAME(), NULL); + if(!snihost) { + failf(data, "Failed to set SNI"); + return CURLE_SSL_CONNECT_ERROR; + } + + DEBUGASSERT(backend); + + backend->data = data; + + /* list of all NSS objects we need to destroy in nss_do_close() */ + Curl_llist_init(&backend->obj_list, nss_destroy_object); + + PR_Lock(nss_initlock); + result = nss_setup(data); + if(result) { + PR_Unlock(nss_initlock); + goto error; + } + + PK11_SetPasswordFunc(nss_get_password); + + result = nss_load_module(&pem_module, pem_library, "PEM"); + PR_Unlock(nss_initlock); + if(result == CURLE_FAILED_INIT) + infof(data, "WARNING: failed to load NSS PEM library %s. Using " + "OpenSSL PEM certificates will not work.", pem_library); + else if(result) + goto error; + + result = CURLE_SSL_CONNECT_ERROR; + + model = PR_NewTCPSocket(); + if(!model) + goto error; + model = SSL_ImportFD(NULL, model); + + if(SSL_OptionSet(model, SSL_SECURITY, PR_TRUE) != SECSuccess) + goto error; + if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) != SECSuccess) + goto error; + if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != SECSuccess) + goto error; + + /* do not use SSL cache if disabled or we are not going to verify peer */ + ssl_no_cache = (SSL_SET_OPTION(primary.sessionid) + && SSL_CONN_CONFIG(verifypeer)) ? PR_FALSE : PR_TRUE; + if(SSL_OptionSet(model, SSL_NO_CACHE, ssl_no_cache) != SECSuccess) + goto error; + + /* enable/disable the requested SSL version(s) */ + if(nss_init_sslver(&sslver, data, conn) != CURLE_OK) + goto error; + if(SSL_VersionRangeGetSupported(ssl_variant_stream, + &sslver_supported) != SECSuccess) + goto error; + if(sslver_supported.max < sslver.max && sslver_supported.max >= sslver.min) { + char *sslver_req_str, *sslver_supp_str; + sslver_req_str = nss_sslver_to_name(sslver.max); + sslver_supp_str = nss_sslver_to_name(sslver_supported.max); + if(sslver_req_str && sslver_supp_str) + infof(data, "Falling back from %s to max supported SSL version (%s)", + sslver_req_str, sslver_supp_str); + free(sslver_req_str); + free(sslver_supp_str); + sslver.max = sslver_supported.max; + } + if(SSL_VersionRangeSet(model, &sslver) != SECSuccess) + goto error; + + ssl_cbc_random_iv = !SSL_SET_OPTION(enable_beast); +#ifdef SSL_CBC_RANDOM_IV + /* unless the user explicitly asks to allow the protocol vulnerability, we + use the work-around */ + if(SSL_OptionSet(model, SSL_CBC_RANDOM_IV, ssl_cbc_random_iv) != SECSuccess) + infof(data, "WARNING: failed to set SSL_CBC_RANDOM_IV = %d", + ssl_cbc_random_iv); +#else + if(ssl_cbc_random_iv) + infof(data, "WARNING: support for SSL_CBC_RANDOM_IV not compiled in"); +#endif + + if(SSL_CONN_CONFIG(cipher_list)) { + if(set_ciphers(data, model, SSL_CONN_CONFIG(cipher_list)) != SECSuccess) { + result = CURLE_SSL_CIPHER; + goto error; + } + } + + if(!SSL_CONN_CONFIG(verifypeer) && SSL_CONN_CONFIG(verifyhost)) + infof(data, "WARNING: ignoring value of ssl.verifyhost"); + + /* bypass the default SSL_AuthCertificate() hook in case we do not want to + * verify peer */ + if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, data) != SECSuccess) + goto error; + + /* not checked yet */ + SSL_SET_OPTION_LVALUE(certverifyresult) = 0; + + if(SSL_BadCertHook(model, BadCertHandler, data) != SECSuccess) + goto error; + + if(SSL_HandshakeCallback(model, HandshakeCallback, data) != SECSuccess) + goto error; + + { + const CURLcode rv = nss_load_ca_certificates(data, conn, sockindex); + if((rv == CURLE_SSL_CACERT_BADFILE) && !SSL_CONN_CONFIG(verifypeer)) + /* not a fatal error because we are not going to verify the peer */ + infof(data, "WARNING: CA certificates failed to load"); + else if(rv) { + result = rv; + goto error; + } + } + + if(SSL_SET_OPTION(CRLfile)) { + const CURLcode rv = nss_load_crl(SSL_SET_OPTION(CRLfile)); + if(rv) { + result = rv; + goto error; + } + infof(data, " CRLfile: %s", SSL_SET_OPTION(CRLfile)); + } + + if(SSL_SET_OPTION(primary.clientcert)) { + char *nickname = dup_nickname(data, SSL_SET_OPTION(primary.clientcert)); + if(nickname) { + /* we are not going to use libnsspem.so to read the client cert */ + backend->obj_clicert = NULL; + } + else { + CURLcode rv = cert_stuff(data, conn, sockindex, + SSL_SET_OPTION(primary.clientcert), + SSL_SET_OPTION(key)); + if(rv) { + /* failf() is already done in cert_stuff() */ + result = rv; + goto error; + } + } + + /* store the nickname for SelectClientCert() called during handshake */ + backend->client_nickname = nickname; + } + else + backend->client_nickname = NULL; + + if(SSL_GetClientAuthDataHook(model, SelectClientCert, + (void *)connssl) != SECSuccess) { + result = CURLE_SSL_CERTPROBLEM; + goto error; + } + +#ifndef CURL_DISABLE_PROXY + if(conn->proxy_ssl[sockindex].use) { + struct ssl_backend_data *proxy_backend; + proxy_backend = conn->proxy_ssl[sockindex].backend; + DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state); + DEBUGASSERT(proxy_backend); + DEBUGASSERT(proxy_backend->handle); + nspr_io = proxy_backend->handle; + second_layer = TRUE; + } +#endif + else { + /* wrap OS file descriptor by NSPR's file descriptor abstraction */ + nspr_io = PR_ImportTCPSocket(sockfd); + if(!nspr_io) + goto error; + } + + /* create our own NSPR I/O layer */ + nspr_io_stub = PR_CreateIOLayerStub(nspr_io_identity, &nspr_io_methods); + if(!nspr_io_stub) { + if(!second_layer) + PR_Close(nspr_io); + goto error; + } + + /* make the per-connection data accessible from NSPR I/O callbacks */ + nspr_io_stub->secret = (void *)connssl; + + /* push our new layer to the NSPR I/O stack */ + if(PR_PushIOLayer(nspr_io, PR_TOP_IO_LAYER, nspr_io_stub) != PR_SUCCESS) { + if(!second_layer) + PR_Close(nspr_io); + PR_Close(nspr_io_stub); + goto error; + } + + /* import our model socket onto the current I/O stack */ + backend->handle = SSL_ImportFD(model, nspr_io); + if(!backend->handle) { + if(!second_layer) + PR_Close(nspr_io); + goto error; + } + + PR_Close(model); /* We don't need this any more */ + model = NULL; + + /* This is the password associated with the cert that we're using */ + if(SSL_SET_OPTION(key_passwd)) { + SSL_SetPKCS11PinArg(backend->handle, SSL_SET_OPTION(key_passwd)); + } + +#ifdef SSL_ENABLE_OCSP_STAPLING + if(SSL_CONN_CONFIG(verifystatus)) { + if(SSL_OptionSet(backend->handle, SSL_ENABLE_OCSP_STAPLING, PR_TRUE) + != SECSuccess) + goto error; + } +#endif + +#ifdef SSL_ENABLE_NPN + if(SSL_OptionSet(backend->handle, SSL_ENABLE_NPN, conn->bits.tls_enable_npn + ? PR_TRUE : PR_FALSE) != SECSuccess) + goto error; +#endif + +#ifdef SSL_ENABLE_ALPN + if(SSL_OptionSet(backend->handle, SSL_ENABLE_ALPN, conn->bits.tls_enable_alpn + ? PR_TRUE : PR_FALSE) != SECSuccess) + goto error; +#endif + +#if NSSVERNUM >= 0x030f04 /* 3.15.4 */ + if(data->set.ssl.falsestart) { + if(SSL_OptionSet(backend->handle, SSL_ENABLE_FALSE_START, PR_TRUE) + != SECSuccess) + goto error; + + if(SSL_SetCanFalseStartCallback(backend->handle, CanFalseStartCallback, + data) != SECSuccess) + goto error; + } +#endif + +#if defined(SSL_ENABLE_NPN) || defined(SSL_ENABLE_ALPN) + if(conn->bits.tls_enable_npn || conn->bits.tls_enable_alpn) { + int cur = 0; + unsigned char protocols[128]; + +#ifdef USE_HTTP2 + if(data->state.httpwant >= CURL_HTTP_VERSION_2 +#ifndef CURL_DISABLE_PROXY + && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy) +#endif + ) { + protocols[cur++] = ALPN_H2_LENGTH; + memcpy(&protocols[cur], ALPN_H2, ALPN_H2_LENGTH); + cur += ALPN_H2_LENGTH; + } +#endif + protocols[cur++] = ALPN_HTTP_1_1_LENGTH; + memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); + cur += ALPN_HTTP_1_1_LENGTH; + + if(SSL_SetNextProtoNego(backend->handle, protocols, cur) != SECSuccess) + goto error; + } +#endif + + + /* Force handshake on next I/O */ + if(SSL_ResetHandshake(backend->handle, /* asServer */ PR_FALSE) + != SECSuccess) + goto error; + + /* propagate hostname to the TLS layer */ + if(SSL_SetURL(backend->handle, snihost) != SECSuccess) + goto error; + + /* prevent NSS from re-using the session for a different hostname */ + if(SSL_SetSockPeerID(backend->handle, snihost) != SECSuccess) + goto error; + + return CURLE_OK; + +error: + if(model) + PR_Close(model); + + return nss_fail_connect(connssl, data, result); +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-27782-ossl_connect_step1/fixed.c b/benchmarks/pairs/vfc/curl-cve-2022-27782-ossl_connect_step1/fixed.c new file mode 100644 index 0000000..fda13d8 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-27782-ossl_connect_step1/fixed.c @@ -0,0 +1,688 @@ +/* Provenance: curl/curl ossl_connect_step1 (fixed). + * repo: curl/curl + * commit: f18af4f874cecab82a9797e8c7541e0990c7a64c + * parent: 7e92d12b4e6911f424678a133b19de670e183a59 + * commit_url: https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c + * cve: CVE-2022-27782 + * license: curl + * function: ossl_connect_step1 + * relpath: lib/vtls/openssl.c + */ + +static CURLcode ossl_connect_step1(struct Curl_easy *data, + struct connectdata *conn, int sockindex) +{ + CURLcode result = CURLE_OK; + char *ciphers; + SSL_METHOD_QUAL SSL_METHOD *req_method = NULL; + X509_LOOKUP *lookup = NULL; + curl_socket_t sockfd = conn->sock[sockindex]; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + ctx_option_t ctx_options = 0; + void *ssl_sessionid = NULL; + +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + bool sni; + const char * const hostname = SSL_HOST_NAME(); + +#ifdef ENABLE_IPV6 + struct in6_addr addr; +#else + struct in_addr addr; +#endif +#endif + const long int ssl_version = SSL_CONN_CONFIG(version); +#ifdef USE_OPENSSL_SRP + const enum CURL_TLSAUTH ssl_authtype = SSL_SET_OPTION(primary.authtype); +#endif + char * const ssl_cert = SSL_SET_OPTION(primary.clientcert); + const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(primary.cert_blob); + const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_blob); + const char * const ssl_cert_type = SSL_SET_OPTION(cert_type); + const char * const ssl_cafile = + /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */ + (ca_info_blob ? NULL : SSL_CONN_CONFIG(CAfile)); + const char * const ssl_capath = SSL_CONN_CONFIG(CApath); + const bool verifypeer = SSL_CONN_CONFIG(verifypeer); + const char * const ssl_crlfile = SSL_SET_OPTION(primary.CRLfile); + char error_buffer[256]; + struct ssl_backend_data *backend = connssl->backend; + bool imported_native_ca = false; + + DEBUGASSERT(ssl_connect_1 == connssl->connecting_state); + DEBUGASSERT(backend); + + /* Make funny stuff to get random input */ + result = ossl_seed(data); + if(result) + return result; + + SSL_SET_OPTION_LVALUE(certverifyresult) = !X509_V_OK; + + /* check to see if we've been told to use an explicit SSL/TLS version */ + + switch(ssl_version) { + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + case CURL_SSLVERSION_TLSv1_0: + case CURL_SSLVERSION_TLSv1_1: + case CURL_SSLVERSION_TLSv1_2: + case CURL_SSLVERSION_TLSv1_3: + /* it will be handled later with the context options */ +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) + req_method = TLS_client_method(); +#else + req_method = SSLv23_client_method(); +#endif + use_sni(TRUE); + break; + case CURL_SSLVERSION_SSLv2: + failf(data, "No SSLv2 support"); + return CURLE_NOT_BUILT_IN; + case CURL_SSLVERSION_SSLv3: + failf(data, "No SSLv3 support"); + return CURLE_NOT_BUILT_IN; + default: + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; + } + + DEBUGASSERT(!backend->ctx); + backend->ctx = SSL_CTX_new(req_method); + + if(!backend->ctx) { + failf(data, "SSL: couldn't create a context: %s", + ossl_strerror(ERR_peek_error(), error_buffer, sizeof(error_buffer))); + return CURLE_OUT_OF_MEMORY; + } + +#ifdef SSL_MODE_RELEASE_BUFFERS + SSL_CTX_set_mode(backend->ctx, SSL_MODE_RELEASE_BUFFERS); +#endif + +#ifdef SSL_CTRL_SET_MSG_CALLBACK + if(data->set.fdebug && data->set.verbose) { + /* the SSL trace callback is only used for verbose logging */ + SSL_CTX_set_msg_callback(backend->ctx, ossl_trace); + SSL_CTX_set_msg_callback_arg(backend->ctx, conn); + set_logger(conn, data); + } +#endif + + /* OpenSSL contains code to work around lots of bugs and flaws in various + SSL-implementations. SSL_CTX_set_options() is used to enabled those + work-arounds. The man page for this option states that SSL_OP_ALL enables + all the work-arounds and that "It is usually safe to use SSL_OP_ALL to + enable the bug workaround options if compatibility with somewhat broken + implementations is desired." + + The "-no_ticket" option was introduced in OpenSSL 0.9.8j. It's a flag to + disable "rfc4507bis session ticket support". rfc4507bis was later turned + into the proper RFC5077: https://datatracker.ietf.org/doc/html/rfc5077 + + The enabled extension concerns the session management. I wonder how often + libcurl stops a connection and then resumes a TLS session. Also, sending + the session data is some overhead. I suggest that you just use your + proposed patch (which explicitly disables TICKET). + + If someone writes an application with libcurl and OpenSSL who wants to + enable the feature, one can do this in the SSL callback. + + SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG option enabling allowed proper + interoperability with web server Netscape Enterprise Server 2.0.1 which + was released back in 1996. + + Due to CVE-2010-4180, option SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG has + become ineffective as of OpenSSL 0.9.8q and 1.0.0c. In order to mitigate + CVE-2010-4180 when using previous OpenSSL versions we no longer enable + this option regardless of OpenSSL version and SSL_OP_ALL definition. + + OpenSSL added a work-around for a SSL 3.0/TLS 1.0 CBC vulnerability + (https://www.openssl.org/~bodo/tls-cbc.txt). In 0.9.6e they added a bit to + SSL_OP_ALL that _disables_ that work-around despite the fact that + SSL_OP_ALL is documented to do "rather harmless" workarounds. In order to + keep the secure work-around, the SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS bit + must not be set. + */ + + ctx_options = SSL_OP_ALL; + +#ifdef SSL_OP_NO_TICKET + ctx_options |= SSL_OP_NO_TICKET; +#endif + +#ifdef SSL_OP_NO_COMPRESSION + ctx_options |= SSL_OP_NO_COMPRESSION; +#endif + +#ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG + /* mitigate CVE-2010-4180 */ + ctx_options &= ~SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG; +#endif + +#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS + /* unless the user explicitly asks to allow the protocol vulnerability we + use the work-around */ + if(!SSL_SET_OPTION(enable_beast)) + ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; +#endif + + switch(ssl_version) { + case CURL_SSLVERSION_SSLv2: + case CURL_SSLVERSION_SSLv3: + return CURLE_NOT_BUILT_IN; + + /* "--tlsv" options mean TLS >= version */ + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: /* TLS >= version 1.0 */ + case CURL_SSLVERSION_TLSv1_0: /* TLS >= version 1.0 */ + case CURL_SSLVERSION_TLSv1_1: /* TLS >= version 1.1 */ + case CURL_SSLVERSION_TLSv1_2: /* TLS >= version 1.2 */ + case CURL_SSLVERSION_TLSv1_3: /* TLS >= version 1.3 */ + /* asking for any TLS version as the minimum, means no SSL versions + allowed */ + ctx_options |= SSL_OP_NO_SSLv2; + ctx_options |= SSL_OP_NO_SSLv3; + +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) /* 1.1.0 */ + result = set_ssl_version_min_max(backend->ctx, conn); +#else + result = set_ssl_version_min_max_legacy(&ctx_options, data, conn, + sockindex); +#endif + if(result != CURLE_OK) + return result; + break; + + default: + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; + } + + SSL_CTX_set_options(backend->ctx, ctx_options); + +#ifdef HAS_NPN + if(conn->bits.tls_enable_npn) + SSL_CTX_set_next_proto_select_cb(backend->ctx, select_next_proto_cb, data); +#endif + +#ifdef HAS_ALPN + if(conn->bits.tls_enable_alpn) { + int cur = 0; + unsigned char protocols[128]; + +#ifdef USE_HTTP2 + if(data->state.httpwant >= CURL_HTTP_VERSION_2 +#ifndef CURL_DISABLE_PROXY + && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy) +#endif + ) { + protocols[cur++] = ALPN_H2_LENGTH; + + memcpy(&protocols[cur], ALPN_H2, ALPN_H2_LENGTH); + cur += ALPN_H2_LENGTH; + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_H2); + } +#endif + + protocols[cur++] = ALPN_HTTP_1_1_LENGTH; + memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); + cur += ALPN_HTTP_1_1_LENGTH; + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_1); + + /* expects length prefixed preference ordered list of protocols in wire + * format + */ + if(SSL_CTX_set_alpn_protos(backend->ctx, protocols, cur)) { + failf(data, "Error setting ALPN"); + return CURLE_SSL_CONNECT_ERROR; + } + } +#endif + + if(ssl_cert || ssl_cert_blob || ssl_cert_type) { + if(!result && + !cert_stuff(data, backend->ctx, + ssl_cert, ssl_cert_blob, ssl_cert_type, + SSL_SET_OPTION(key), SSL_SET_OPTION(key_blob), + SSL_SET_OPTION(key_type), SSL_SET_OPTION(key_passwd))) + result = CURLE_SSL_CERTPROBLEM; + if(result) + /* failf() is already done in cert_stuff() */ + return result; + } + + ciphers = SSL_CONN_CONFIG(cipher_list); + if(!ciphers) + ciphers = (char *)DEFAULT_CIPHER_SELECTION; + if(ciphers) { + if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) { + failf(data, "failed setting cipher list: %s", ciphers); + return CURLE_SSL_CIPHER; + } + infof(data, "Cipher selection: %s", ciphers); + } + +#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES + { + char *ciphers13 = SSL_CONN_CONFIG(cipher_list13); + if(ciphers13) { + if(!SSL_CTX_set_ciphersuites(backend->ctx, ciphers13)) { + failf(data, "failed setting TLS 1.3 cipher suite: %s", ciphers13); + return CURLE_SSL_CIPHER; + } + infof(data, "TLS 1.3 cipher selection: %s", ciphers13); + } + } +#endif + +#ifdef HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH + /* OpenSSL 1.1.1 requires clients to opt-in for PHA */ + SSL_CTX_set_post_handshake_auth(backend->ctx, 1); +#endif + +#ifdef HAVE_SSL_CTX_SET_EC_CURVES + { + char *curves = SSL_CONN_CONFIG(curves); + if(curves) { + if(!SSL_CTX_set1_curves_list(backend->ctx, curves)) { + failf(data, "failed setting curves list: '%s'", curves); + return CURLE_SSL_CIPHER; + } + } + } +#endif + +#ifdef USE_OPENSSL_SRP + if((ssl_authtype == CURL_TLSAUTH_SRP) && + Curl_allow_auth_to_host(data)) { + char * const ssl_username = SSL_SET_OPTION(primary.username); + char * const ssl_password = SSL_SET_OPTION(primary.password); + infof(data, "Using TLS-SRP username: %s", ssl_username); + + if(!SSL_CTX_set_srp_username(backend->ctx, ssl_username)) { + failf(data, "Unable to set SRP user name"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + if(!SSL_CTX_set_srp_password(backend->ctx, ssl_password)) { + failf(data, "failed setting SRP password"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + if(!SSL_CONN_CONFIG(cipher_list)) { + infof(data, "Setting cipher list SRP"); + + if(!SSL_CTX_set_cipher_list(backend->ctx, "SRP")) { + failf(data, "failed setting SRP cipher list"); + return CURLE_SSL_CIPHER; + } + } + } +#endif + + +#if defined(USE_WIN32_CRYPTO) + /* Import certificates from the Windows root certificate store if requested. + https://stackoverflow.com/questions/9507184/ + https://github.com/d3x0r/SACK/blob/master/src/netlib/ssl_layer.c#L1037 + https://datatracker.ietf.org/doc/html/rfc5280 */ + if((SSL_CONN_CONFIG(verifypeer) || SSL_CONN_CONFIG(verifyhost)) && + (SSL_SET_OPTION(native_ca_store))) { + X509_STORE *store = SSL_CTX_get_cert_store(backend->ctx); + HCERTSTORE hStore = CertOpenSystemStore(0, TEXT("ROOT")); + + if(hStore) { + PCCERT_CONTEXT pContext = NULL; + /* The array of enhanced key usage OIDs will vary per certificate and is + declared outside of the loop so that rather than malloc/free each + iteration we can grow it with realloc, when necessary. */ + CERT_ENHKEY_USAGE *enhkey_usage = NULL; + DWORD enhkey_usage_size = 0; + + /* This loop makes a best effort to import all valid certificates from + the MS root store. If a certificate cannot be imported it is skipped. + 'result' is used to store only hard-fail conditions (such as out of + memory) that cause an early break. */ + result = CURLE_OK; + for(;;) { + X509 *x509; + FILETIME now; + BYTE key_usage[2]; + DWORD req_size; + const unsigned char *encoded_cert; +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + char cert_name[256]; +#endif + + pContext = CertEnumCertificatesInStore(hStore, pContext); + if(!pContext) + break; + +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + if(!CertGetNameStringA(pContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, + NULL, cert_name, sizeof(cert_name))) { + strcpy(cert_name, "Unknown"); + } + infof(data, "SSL: Checking cert \"%s\"", cert_name); +#endif + + encoded_cert = (const unsigned char *)pContext->pbCertEncoded; + if(!encoded_cert) + continue; + + GetSystemTimeAsFileTime(&now); + if(CompareFileTime(&pContext->pCertInfo->NotBefore, &now) > 0 || + CompareFileTime(&now, &pContext->pCertInfo->NotAfter) > 0) + continue; + + /* If key usage exists check for signing attribute */ + if(CertGetIntendedKeyUsage(pContext->dwCertEncodingType, + pContext->pCertInfo, + key_usage, sizeof(key_usage))) { + if(!(key_usage[0] & CERT_KEY_CERT_SIGN_KEY_USAGE)) + continue; + } + else if(GetLastError()) + continue; + + /* If enhanced key usage exists check for server auth attribute. + * + * Note "In a Microsoft environment, a certificate might also have EKU + * extended properties that specify valid uses for the certificate." + * The call below checks both, and behavior varies depending on what is + * found. For more details see CertGetEnhancedKeyUsage doc. + */ + if(CertGetEnhancedKeyUsage(pContext, 0, NULL, &req_size)) { + if(req_size && req_size > enhkey_usage_size) { + void *tmp = realloc(enhkey_usage, req_size); + + if(!tmp) { + failf(data, "SSL: Out of memory allocating for OID list"); + result = CURLE_OUT_OF_MEMORY; + break; + } + + enhkey_usage = (CERT_ENHKEY_USAGE *)tmp; + enhkey_usage_size = req_size; + } + + if(CertGetEnhancedKeyUsage(pContext, 0, enhkey_usage, &req_size)) { + if(!enhkey_usage->cUsageIdentifier) { + /* "If GetLastError returns CRYPT_E_NOT_FOUND, the certificate is + good for all uses. If it returns zero, the certificate has no + valid uses." */ + if((HRESULT)GetLastError() != CRYPT_E_NOT_FOUND) + continue; + } + else { + DWORD i; + bool found = false; + + for(i = 0; i < enhkey_usage->cUsageIdentifier; ++i) { + if(!strcmp("1.3.6.1.5.5.7.3.1" /* OID server auth */, + enhkey_usage->rgpszUsageIdentifier[i])) { + found = true; + break; + } + } + + if(!found) + continue; + } + } + else + continue; + } + else + continue; + + x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded); + if(!x509) + continue; + + /* Try to import the certificate. This may fail for legitimate reasons + such as duplicate certificate, which is allowed by MS but not + OpenSSL. */ + if(X509_STORE_add_cert(store, x509) == 1) { +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + infof(data, "SSL: Imported cert \"%s\"", cert_name); +#endif + imported_native_ca = true; + } + X509_free(x509); + } + + free(enhkey_usage); + CertFreeCertificateContext(pContext); + CertCloseStore(hStore, 0); + + if(result) + return result; + } + if(imported_native_ca) + infof(data, "successfully imported Windows CA store"); + else + infof(data, "error importing Windows CA store, continuing anyway"); + } +#endif + + if(ca_info_blob) { + result = load_cacert_from_memory(backend->ctx, ca_info_blob); + if(result) { + if(result == CURLE_OUT_OF_MEMORY || + (verifypeer && !imported_native_ca)) { + failf(data, "error importing CA certificate blob"); + return result; + } + /* Only warn if no certificate verification is required. */ + infof(data, "error importing CA certificate blob, continuing anyway"); + } + } + + if(verifypeer && !imported_native_ca && (ssl_cafile || ssl_capath)) { +#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) + /* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */ + if(ssl_cafile && + !SSL_CTX_load_verify_file(backend->ctx, ssl_cafile)) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate file: %s", ssl_cafile); + return CURLE_SSL_CACERT_BADFILE; + } + if(ssl_capath && + !SSL_CTX_load_verify_dir(backend->ctx, ssl_capath)) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate path: %s", ssl_capath); + return CURLE_SSL_CACERT_BADFILE; + } +#else + /* tell OpenSSL where to find CA certificates that are used to verify the + server's certificate. */ + if(!SSL_CTX_load_verify_locations(backend->ctx, ssl_cafile, ssl_capath)) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate verify locations:" + " CAfile: %s CApath: %s", + ssl_cafile ? ssl_cafile : "none", + ssl_capath ? ssl_capath : "none"); + return CURLE_SSL_CACERT_BADFILE; + } +#endif + infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none"); + infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none"); + } + +#ifdef CURL_CA_FALLBACK + if(verifypeer && + !ca_info_blob && !ssl_cafile && !ssl_capath && !imported_native_ca) { + /* verifying the peer without any CA certificates won't + work so use openssl's built-in default as fallback */ + SSL_CTX_set_default_verify_paths(backend->ctx); + } +#endif + + if(ssl_crlfile) { + /* tell OpenSSL where to find CRL file that is used to check certificate + * revocation */ + lookup = X509_STORE_add_lookup(SSL_CTX_get_cert_store(backend->ctx), + X509_LOOKUP_file()); + if(!lookup || + (!X509_load_crl_file(lookup, ssl_crlfile, X509_FILETYPE_PEM)) ) { + failf(data, "error loading CRL file: %s", ssl_crlfile); + return CURLE_SSL_CRL_BADFILE; + } + /* Everything is fine. */ + infof(data, "successfully loaded CRL file:"); + X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx), + X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); + + infof(data, " CRLfile: %s", ssl_crlfile); + } + + if(verifypeer) { + /* Try building a chain using issuers in the trusted store first to avoid + problems with server-sent legacy intermediates. Newer versions of + OpenSSL do alternate chain checking by default but we do not know how to + determine that in a reliable manner. + https://rt.openssl.org/Ticket/Display.html?id=3621&user=guest&pass=guest + */ +#if defined(X509_V_FLAG_TRUSTED_FIRST) + X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx), + X509_V_FLAG_TRUSTED_FIRST); +#endif +#ifdef X509_V_FLAG_PARTIAL_CHAIN + if(!SSL_SET_OPTION(no_partialchain) && !ssl_crlfile) { + /* Have intermediate certificates in the trust store be treated as + trust-anchors, in the same way as self-signed root CA certificates + are. This allows users to verify servers using the intermediate cert + only, instead of needing the whole chain. + + Due to OpenSSL bug https://github.com/openssl/openssl/issues/5081 we + cannot do partial chains with a CRL check. + */ + X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx), + X509_V_FLAG_PARTIAL_CHAIN); + } +#endif + } + + /* OpenSSL always tries to verify the peer, this only says whether it should + * fail to connect if the verification fails, or if it should continue + * anyway. In the latter case the result of the verification is checked with + * SSL_get_verify_result() below. */ + SSL_CTX_set_verify(backend->ctx, + verifypeer ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL); + + /* Enable logging of secrets to the file specified in env SSLKEYLOGFILE. */ +#ifdef HAVE_KEYLOG_CALLBACK + if(Curl_tls_keylog_enabled()) { + SSL_CTX_set_keylog_callback(backend->ctx, ossl_keylog_callback); + } +#endif + + /* Enable the session cache because it's a prerequisite for the "new session" + * callback. Use the "external storage" mode to prevent OpenSSL from creating + * an internal session cache. + */ + SSL_CTX_set_session_cache_mode(backend->ctx, + SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL); + SSL_CTX_sess_set_new_cb(backend->ctx, ossl_new_session_cb); + + /* give application a chance to interfere with SSL set up. */ + if(data->set.ssl.fsslctx) { + Curl_set_in_callback(data, true); + result = (*data->set.ssl.fsslctx)(data, backend->ctx, + data->set.ssl.fsslctxp); + Curl_set_in_callback(data, false); + if(result) { + failf(data, "error signaled by ssl ctx callback"); + return result; + } + } + + /* Let's make an SSL structure */ + if(backend->handle) + SSL_free(backend->handle); + backend->handle = SSL_new(backend->ctx); + if(!backend->handle) { + failf(data, "SSL: couldn't create a context (handle)"); + return CURLE_OUT_OF_MEMORY; + } + +#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ + !defined(OPENSSL_NO_OCSP) + if(SSL_CONN_CONFIG(verifystatus)) + SSL_set_tlsext_status_type(backend->handle, TLSEXT_STATUSTYPE_ocsp); +#endif + +#if defined(OPENSSL_IS_BORINGSSL) && defined(ALLOW_RENEG) + SSL_set_renegotiate_mode(backend->handle, ssl_renegotiate_freely); +#endif + + SSL_set_connect_state(backend->handle); + + backend->server_cert = 0x0; +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) && +#ifdef ENABLE_IPV6 + (0 == Curl_inet_pton(AF_INET6, hostname, &addr)) && +#endif + sni) { + char *snihost = Curl_ssl_snihost(data, hostname, NULL); + if(!snihost || !SSL_set_tlsext_host_name(backend->handle, snihost)) { + failf(data, "Failed set SNI"); + return CURLE_SSL_CONNECT_ERROR; + } + } +#endif + + if(!ossl_associate_connection(data, conn, sockindex)) { + /* Maybe the internal errors of SSL_get_ex_new_index or SSL_set_ex_data */ + failf(data, "SSL: ossl_associate_connection failed: %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer))); + return CURLE_SSL_CONNECT_ERROR; + } + + if(SSL_SET_OPTION(primary.sessionid)) { + Curl_ssl_sessionid_lock(data); + if(!Curl_ssl_getsessionid(data, conn, SSL_IS_PROXY() ? TRUE : FALSE, + &ssl_sessionid, NULL, sockindex)) { + /* we got a session id, use it! */ + if(!SSL_set_session(backend->handle, ssl_sessionid)) { + Curl_ssl_sessionid_unlock(data); + failf(data, "SSL: SSL_set_session failed: %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer))); + return CURLE_SSL_CONNECT_ERROR; + } + /* Informational message */ + infof(data, "SSL re-using session ID"); + } + Curl_ssl_sessionid_unlock(data); + } + +#ifndef CURL_DISABLE_PROXY + if(conn->proxy_ssl[sockindex].use) { + BIO *const bio = BIO_new(BIO_f_ssl()); + struct ssl_backend_data *proxy_backend; + SSL* handle = NULL; + proxy_backend = conn->proxy_ssl[sockindex].backend; + DEBUGASSERT(proxy_backend); + handle = proxy_backend->handle; + DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state); + DEBUGASSERT(handle != NULL); + DEBUGASSERT(bio != NULL); + BIO_set_ssl(bio, handle, FALSE); + SSL_set_bio(backend->handle, bio, bio); + } + else +#endif + if(!SSL_set_fd(backend->handle, (int)sockfd)) { + /* pass the raw socket into the SSL layers */ + failf(data, "SSL: SSL_set_fd failed: %s", + ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer))); + return CURLE_SSL_CONNECT_ERROR; + } + + connssl->connecting_state = ssl_connect_2; + + return CURLE_OK; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-27782-ossl_connect_step1/vuln.c b/benchmarks/pairs/vfc/curl-cve-2022-27782-ossl_connect_step1/vuln.c new file mode 100644 index 0000000..985177a --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-27782-ossl_connect_step1/vuln.c @@ -0,0 +1,688 @@ +/* Provenance: curl/curl ossl_connect_step1 (vuln). + * repo: curl/curl + * commit: 7e92d12b4e6911f424678a133b19de670e183a59 + * parent: 7e92d12b4e6911f424678a133b19de670e183a59 + * commit_url: https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c + * cve: CVE-2022-27782 + * license: curl + * function: ossl_connect_step1 + * relpath: lib/vtls/openssl.c + */ + +static CURLcode ossl_connect_step1(struct Curl_easy *data, + struct connectdata *conn, int sockindex) +{ + CURLcode result = CURLE_OK; + char *ciphers; + SSL_METHOD_QUAL SSL_METHOD *req_method = NULL; + X509_LOOKUP *lookup = NULL; + curl_socket_t sockfd = conn->sock[sockindex]; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + ctx_option_t ctx_options = 0; + void *ssl_sessionid = NULL; + +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + bool sni; + const char * const hostname = SSL_HOST_NAME(); + +#ifdef ENABLE_IPV6 + struct in6_addr addr; +#else + struct in_addr addr; +#endif +#endif + const long int ssl_version = SSL_CONN_CONFIG(version); +#ifdef USE_OPENSSL_SRP + const enum CURL_TLSAUTH ssl_authtype = SSL_SET_OPTION(authtype); +#endif + char * const ssl_cert = SSL_SET_OPTION(primary.clientcert); + const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(primary.cert_blob); + const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_blob); + const char * const ssl_cert_type = SSL_SET_OPTION(cert_type); + const char * const ssl_cafile = + /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */ + (ca_info_blob ? NULL : SSL_CONN_CONFIG(CAfile)); + const char * const ssl_capath = SSL_CONN_CONFIG(CApath); + const bool verifypeer = SSL_CONN_CONFIG(verifypeer); + const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile); + char error_buffer[256]; + struct ssl_backend_data *backend = connssl->backend; + bool imported_native_ca = false; + + DEBUGASSERT(ssl_connect_1 == connssl->connecting_state); + DEBUGASSERT(backend); + + /* Make funny stuff to get random input */ + result = ossl_seed(data); + if(result) + return result; + + SSL_SET_OPTION_LVALUE(certverifyresult) = !X509_V_OK; + + /* check to see if we've been told to use an explicit SSL/TLS version */ + + switch(ssl_version) { + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + case CURL_SSLVERSION_TLSv1_0: + case CURL_SSLVERSION_TLSv1_1: + case CURL_SSLVERSION_TLSv1_2: + case CURL_SSLVERSION_TLSv1_3: + /* it will be handled later with the context options */ +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) + req_method = TLS_client_method(); +#else + req_method = SSLv23_client_method(); +#endif + use_sni(TRUE); + break; + case CURL_SSLVERSION_SSLv2: + failf(data, "No SSLv2 support"); + return CURLE_NOT_BUILT_IN; + case CURL_SSLVERSION_SSLv3: + failf(data, "No SSLv3 support"); + return CURLE_NOT_BUILT_IN; + default: + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; + } + + DEBUGASSERT(!backend->ctx); + backend->ctx = SSL_CTX_new(req_method); + + if(!backend->ctx) { + failf(data, "SSL: couldn't create a context: %s", + ossl_strerror(ERR_peek_error(), error_buffer, sizeof(error_buffer))); + return CURLE_OUT_OF_MEMORY; + } + +#ifdef SSL_MODE_RELEASE_BUFFERS + SSL_CTX_set_mode(backend->ctx, SSL_MODE_RELEASE_BUFFERS); +#endif + +#ifdef SSL_CTRL_SET_MSG_CALLBACK + if(data->set.fdebug && data->set.verbose) { + /* the SSL trace callback is only used for verbose logging */ + SSL_CTX_set_msg_callback(backend->ctx, ossl_trace); + SSL_CTX_set_msg_callback_arg(backend->ctx, conn); + set_logger(conn, data); + } +#endif + + /* OpenSSL contains code to work around lots of bugs and flaws in various + SSL-implementations. SSL_CTX_set_options() is used to enabled those + work-arounds. The man page for this option states that SSL_OP_ALL enables + all the work-arounds and that "It is usually safe to use SSL_OP_ALL to + enable the bug workaround options if compatibility with somewhat broken + implementations is desired." + + The "-no_ticket" option was introduced in OpenSSL 0.9.8j. It's a flag to + disable "rfc4507bis session ticket support". rfc4507bis was later turned + into the proper RFC5077: https://datatracker.ietf.org/doc/html/rfc5077 + + The enabled extension concerns the session management. I wonder how often + libcurl stops a connection and then resumes a TLS session. Also, sending + the session data is some overhead. I suggest that you just use your + proposed patch (which explicitly disables TICKET). + + If someone writes an application with libcurl and OpenSSL who wants to + enable the feature, one can do this in the SSL callback. + + SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG option enabling allowed proper + interoperability with web server Netscape Enterprise Server 2.0.1 which + was released back in 1996. + + Due to CVE-2010-4180, option SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG has + become ineffective as of OpenSSL 0.9.8q and 1.0.0c. In order to mitigate + CVE-2010-4180 when using previous OpenSSL versions we no longer enable + this option regardless of OpenSSL version and SSL_OP_ALL definition. + + OpenSSL added a work-around for a SSL 3.0/TLS 1.0 CBC vulnerability + (https://www.openssl.org/~bodo/tls-cbc.txt). In 0.9.6e they added a bit to + SSL_OP_ALL that _disables_ that work-around despite the fact that + SSL_OP_ALL is documented to do "rather harmless" workarounds. In order to + keep the secure work-around, the SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS bit + must not be set. + */ + + ctx_options = SSL_OP_ALL; + +#ifdef SSL_OP_NO_TICKET + ctx_options |= SSL_OP_NO_TICKET; +#endif + +#ifdef SSL_OP_NO_COMPRESSION + ctx_options |= SSL_OP_NO_COMPRESSION; +#endif + +#ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG + /* mitigate CVE-2010-4180 */ + ctx_options &= ~SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG; +#endif + +#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS + /* unless the user explicitly asks to allow the protocol vulnerability we + use the work-around */ + if(!SSL_SET_OPTION(enable_beast)) + ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; +#endif + + switch(ssl_version) { + case CURL_SSLVERSION_SSLv2: + case CURL_SSLVERSION_SSLv3: + return CURLE_NOT_BUILT_IN; + + /* "--tlsv" options mean TLS >= version */ + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: /* TLS >= version 1.0 */ + case CURL_SSLVERSION_TLSv1_0: /* TLS >= version 1.0 */ + case CURL_SSLVERSION_TLSv1_1: /* TLS >= version 1.1 */ + case CURL_SSLVERSION_TLSv1_2: /* TLS >= version 1.2 */ + case CURL_SSLVERSION_TLSv1_3: /* TLS >= version 1.3 */ + /* asking for any TLS version as the minimum, means no SSL versions + allowed */ + ctx_options |= SSL_OP_NO_SSLv2; + ctx_options |= SSL_OP_NO_SSLv3; + +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) /* 1.1.0 */ + result = set_ssl_version_min_max(backend->ctx, conn); +#else + result = set_ssl_version_min_max_legacy(&ctx_options, data, conn, + sockindex); +#endif + if(result != CURLE_OK) + return result; + break; + + default: + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; + } + + SSL_CTX_set_options(backend->ctx, ctx_options); + +#ifdef HAS_NPN + if(conn->bits.tls_enable_npn) + SSL_CTX_set_next_proto_select_cb(backend->ctx, select_next_proto_cb, data); +#endif + +#ifdef HAS_ALPN + if(conn->bits.tls_enable_alpn) { + int cur = 0; + unsigned char protocols[128]; + +#ifdef USE_HTTP2 + if(data->state.httpwant >= CURL_HTTP_VERSION_2 +#ifndef CURL_DISABLE_PROXY + && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy) +#endif + ) { + protocols[cur++] = ALPN_H2_LENGTH; + + memcpy(&protocols[cur], ALPN_H2, ALPN_H2_LENGTH); + cur += ALPN_H2_LENGTH; + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_H2); + } +#endif + + protocols[cur++] = ALPN_HTTP_1_1_LENGTH; + memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); + cur += ALPN_HTTP_1_1_LENGTH; + infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_1); + + /* expects length prefixed preference ordered list of protocols in wire + * format + */ + if(SSL_CTX_set_alpn_protos(backend->ctx, protocols, cur)) { + failf(data, "Error setting ALPN"); + return CURLE_SSL_CONNECT_ERROR; + } + } +#endif + + if(ssl_cert || ssl_cert_blob || ssl_cert_type) { + if(!result && + !cert_stuff(data, backend->ctx, + ssl_cert, ssl_cert_blob, ssl_cert_type, + SSL_SET_OPTION(key), SSL_SET_OPTION(key_blob), + SSL_SET_OPTION(key_type), SSL_SET_OPTION(key_passwd))) + result = CURLE_SSL_CERTPROBLEM; + if(result) + /* failf() is already done in cert_stuff() */ + return result; + } + + ciphers = SSL_CONN_CONFIG(cipher_list); + if(!ciphers) + ciphers = (char *)DEFAULT_CIPHER_SELECTION; + if(ciphers) { + if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) { + failf(data, "failed setting cipher list: %s", ciphers); + return CURLE_SSL_CIPHER; + } + infof(data, "Cipher selection: %s", ciphers); + } + +#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES + { + char *ciphers13 = SSL_CONN_CONFIG(cipher_list13); + if(ciphers13) { + if(!SSL_CTX_set_ciphersuites(backend->ctx, ciphers13)) { + failf(data, "failed setting TLS 1.3 cipher suite: %s", ciphers13); + return CURLE_SSL_CIPHER; + } + infof(data, "TLS 1.3 cipher selection: %s", ciphers13); + } + } +#endif + +#ifdef HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH + /* OpenSSL 1.1.1 requires clients to opt-in for PHA */ + SSL_CTX_set_post_handshake_auth(backend->ctx, 1); +#endif + +#ifdef HAVE_SSL_CTX_SET_EC_CURVES + { + char *curves = SSL_CONN_CONFIG(curves); + if(curves) { + if(!SSL_CTX_set1_curves_list(backend->ctx, curves)) { + failf(data, "failed setting curves list: '%s'", curves); + return CURLE_SSL_CIPHER; + } + } + } +#endif + +#ifdef USE_OPENSSL_SRP + if((ssl_authtype == CURL_TLSAUTH_SRP) && + Curl_allow_auth_to_host(data)) { + char * const ssl_username = SSL_SET_OPTION(username); + + infof(data, "Using TLS-SRP username: %s", ssl_username); + + if(!SSL_CTX_set_srp_username(backend->ctx, ssl_username)) { + failf(data, "Unable to set SRP user name"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + if(!SSL_CTX_set_srp_password(backend->ctx, SSL_SET_OPTION(password))) { + failf(data, "failed setting SRP password"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + if(!SSL_CONN_CONFIG(cipher_list)) { + infof(data, "Setting cipher list SRP"); + + if(!SSL_CTX_set_cipher_list(backend->ctx, "SRP")) { + failf(data, "failed setting SRP cipher list"); + return CURLE_SSL_CIPHER; + } + } + } +#endif + + +#if defined(USE_WIN32_CRYPTO) + /* Import certificates from the Windows root certificate store if requested. + https://stackoverflow.com/questions/9507184/ + https://github.com/d3x0r/SACK/blob/master/src/netlib/ssl_layer.c#L1037 + https://datatracker.ietf.org/doc/html/rfc5280 */ + if((SSL_CONN_CONFIG(verifypeer) || SSL_CONN_CONFIG(verifyhost)) && + (SSL_SET_OPTION(native_ca_store))) { + X509_STORE *store = SSL_CTX_get_cert_store(backend->ctx); + HCERTSTORE hStore = CertOpenSystemStore(0, TEXT("ROOT")); + + if(hStore) { + PCCERT_CONTEXT pContext = NULL; + /* The array of enhanced key usage OIDs will vary per certificate and is + declared outside of the loop so that rather than malloc/free each + iteration we can grow it with realloc, when necessary. */ + CERT_ENHKEY_USAGE *enhkey_usage = NULL; + DWORD enhkey_usage_size = 0; + + /* This loop makes a best effort to import all valid certificates from + the MS root store. If a certificate cannot be imported it is skipped. + 'result' is used to store only hard-fail conditions (such as out of + memory) that cause an early break. */ + result = CURLE_OK; + for(;;) { + X509 *x509; + FILETIME now; + BYTE key_usage[2]; + DWORD req_size; + const unsigned char *encoded_cert; +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + char cert_name[256]; +#endif + + pContext = CertEnumCertificatesInStore(hStore, pContext); + if(!pContext) + break; + +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + if(!CertGetNameStringA(pContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, + NULL, cert_name, sizeof(cert_name))) { + strcpy(cert_name, "Unknown"); + } + infof(data, "SSL: Checking cert \"%s\"", cert_name); +#endif + + encoded_cert = (const unsigned char *)pContext->pbCertEncoded; + if(!encoded_cert) + continue; + + GetSystemTimeAsFileTime(&now); + if(CompareFileTime(&pContext->pCertInfo->NotBefore, &now) > 0 || + CompareFileTime(&now, &pContext->pCertInfo->NotAfter) > 0) + continue; + + /* If key usage exists check for signing attribute */ + if(CertGetIntendedKeyUsage(pContext->dwCertEncodingType, + pContext->pCertInfo, + key_usage, sizeof(key_usage))) { + if(!(key_usage[0] & CERT_KEY_CERT_SIGN_KEY_USAGE)) + continue; + } + else if(GetLastError()) + continue; + + /* If enhanced key usage exists check for server auth attribute. + * + * Note "In a Microsoft environment, a certificate might also have EKU + * extended properties that specify valid uses for the certificate." + * The call below checks both, and behavior varies depending on what is + * found. For more details see CertGetEnhancedKeyUsage doc. + */ + if(CertGetEnhancedKeyUsage(pContext, 0, NULL, &req_size)) { + if(req_size && req_size > enhkey_usage_size) { + void *tmp = realloc(enhkey_usage, req_size); + + if(!tmp) { + failf(data, "SSL: Out of memory allocating for OID list"); + result = CURLE_OUT_OF_MEMORY; + break; + } + + enhkey_usage = (CERT_ENHKEY_USAGE *)tmp; + enhkey_usage_size = req_size; + } + + if(CertGetEnhancedKeyUsage(pContext, 0, enhkey_usage, &req_size)) { + if(!enhkey_usage->cUsageIdentifier) { + /* "If GetLastError returns CRYPT_E_NOT_FOUND, the certificate is + good for all uses. If it returns zero, the certificate has no + valid uses." */ + if((HRESULT)GetLastError() != CRYPT_E_NOT_FOUND) + continue; + } + else { + DWORD i; + bool found = false; + + for(i = 0; i < enhkey_usage->cUsageIdentifier; ++i) { + if(!strcmp("1.3.6.1.5.5.7.3.1" /* OID server auth */, + enhkey_usage->rgpszUsageIdentifier[i])) { + found = true; + break; + } + } + + if(!found) + continue; + } + } + else + continue; + } + else + continue; + + x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded); + if(!x509) + continue; + + /* Try to import the certificate. This may fail for legitimate reasons + such as duplicate certificate, which is allowed by MS but not + OpenSSL. */ + if(X509_STORE_add_cert(store, x509) == 1) { +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + infof(data, "SSL: Imported cert \"%s\"", cert_name); +#endif + imported_native_ca = true; + } + X509_free(x509); + } + + free(enhkey_usage); + CertFreeCertificateContext(pContext); + CertCloseStore(hStore, 0); + + if(result) + return result; + } + if(imported_native_ca) + infof(data, "successfully imported Windows CA store"); + else + infof(data, "error importing Windows CA store, continuing anyway"); + } +#endif + + if(ca_info_blob) { + result = load_cacert_from_memory(backend->ctx, ca_info_blob); + if(result) { + if(result == CURLE_OUT_OF_MEMORY || + (verifypeer && !imported_native_ca)) { + failf(data, "error importing CA certificate blob"); + return result; + } + /* Only warn if no certificate verification is required. */ + infof(data, "error importing CA certificate blob, continuing anyway"); + } + } + + if(verifypeer && !imported_native_ca && (ssl_cafile || ssl_capath)) { +#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) + /* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */ + if(ssl_cafile && + !SSL_CTX_load_verify_file(backend->ctx, ssl_cafile)) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate file: %s", ssl_cafile); + return CURLE_SSL_CACERT_BADFILE; + } + if(ssl_capath && + !SSL_CTX_load_verify_dir(backend->ctx, ssl_capath)) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate path: %s", ssl_capath); + return CURLE_SSL_CACERT_BADFILE; + } +#else + /* tell OpenSSL where to find CA certificates that are used to verify the + server's certificate. */ + if(!SSL_CTX_load_verify_locations(backend->ctx, ssl_cafile, ssl_capath)) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate verify locations:" + " CAfile: %s CApath: %s", + ssl_cafile ? ssl_cafile : "none", + ssl_capath ? ssl_capath : "none"); + return CURLE_SSL_CACERT_BADFILE; + } +#endif + infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none"); + infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none"); + } + +#ifdef CURL_CA_FALLBACK + if(verifypeer && + !ca_info_blob && !ssl_cafile && !ssl_capath && !imported_native_ca) { + /* verifying the peer without any CA certificates won't + work so use openssl's built-in default as fallback */ + SSL_CTX_set_default_verify_paths(backend->ctx); + } +#endif + + if(ssl_crlfile) { + /* tell OpenSSL where to find CRL file that is used to check certificate + * revocation */ + lookup = X509_STORE_add_lookup(SSL_CTX_get_cert_store(backend->ctx), + X509_LOOKUP_file()); + if(!lookup || + (!X509_load_crl_file(lookup, ssl_crlfile, X509_FILETYPE_PEM)) ) { + failf(data, "error loading CRL file: %s", ssl_crlfile); + return CURLE_SSL_CRL_BADFILE; + } + /* Everything is fine. */ + infof(data, "successfully loaded CRL file:"); + X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx), + X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); + + infof(data, " CRLfile: %s", ssl_crlfile); + } + + if(verifypeer) { + /* Try building a chain using issuers in the trusted store first to avoid + problems with server-sent legacy intermediates. Newer versions of + OpenSSL do alternate chain checking by default but we do not know how to + determine that in a reliable manner. + https://rt.openssl.org/Ticket/Display.html?id=3621&user=guest&pass=guest + */ +#if defined(X509_V_FLAG_TRUSTED_FIRST) + X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx), + X509_V_FLAG_TRUSTED_FIRST); +#endif +#ifdef X509_V_FLAG_PARTIAL_CHAIN + if(!SSL_SET_OPTION(no_partialchain) && !ssl_crlfile) { + /* Have intermediate certificates in the trust store be treated as + trust-anchors, in the same way as self-signed root CA certificates + are. This allows users to verify servers using the intermediate cert + only, instead of needing the whole chain. + + Due to OpenSSL bug https://github.com/openssl/openssl/issues/5081 we + cannot do partial chains with a CRL check. + */ + X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx), + X509_V_FLAG_PARTIAL_CHAIN); + } +#endif + } + + /* OpenSSL always tries to verify the peer, this only says whether it should + * fail to connect if the verification fails, or if it should continue + * anyway. In the latter case the result of the verification is checked with + * SSL_get_verify_result() below. */ + SSL_CTX_set_verify(backend->ctx, + verifypeer ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL); + + /* Enable logging of secrets to the file specified in env SSLKEYLOGFILE. */ +#ifdef HAVE_KEYLOG_CALLBACK + if(Curl_tls_keylog_enabled()) { + SSL_CTX_set_keylog_callback(backend->ctx, ossl_keylog_callback); + } +#endif + + /* Enable the session cache because it's a prerequisite for the "new session" + * callback. Use the "external storage" mode to prevent OpenSSL from creating + * an internal session cache. + */ + SSL_CTX_set_session_cache_mode(backend->ctx, + SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL); + SSL_CTX_sess_set_new_cb(backend->ctx, ossl_new_session_cb); + + /* give application a chance to interfere with SSL set up. */ + if(data->set.ssl.fsslctx) { + Curl_set_in_callback(data, true); + result = (*data->set.ssl.fsslctx)(data, backend->ctx, + data->set.ssl.fsslctxp); + Curl_set_in_callback(data, false); + if(result) { + failf(data, "error signaled by ssl ctx callback"); + return result; + } + } + + /* Let's make an SSL structure */ + if(backend->handle) + SSL_free(backend->handle); + backend->handle = SSL_new(backend->ctx); + if(!backend->handle) { + failf(data, "SSL: couldn't create a context (handle)"); + return CURLE_OUT_OF_MEMORY; + } + +#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ + !defined(OPENSSL_NO_OCSP) + if(SSL_CONN_CONFIG(verifystatus)) + SSL_set_tlsext_status_type(backend->handle, TLSEXT_STATUSTYPE_ocsp); +#endif + +#if defined(OPENSSL_IS_BORINGSSL) && defined(ALLOW_RENEG) + SSL_set_renegotiate_mode(backend->handle, ssl_renegotiate_freely); +#endif + + SSL_set_connect_state(backend->handle); + + backend->server_cert = 0x0; +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) && +#ifdef ENABLE_IPV6 + (0 == Curl_inet_pton(AF_INET6, hostname, &addr)) && +#endif + sni) { + char *snihost = Curl_ssl_snihost(data, hostname, NULL); + if(!snihost || !SSL_set_tlsext_host_name(backend->handle, snihost)) { + failf(data, "Failed set SNI"); + return CURLE_SSL_CONNECT_ERROR; + } + } +#endif + + if(!ossl_associate_connection(data, conn, sockindex)) { + /* Maybe the internal errors of SSL_get_ex_new_index or SSL_set_ex_data */ + failf(data, "SSL: ossl_associate_connection failed: %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer))); + return CURLE_SSL_CONNECT_ERROR; + } + + if(SSL_SET_OPTION(primary.sessionid)) { + Curl_ssl_sessionid_lock(data); + if(!Curl_ssl_getsessionid(data, conn, SSL_IS_PROXY() ? TRUE : FALSE, + &ssl_sessionid, NULL, sockindex)) { + /* we got a session id, use it! */ + if(!SSL_set_session(backend->handle, ssl_sessionid)) { + Curl_ssl_sessionid_unlock(data); + failf(data, "SSL: SSL_set_session failed: %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer))); + return CURLE_SSL_CONNECT_ERROR; + } + /* Informational message */ + infof(data, "SSL re-using session ID"); + } + Curl_ssl_sessionid_unlock(data); + } + +#ifndef CURL_DISABLE_PROXY + if(conn->proxy_ssl[sockindex].use) { + BIO *const bio = BIO_new(BIO_f_ssl()); + struct ssl_backend_data *proxy_backend; + SSL* handle = NULL; + proxy_backend = conn->proxy_ssl[sockindex].backend; + DEBUGASSERT(proxy_backend); + handle = proxy_backend->handle; + DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state); + DEBUGASSERT(handle != NULL); + DEBUGASSERT(bio != NULL); + BIO_set_ssl(bio, handle, FALSE); + SSL_set_bio(backend->handle, bio, bio); + } + else +#endif + if(!SSL_set_fd(backend->handle, (int)sockfd)) { + /* pass the raw socket into the SSL layers */ + failf(data, "SSL: SSL_set_fd failed: %s", + ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer))); + return CURLE_SSL_CONNECT_ERROR; + } + + connssl->connecting_state = ssl_connect_2; + + return CURLE_OK; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-30115/fixed.c b/benchmarks/pairs/vfc/curl-cve-2022-30115/fixed.c new file mode 100644 index 0000000..09bed82 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-30115/fixed.c @@ -0,0 +1,39 @@ +/* Provenance: curl/curl hsts_create (fixed). + * repo: curl/curl + * commit: fae6fea209a2d4db1582f608bd8cc8000721733a + * parent: ff3ee510c328db03bf171cae6179bb9463fb054f + * commit_url: https://github.com/curl/curl/commit/fae6fea209a2d4db1582f608bd8cc8000721733a + * cve: CVE-2022-30115 + * license: curl + * function: hsts_create + * relpath: lib/hsts.c + */ + +static CURLcode hsts_create(struct hsts *h, + const char *hostname, + bool subdomains, + curl_off_t expires) +{ + struct stsentry *sts = hsts_entry(); + char *duphost; + size_t hlen; + if(!sts) + return CURLE_OUT_OF_MEMORY; + + duphost = strdup(hostname); + if(!duphost) { + free(sts); + return CURLE_OUT_OF_MEMORY; + } + + hlen = strlen(duphost); + if(duphost[hlen - 1] == '.') + /* strip off trailing any dot */ + duphost[--hlen] = 0; + + sts->host = duphost; + sts->expires = expires; + sts->includeSubDomains = subdomains; + Curl_llist_insert_next(&h->list, h->list.tail, sts, &sts->node); + return CURLE_OK; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-30115/vuln.c b/benchmarks/pairs/vfc/curl-cve-2022-30115/vuln.c new file mode 100644 index 0000000..88eaafe --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-30115/vuln.c @@ -0,0 +1,30 @@ +/* Provenance: curl/curl hsts_create (vuln). + * repo: curl/curl + * commit: ff3ee510c328db03bf171cae6179bb9463fb054f + * parent: ff3ee510c328db03bf171cae6179bb9463fb054f + * commit_url: https://github.com/curl/curl/commit/fae6fea209a2d4db1582f608bd8cc8000721733a + * cve: CVE-2022-30115 + * license: curl + * function: hsts_create + * relpath: lib/hsts.c + */ + +static CURLcode hsts_create(struct hsts *h, + const char *hostname, + bool subdomains, + curl_off_t expires) +{ + struct stsentry *sts = hsts_entry(); + if(!sts) + return CURLE_OUT_OF_MEMORY; + + sts->expires = expires; + sts->includeSubDomains = subdomains; + sts->host = strdup(hostname); + if(!sts->host) { + free(sts); + return CURLE_OUT_OF_MEMORY; + } + Curl_llist_insert_next(&h->list, h->list.tail, sts, &sts->node); + return CURLE_OK; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-32206/fixed.c b/benchmarks/pairs/vfc/curl-cve-2022-32206/fixed.c new file mode 100644 index 0000000..cbaeca6 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-32206/fixed.c @@ -0,0 +1,65 @@ +/* Provenance: curl/curl Curl_build_unencoding_stack (fixed). + * repo: curl/curl + * commit: 3a09fbb7f264c67c438d01a30669ce325aa508e2 + * parent: 6ecdf5136b52af747e7bda08db9a748256b1cd09 + * commit_url: https://github.com/curl/curl/commit/3a09fbb7f264c67c438d01a30669ce325aa508e2 + * cve: CVE-2022-32206 + * license: curl + * function: Curl_build_unencoding_stack + * relpath: lib/content_encoding.c + */ + +CURLcode Curl_build_unencoding_stack(struct Curl_easy *data, + const char *enclist, int maybechunked) +{ + struct SingleRequest *k = &data->req; + int counter = 0; + + do { + const char *name; + size_t namelen; + + /* Parse a single encoding name. */ + while(ISSPACE(*enclist) || *enclist == ',') + enclist++; + + name = enclist; + + for(namelen = 0; *enclist && *enclist != ','; enclist++) + if(!ISSPACE(*enclist)) + namelen = enclist - name + 1; + + /* Special case: chunked encoding is handled at the reader level. */ + if(maybechunked && namelen == 7 && strncasecompare(name, "chunked", 7)) { + k->chunk = TRUE; /* chunks coming our way. */ + Curl_httpchunk_init(data); /* init our chunky engine. */ + } + else if(namelen) { + const struct content_encoding *encoding = find_encoding(name, namelen); + struct contenc_writer *writer; + + if(!k->writer_stack) { + k->writer_stack = new_unencoding_writer(data, &client_encoding, NULL); + + if(!k->writer_stack) + return CURLE_OUT_OF_MEMORY; + } + + if(!encoding) + encoding = &error_encoding; /* Defer error at stack use. */ + + if(++counter >= MAX_ENCODE_STACK) { + failf(data, "Reject response due to %u content encodings", + counter); + return CURLE_BAD_CONTENT_ENCODING; + } + /* Stack the unencoding stage. */ + writer = new_unencoding_writer(data, encoding, k->writer_stack); + if(!writer) + return CURLE_OUT_OF_MEMORY; + k->writer_stack = writer; + } + } while(*enclist); + + return CURLE_OK; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-32206/vuln.c b/benchmarks/pairs/vfc/curl-cve-2022-32206/vuln.c new file mode 100644 index 0000000..a8f60c7 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-32206/vuln.c @@ -0,0 +1,59 @@ +/* Provenance: curl/curl Curl_build_unencoding_stack (vuln). + * repo: curl/curl + * commit: 6ecdf5136b52af747e7bda08db9a748256b1cd09 + * parent: 6ecdf5136b52af747e7bda08db9a748256b1cd09 + * commit_url: https://github.com/curl/curl/commit/3a09fbb7f264c67c438d01a30669ce325aa508e2 + * cve: CVE-2022-32206 + * license: curl + * function: Curl_build_unencoding_stack + * relpath: lib/content_encoding.c + */ + +CURLcode Curl_build_unencoding_stack(struct Curl_easy *data, + const char *enclist, int maybechunked) +{ + struct SingleRequest *k = &data->req; + + do { + const char *name; + size_t namelen; + + /* Parse a single encoding name. */ + while(ISSPACE(*enclist) || *enclist == ',') + enclist++; + + name = enclist; + + for(namelen = 0; *enclist && *enclist != ','; enclist++) + if(!ISSPACE(*enclist)) + namelen = enclist - name + 1; + + /* Special case: chunked encoding is handled at the reader level. */ + if(maybechunked && namelen == 7 && strncasecompare(name, "chunked", 7)) { + k->chunk = TRUE; /* chunks coming our way. */ + Curl_httpchunk_init(data); /* init our chunky engine. */ + } + else if(namelen) { + const struct content_encoding *encoding = find_encoding(name, namelen); + struct contenc_writer *writer; + + if(!k->writer_stack) { + k->writer_stack = new_unencoding_writer(data, &client_encoding, NULL); + + if(!k->writer_stack) + return CURLE_OUT_OF_MEMORY; + } + + if(!encoding) + encoding = &error_encoding; /* Defer error at stack use. */ + + /* Stack the unencoding stage. */ + writer = new_unencoding_writer(data, encoding, k->writer_stack); + if(!writer) + return CURLE_OUT_OF_MEMORY; + k->writer_stack = writer; + } + } while(*enclist); + + return CURLE_OK; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-32207/fixed.c b/benchmarks/pairs/vfc/curl-cve-2022-32207/fixed.c new file mode 100644 index 0000000..9ca2e5e --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-32207/fixed.c @@ -0,0 +1,110 @@ +/* Provenance: curl/curl cookie_output (fixed). + * repo: curl/curl + * commit: 20f9dd6bae50b7223171b17ba7798946e74f877f + * parent: 46f8911d3942dc06fdd67e9f6f3908982e5d2fb4 + * commit_url: https://github.com/curl/curl/commit/20f9dd6bae50b7223171b17ba7798946e74f877f + * cve: CVE-2022-32207 + * license: curl + * function: cookie_output + * relpath: lib/cookie.c + */ + +* cookie_output() + * + * Writes all internally known cookies to the specified file. Specify + * "-" as file name to write to stdout. + * + * The function returns non-zero on write failure. + */ +static CURLcode cookie_output(struct Curl_easy *data, + struct CookieInfo *c, const char *filename) +{ + struct Cookie *co; + FILE *out = NULL; + bool use_stdout = FALSE; + char *tempstore = NULL; + CURLcode error = CURLE_OK; + + if(!c) + /* no cookie engine alive */ + return CURLE_OK; + + /* at first, remove expired cookies */ + remove_expired(c); + + if(!strcmp("-", filename)) { + /* use stdout */ + out = stdout; + use_stdout = TRUE; + } + else { + error = Curl_fopen(data, filename, &out, &tempstore); + if(error) + goto error; + } + + fputs("# Netscape HTTP Cookie File\n" + "# https://curl.se/docs/http-cookies.html\n" + "# This file was generated by libcurl! Edit at your own risk.\n\n", + out); + + if(c->numcookies) { + unsigned int i; + size_t nvalid = 0; + struct Cookie **array; + + array = calloc(1, sizeof(struct Cookie *) * c->numcookies); + if(!array) { + error = CURLE_OUT_OF_MEMORY; + goto error; + } + + /* only sort the cookies with a domain property */ + for(i = 0; i < COOKIE_HASH_SIZE; i++) { + for(co = c->cookies[i]; co; co = co->next) { + if(!co->domain) + continue; + array[nvalid++] = co; + } + } + + qsort(array, nvalid, sizeof(struct Cookie *), cookie_sort_ct); + + for(i = 0; i < nvalid; i++) { + char *format_ptr = get_netscape_format(array[i]); + if(!format_ptr) { + free(array); + error = CURLE_OUT_OF_MEMORY; + goto error; + } + fprintf(out, "%s\n", format_ptr); + free(format_ptr); + } + + free(array); + } + + if(!use_stdout) { + fclose(out); + out = NULL; + if(tempstore && Curl_rename(tempstore, filename)) { + unlink(tempstore); + error = CURLE_WRITE_ERROR; + goto error; + } + } + + /* + * If we reach here we have successfully written a cookie file so theree is + * no need to inspect the error, any error case should have jumped into the + * error block below. + */ + free(tempstore); + return CURLE_OK; + +error: + if(out && !use_stdout) + fclose(out); + free(tempstore); + return error; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-32207/vuln.c b/benchmarks/pairs/vfc/curl-cve-2022-32207/vuln.c new file mode 100644 index 0000000..0850245 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-32207/vuln.c @@ -0,0 +1,121 @@ +/* Provenance: curl/curl cookie_output (vuln). + * repo: curl/curl + * commit: 46f8911d3942dc06fdd67e9f6f3908982e5d2fb4 + * parent: 46f8911d3942dc06fdd67e9f6f3908982e5d2fb4 + * commit_url: https://github.com/curl/curl/commit/20f9dd6bae50b7223171b17ba7798946e74f877f + * cve: CVE-2022-32207 + * license: curl + * function: cookie_output + * relpath: lib/cookie.c + */ + +* cookie_output() + * + * Writes all internally known cookies to the specified file. Specify + * "-" as file name to write to stdout. + * + * The function returns non-zero on write failure. + */ +static CURLcode cookie_output(struct Curl_easy *data, + struct CookieInfo *c, const char *filename) +{ + struct Cookie *co; + FILE *out = NULL; + bool use_stdout = FALSE; + char *tempstore = NULL; + CURLcode error = CURLE_OK; + + if(!c) + /* no cookie engine alive */ + return CURLE_OK; + + /* at first, remove expired cookies */ + remove_expired(c); + + if(!strcmp("-", filename)) { + /* use stdout */ + out = stdout; + use_stdout = TRUE; + } + else { + unsigned char randsuffix[9]; + + if(Curl_rand_hex(data, randsuffix, sizeof(randsuffix))) + return 2; + + tempstore = aprintf("%s.%s.tmp", filename, randsuffix); + if(!tempstore) + return CURLE_OUT_OF_MEMORY; + + out = fopen(tempstore, FOPEN_WRITETEXT); + if(!out) { + error = CURLE_WRITE_ERROR; + goto error; + } + } + + fputs("# Netscape HTTP Cookie File\n" + "# https://curl.se/docs/http-cookies.html\n" + "# This file was generated by libcurl! Edit at your own risk.\n\n", + out); + + if(c->numcookies) { + unsigned int i; + size_t nvalid = 0; + struct Cookie **array; + + array = calloc(1, sizeof(struct Cookie *) * c->numcookies); + if(!array) { + error = CURLE_OUT_OF_MEMORY; + goto error; + } + + /* only sort the cookies with a domain property */ + for(i = 0; i < COOKIE_HASH_SIZE; i++) { + for(co = c->cookies[i]; co; co = co->next) { + if(!co->domain) + continue; + array[nvalid++] = co; + } + } + + qsort(array, nvalid, sizeof(struct Cookie *), cookie_sort_ct); + + for(i = 0; i < nvalid; i++) { + char *format_ptr = get_netscape_format(array[i]); + if(!format_ptr) { + free(array); + error = CURLE_OUT_OF_MEMORY; + goto error; + } + fprintf(out, "%s\n", format_ptr); + free(format_ptr); + } + + free(array); + } + + if(!use_stdout) { + fclose(out); + out = NULL; + if(Curl_rename(tempstore, filename)) { + unlink(tempstore); + error = CURLE_WRITE_ERROR; + goto error; + } + } + + /* + * If we reach here we have successfully written a cookie file so theree is + * no need to inspect the error, any error case should have jumped into the + * error block below. + */ + free(tempstore); + return CURLE_OK; + +error: + if(out && !use_stdout) + fclose(out); + free(tempstore); + return error; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-32208/fixed.c b/benchmarks/pairs/vfc/curl-cve-2022-32208/fixed.c new file mode 100644 index 0000000..08e4392 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-32208/fixed.c @@ -0,0 +1,45 @@ +/* Provenance: curl/curl read_data (fixed). + * repo: curl/curl + * commit: 6ecdf5136b52af747e7bda08db9a748256b1cd09 + * parent: 2b67a0a1129b20a56ed04859fec8999f5c0c4280 + * commit_url: https://github.com/curl/curl/commit/6ecdf5136b52af747e7bda08db9a748256b1cd09 + * cve: CVE-2022-32208 + * license: curl + * function: read_data + * relpath: lib/krb5.c + */ + +static CURLcode read_data(struct connectdata *conn, + curl_socket_t fd, + struct krb5buffer *buf) +{ + int len; + CURLcode result; + int nread; + + result = socket_read(fd, &len, sizeof(len)); + if(result) + return result; + + if(len) { + /* only realloc if there was a length */ + len = ntohl(len); + if(len > CURL_MAX_INPUT_LENGTH) + len = 0; + else + buf->data = Curl_saferealloc(buf->data, len); + } + if(!len || !buf->data) + return CURLE_OUT_OF_MEMORY; + + result = socket_read(fd, buf->data, len); + if(result) + return result; + nread = conn->mech->decode(conn->app_data, buf->data, len, + conn->data_prot, conn); + if(nread < 0) + return CURLE_RECV_ERROR; + buf->size = (size_t)nread; + buf->index = 0; + return CURLE_OK; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2022-32208/vuln.c b/benchmarks/pairs/vfc/curl-cve-2022-32208/vuln.c new file mode 100644 index 0000000..02f11e5 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2022-32208/vuln.c @@ -0,0 +1,38 @@ +/* Provenance: curl/curl read_data (vuln). + * repo: curl/curl + * commit: 2b67a0a1129b20a56ed04859fec8999f5c0c4280 + * parent: 2b67a0a1129b20a56ed04859fec8999f5c0c4280 + * commit_url: https://github.com/curl/curl/commit/6ecdf5136b52af747e7bda08db9a748256b1cd09 + * cve: CVE-2022-32208 + * license: curl + * function: read_data + * relpath: lib/krb5.c + */ + +static CURLcode read_data(struct connectdata *conn, + curl_socket_t fd, + struct krb5buffer *buf) +{ + int len; + CURLcode result; + + result = socket_read(fd, &len, sizeof(len)); + if(result) + return result; + + if(len) { + /* only realloc if there was a length */ + len = ntohl(len); + buf->data = Curl_saferealloc(buf->data, len); + } + if(!len || !buf->data) + return CURLE_OUT_OF_MEMORY; + + result = socket_read(fd, buf->data, len); + if(result) + return result; + buf->size = conn->mech->decode(conn->app_data, buf->data, len, + conn->data_prot, conn); + buf->index = 0; + return CURLE_OK; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2023-38545-do_socks5/fixed.c b/benchmarks/pairs/vfc/curl-cve-2023-38545-do_socks5/fixed.c new file mode 100644 index 0000000..e4dde4d --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2023-38545-do_socks5/fixed.c @@ -0,0 +1,518 @@ +/* Provenance: curl/curl do_SOCKS5 (fixed). + * repo: curl/curl + * commit: fb4415d8aee6c1045be932a34fe6107c2f5ed147 + * parent: 09e25b9d94f4106eac8ca3a43b221bdc66f405e4 + * commit_url: https://github.com/curl/curl/commit/fb4415d8aee6c1045be932a34fe6107c2f5ed147 + * cve: CVE-2023-38545 + * license: curl + * function: do_SOCKS5 + * relpath: lib/socks.c + */ + +static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf, + struct socks_state *sx, + struct Curl_easy *data) +{ + /* + According to the RFC1928, section "6. Replies". This is what a SOCK5 + replies: + + +----+-----+-------+------+----------+----------+ + |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | + +----+-----+-------+------+----------+----------+ + | 1 | 1 | X'00' | 1 | Variable | 2 | + +----+-----+-------+------+----------+----------+ + + Where: + + o VER protocol version: X'05' + o REP Reply field: + o X'00' succeeded + */ + struct connectdata *conn = cf->conn; + unsigned char *socksreq = (unsigned char *)data->state.buffer; + int idx; + CURLcode result; + CURLproxycode presult; + bool socks5_resolve_local = + (conn->socks_proxy.proxytype == CURLPROXY_SOCKS5) ? TRUE : FALSE; + const size_t hostname_len = strlen(sx->hostname); + ssize_t len = 0; + const unsigned char auth = data->set.socks5auth; + bool allow_gssapi = FALSE; + struct Curl_dns_entry *dns = NULL; + + DEBUGASSERT(auth & (CURLAUTH_BASIC | CURLAUTH_GSSAPI)); + switch(sx->state) { + case CONNECT_SOCKS_INIT: + if(conn->bits.httpproxy) + infof(data, "SOCKS5: connecting to HTTP proxy %s port %d", + sx->hostname, sx->remote_port); + + /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */ + if(!socks5_resolve_local && hostname_len > 255) { + failf(data, "SOCKS5: the destination hostname is too long to be " + "resolved remotely by the proxy."); + return CURLPX_LONG_HOSTNAME; + } + + if(auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI)) + infof(data, + "warning: unsupported value passed to CURLOPT_SOCKS5_AUTH: %u", + auth); + if(!(auth & CURLAUTH_BASIC)) + /* disable username/password auth */ + sx->proxy_user = NULL; +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + if(auth & CURLAUTH_GSSAPI) + allow_gssapi = TRUE; +#endif + + idx = 0; + socksreq[idx++] = 5; /* version */ + idx++; /* number of authentication methods */ + socksreq[idx++] = 0; /* no authentication */ + if(allow_gssapi) + socksreq[idx++] = 1; /* GSS-API */ + if(sx->proxy_user) + socksreq[idx++] = 2; /* username/password */ + /* write the number of authentication methods */ + socksreq[1] = (unsigned char) (idx - 2); + + sx->outp = socksreq; + sx->outstanding = idx; + presult = socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT, + "initial SOCKS5 request"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in sending state */ + return CURLPX_OK; + } + sxstate(sx, data, CONNECT_SOCKS_READ); + goto CONNECT_SOCKS_READ_INIT; + case CONNECT_SOCKS_SEND: + presult = socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT, + "initial SOCKS5 request"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in sending state */ + return CURLPX_OK; + } + /* FALLTHROUGH */ +CONNECT_SOCKS_READ_INIT: + case CONNECT_SOCKS_READ_INIT: + sx->outstanding = 2; /* expect two bytes */ + sx->outp = socksreq; /* store it here */ + /* FALLTHROUGH */ + case CONNECT_SOCKS_READ: + presult = socks_state_recv(cf, sx, data, CURLPX_RECV_CONNECT, + "initial SOCKS5 response"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in reading state */ + return CURLPX_OK; + } + else if(socksreq[0] != 5) { + failf(data, "Received invalid version in initial SOCKS5 response."); + return CURLPX_BAD_VERSION; + } + else if(socksreq[1] == 0) { + /* DONE! No authentication needed. Send request. */ + sxstate(sx, data, CONNECT_REQ_INIT); + goto CONNECT_REQ_INIT; + } + else if(socksreq[1] == 2) { + /* regular name + password authentication */ + sxstate(sx, data, CONNECT_AUTH_INIT); + goto CONNECT_AUTH_INIT; + } +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + else if(allow_gssapi && (socksreq[1] == 1)) { + sxstate(sx, data, CONNECT_GSSAPI_INIT); + result = Curl_SOCKS5_gssapi_negotiate(cf, data); + if(result) { + failf(data, "Unable to negotiate SOCKS5 GSS-API context."); + return CURLPX_GSSAPI; + } + } +#endif + else { + /* error */ + if(!allow_gssapi && (socksreq[1] == 1)) { + failf(data, + "SOCKS5 GSSAPI per-message authentication is not supported."); + return CURLPX_GSSAPI_PERMSG; + } + else if(socksreq[1] == 255) { + failf(data, "No authentication method was acceptable."); + return CURLPX_NO_AUTH; + } + } + failf(data, + "Undocumented SOCKS5 mode attempted to be used by server."); + return CURLPX_UNKNOWN_MODE; +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + case CONNECT_GSSAPI_INIT: + /* GSSAPI stuff done non-blocking */ + break; +#endif + + default: /* do nothing! */ + break; + +CONNECT_AUTH_INIT: + case CONNECT_AUTH_INIT: { + /* Needs user name and password */ + size_t proxy_user_len, proxy_password_len; + if(sx->proxy_user && sx->proxy_password) { + proxy_user_len = strlen(sx->proxy_user); + proxy_password_len = strlen(sx->proxy_password); + } + else { + proxy_user_len = 0; + proxy_password_len = 0; + } + + /* username/password request looks like + * +----+------+----------+------+----------+ + * |VER | ULEN | UNAME | PLEN | PASSWD | + * +----+------+----------+------+----------+ + * | 1 | 1 | 1 to 255 | 1 | 1 to 255 | + * +----+------+----------+------+----------+ + */ + len = 0; + socksreq[len++] = 1; /* username/pw subnegotiation version */ + socksreq[len++] = (unsigned char) proxy_user_len; + if(sx->proxy_user && proxy_user_len) { + /* the length must fit in a single byte */ + if(proxy_user_len > 255) { + failf(data, "Excessive user name length for proxy auth"); + return CURLPX_LONG_USER; + } + memcpy(socksreq + len, sx->proxy_user, proxy_user_len); + } + len += proxy_user_len; + socksreq[len++] = (unsigned char) proxy_password_len; + if(sx->proxy_password && proxy_password_len) { + /* the length must fit in a single byte */ + if(proxy_password_len > 255) { + failf(data, "Excessive password length for proxy auth"); + return CURLPX_LONG_PASSWD; + } + memcpy(socksreq + len, sx->proxy_password, proxy_password_len); + } + len += proxy_password_len; + sxstate(sx, data, CONNECT_AUTH_SEND); + sx->outstanding = len; + sx->outp = socksreq; + } + /* FALLTHROUGH */ + case CONNECT_AUTH_SEND: + presult = socks_state_send(cf, sx, data, CURLPX_SEND_AUTH, + "SOCKS5 sub-negotiation request"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in sending state */ + return CURLPX_OK; + } + sx->outp = socksreq; + sx->outstanding = 2; + sxstate(sx, data, CONNECT_AUTH_READ); + /* FALLTHROUGH */ + case CONNECT_AUTH_READ: + presult = socks_state_recv(cf, sx, data, CURLPX_RECV_AUTH, + "SOCKS5 sub-negotiation response"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in reading state */ + return CURLPX_OK; + } + /* ignore the first (VER) byte */ + else if(socksreq[1]) { /* status */ + failf(data, "User was rejected by the SOCKS5 server (%d %d).", + socksreq[0], socksreq[1]); + return CURLPX_USER_REJECTED; + } + + /* Everything is good so far, user was authenticated! */ + sxstate(sx, data, CONNECT_REQ_INIT); + /* FALLTHROUGH */ +CONNECT_REQ_INIT: + case CONNECT_REQ_INIT: + if(socks5_resolve_local) { + enum resolve_t rc = Curl_resolv(data, sx->hostname, sx->remote_port, + TRUE, &dns); + + if(rc == CURLRESOLV_ERROR) + return CURLPX_RESOLVE_HOST; + + if(rc == CURLRESOLV_PENDING) { + sxstate(sx, data, CONNECT_RESOLVING); + return CURLPX_OK; + } + sxstate(sx, data, CONNECT_RESOLVED); + goto CONNECT_RESOLVED; + } + goto CONNECT_RESOLVE_REMOTE; + + case CONNECT_RESOLVING: + /* check if we have the name resolved by now */ + dns = Curl_fetch_addr(data, sx->hostname, sx->remote_port); + + if(dns) { +#ifdef CURLRES_ASYNCH + data->state.async.dns = dns; + data->state.async.done = TRUE; +#endif + infof(data, "SOCKS5: hostname '%s' found", sx->hostname); + } + + if(!dns) { + result = Curl_resolv_check(data, &dns); + if(!dns) { + if(result) + return CURLPX_RESOLVE_HOST; + return CURLPX_OK; + } + } + /* FALLTHROUGH */ +CONNECT_RESOLVED: + case CONNECT_RESOLVED: { + char dest[MAX_IPADR_LEN] = "unknown"; /* printable address */ + struct Curl_addrinfo *hp = NULL; + if(dns) + hp = dns->addr; + if(!hp) { + failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.", + sx->hostname); + return CURLPX_RESOLVE_HOST; + } + + Curl_printable_address(hp, dest, sizeof(dest)); + + len = 0; + socksreq[len++] = 5; /* version (SOCKS5) */ + socksreq[len++] = 1; /* connect */ + socksreq[len++] = 0; /* must be zero */ + if(hp->ai_family == AF_INET) { + int i; + struct sockaddr_in *saddr_in; + socksreq[len++] = 1; /* ATYP: IPv4 = 1 */ + + saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr; + for(i = 0; i < 4; i++) { + socksreq[len++] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[i]; + } + + infof(data, "SOCKS5 connect to %s:%d (locally resolved)", dest, + sx->remote_port); + } +#ifdef ENABLE_IPV6 + else if(hp->ai_family == AF_INET6) { + int i; + struct sockaddr_in6 *saddr_in6; + socksreq[len++] = 4; /* ATYP: IPv6 = 4 */ + + saddr_in6 = (struct sockaddr_in6 *)(void *)hp->ai_addr; + for(i = 0; i < 16; i++) { + socksreq[len++] = + ((unsigned char *)&saddr_in6->sin6_addr.s6_addr)[i]; + } + + infof(data, "SOCKS5 connect to [%s]:%d (locally resolved)", dest, + sx->remote_port); + } +#endif + else { + hp = NULL; /* fail! */ + failf(data, "SOCKS5 connection to %s not supported", dest); + } + + Curl_resolv_unlock(data, dns); /* not used anymore from now on */ + goto CONNECT_REQ_SEND; + } +CONNECT_RESOLVE_REMOTE: + case CONNECT_RESOLVE_REMOTE: + /* Authentication is complete, now specify destination to the proxy */ + len = 0; + socksreq[len++] = 5; /* version (SOCKS5) */ + socksreq[len++] = 1; /* connect */ + socksreq[len++] = 0; /* must be zero */ + + if(!socks5_resolve_local) { + /* ATYP: domain name = 3, + IPv6 == 4, + IPv4 == 1 */ + unsigned char ip4[4]; +#ifdef ENABLE_IPV6 + if(conn->bits.ipv6_ip) { + char ip6[16]; + if(1 != Curl_inet_pton(AF_INET6, sx->hostname, ip6)) + return CURLPX_BAD_ADDRESS_TYPE; + socksreq[len++] = 4; + memcpy(&socksreq[len], ip6, sizeof(ip6)); + len += sizeof(ip6); + } + else +#endif + if(1 == Curl_inet_pton(AF_INET, sx->hostname, ip4)) { + socksreq[len++] = 1; + memcpy(&socksreq[len], ip4, sizeof(ip4)); + len += sizeof(ip4); + } + else { + socksreq[len++] = 3; + socksreq[len++] = (unsigned char) hostname_len; /* one byte length */ + memcpy(&socksreq[len], sx->hostname, hostname_len); /* w/o NULL */ + len += hostname_len; + } + infof(data, "SOCKS5 connect to %s:%d (remotely resolved)", + sx->hostname, sx->remote_port); + } + /* FALLTHROUGH */ + +CONNECT_REQ_SEND: + case CONNECT_REQ_SEND: + /* PORT MSB */ + socksreq[len++] = (unsigned char)((sx->remote_port >> 8) & 0xff); + /* PORT LSB */ + socksreq[len++] = (unsigned char)(sx->remote_port & 0xff); + +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + if(conn->socks5_gssapi_enctype) { + failf(data, "SOCKS5 GSS-API protection not yet implemented."); + return CURLPX_GSSAPI_PROTECTION; + } +#endif + sx->outp = socksreq; + sx->outstanding = len; + sxstate(sx, data, CONNECT_REQ_SENDING); + /* FALLTHROUGH */ + case CONNECT_REQ_SENDING: + presult = socks_state_send(cf, sx, data, CURLPX_SEND_REQUEST, + "SOCKS5 connect request"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in send state */ + return CURLPX_OK; + } +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + if(conn->socks5_gssapi_enctype) { + failf(data, "SOCKS5 GSS-API protection not yet implemented."); + return CURLPX_GSSAPI_PROTECTION; + } +#endif + sx->outstanding = 10; /* minimum packet size is 10 */ + sx->outp = socksreq; + sxstate(sx, data, CONNECT_REQ_READ); + /* FALLTHROUGH */ + case CONNECT_REQ_READ: + presult = socks_state_recv(cf, sx, data, CURLPX_RECV_REQACK, + "SOCKS5 connect request ack"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in reading state */ + return CURLPX_OK; + } + else if(socksreq[0] != 5) { /* version */ + failf(data, + "SOCKS5 reply has wrong version, version should be 5."); + return CURLPX_BAD_VERSION; + } + else if(socksreq[1]) { /* Anything besides 0 is an error */ + CURLproxycode rc = CURLPX_REPLY_UNASSIGNED; + int code = socksreq[1]; + failf(data, "Can't complete SOCKS5 connection to %s. (%d)", + sx->hostname, (unsigned char)socksreq[1]); + if(code < 9) { + /* RFC 1928 section 6 lists: */ + static const CURLproxycode lookup[] = { + CURLPX_OK, + CURLPX_REPLY_GENERAL_SERVER_FAILURE, + CURLPX_REPLY_NOT_ALLOWED, + CURLPX_REPLY_NETWORK_UNREACHABLE, + CURLPX_REPLY_HOST_UNREACHABLE, + CURLPX_REPLY_CONNECTION_REFUSED, + CURLPX_REPLY_TTL_EXPIRED, + CURLPX_REPLY_COMMAND_NOT_SUPPORTED, + CURLPX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED, + }; + rc = lookup[code]; + } + return rc; + } + + /* Fix: in general, returned BND.ADDR is variable length parameter by RFC + 1928, so the reply packet should be read until the end to avoid errors + at subsequent protocol level. + + +----+-----+-------+------+----------+----------+ + |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | + +----+-----+-------+------+----------+----------+ + | 1 | 1 | X'00' | 1 | Variable | 2 | + +----+-----+-------+------+----------+----------+ + + ATYP: + o IP v4 address: X'01', BND.ADDR = 4 byte + o domain name: X'03', BND.ADDR = [ 1 byte length, string ] + o IP v6 address: X'04', BND.ADDR = 16 byte + */ + + /* Calculate real packet size */ + if(socksreq[3] == 3) { + /* domain name */ + int addrlen = (int) socksreq[4]; + len = 5 + addrlen + 2; + } + else if(socksreq[3] == 4) { + /* IPv6 */ + len = 4 + 16 + 2; + } + else if(socksreq[3] == 1) { + len = 4 + 4 + 2; + } + else { + failf(data, "SOCKS5 reply has wrong address type."); + return CURLPX_BAD_ADDRESS_TYPE; + } + + /* At this point we already read first 10 bytes */ +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + if(!conn->socks5_gssapi_enctype) { + /* decrypt_gssapi_blockread already read the whole packet */ +#endif + if(len > 10) { + sx->outstanding = len - 10; /* get the rest */ + sx->outp = &socksreq[10]; + sxstate(sx, data, CONNECT_REQ_READ_MORE); + } + else { + sxstate(sx, data, CONNECT_DONE); + break; + } +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + } +#endif + /* FALLTHROUGH */ + case CONNECT_REQ_READ_MORE: + presult = socks_state_recv(cf, sx, data, CURLPX_RECV_ADDRESS, + "SOCKS5 connect request address"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in reading state */ + return CURLPX_OK; + } + sxstate(sx, data, CONNECT_DONE); + } + infof(data, "SOCKS5 request granted."); + + return CURLPX_OK; /* Proxy was successful! */ +} diff --git a/benchmarks/pairs/vfc/curl-cve-2023-38545-do_socks5/vuln.c b/benchmarks/pairs/vfc/curl-cve-2023-38545-do_socks5/vuln.c new file mode 100644 index 0000000..780fcad --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2023-38545-do_socks5/vuln.c @@ -0,0 +1,518 @@ +/* Provenance: curl/curl do_SOCKS5 (vuln). + * repo: curl/curl + * commit: 09e25b9d94f4106eac8ca3a43b221bdc66f405e4 + * parent: 09e25b9d94f4106eac8ca3a43b221bdc66f405e4 + * commit_url: https://github.com/curl/curl/commit/fb4415d8aee6c1045be932a34fe6107c2f5ed147 + * cve: CVE-2023-38545 + * license: curl + * function: do_SOCKS5 + * relpath: lib/socks.c + */ + +static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf, + struct socks_state *sx, + struct Curl_easy *data) +{ + /* + According to the RFC1928, section "6. Replies". This is what a SOCK5 + replies: + + +----+-----+-------+------+----------+----------+ + |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | + +----+-----+-------+------+----------+----------+ + | 1 | 1 | X'00' | 1 | Variable | 2 | + +----+-----+-------+------+----------+----------+ + + Where: + + o VER protocol version: X'05' + o REP Reply field: + o X'00' succeeded + */ + struct connectdata *conn = cf->conn; + unsigned char *socksreq = (unsigned char *)data->state.buffer; + int idx; + CURLcode result; + CURLproxycode presult; + bool socks5_resolve_local = + (conn->socks_proxy.proxytype == CURLPROXY_SOCKS5) ? TRUE : FALSE; + const size_t hostname_len = strlen(sx->hostname); + ssize_t len = 0; + const unsigned char auth = data->set.socks5auth; + bool allow_gssapi = FALSE; + struct Curl_dns_entry *dns = NULL; + + DEBUGASSERT(auth & (CURLAUTH_BASIC | CURLAUTH_GSSAPI)); + switch(sx->state) { + case CONNECT_SOCKS_INIT: + if(conn->bits.httpproxy) + infof(data, "SOCKS5: connecting to HTTP proxy %s port %d", + sx->hostname, sx->remote_port); + + /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */ + if(!socks5_resolve_local && hostname_len > 255) { + infof(data, "SOCKS5: server resolving disabled for hostnames of " + "length > 255 [actual len=%zu]", hostname_len); + socks5_resolve_local = TRUE; + } + + if(auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI)) + infof(data, + "warning: unsupported value passed to CURLOPT_SOCKS5_AUTH: %u", + auth); + if(!(auth & CURLAUTH_BASIC)) + /* disable username/password auth */ + sx->proxy_user = NULL; +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + if(auth & CURLAUTH_GSSAPI) + allow_gssapi = TRUE; +#endif + + idx = 0; + socksreq[idx++] = 5; /* version */ + idx++; /* number of authentication methods */ + socksreq[idx++] = 0; /* no authentication */ + if(allow_gssapi) + socksreq[idx++] = 1; /* GSS-API */ + if(sx->proxy_user) + socksreq[idx++] = 2; /* username/password */ + /* write the number of authentication methods */ + socksreq[1] = (unsigned char) (idx - 2); + + sx->outp = socksreq; + sx->outstanding = idx; + presult = socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT, + "initial SOCKS5 request"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in sending state */ + return CURLPX_OK; + } + sxstate(sx, data, CONNECT_SOCKS_READ); + goto CONNECT_SOCKS_READ_INIT; + case CONNECT_SOCKS_SEND: + presult = socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT, + "initial SOCKS5 request"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in sending state */ + return CURLPX_OK; + } + /* FALLTHROUGH */ +CONNECT_SOCKS_READ_INIT: + case CONNECT_SOCKS_READ_INIT: + sx->outstanding = 2; /* expect two bytes */ + sx->outp = socksreq; /* store it here */ + /* FALLTHROUGH */ + case CONNECT_SOCKS_READ: + presult = socks_state_recv(cf, sx, data, CURLPX_RECV_CONNECT, + "initial SOCKS5 response"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in reading state */ + return CURLPX_OK; + } + else if(socksreq[0] != 5) { + failf(data, "Received invalid version in initial SOCKS5 response."); + return CURLPX_BAD_VERSION; + } + else if(socksreq[1] == 0) { + /* DONE! No authentication needed. Send request. */ + sxstate(sx, data, CONNECT_REQ_INIT); + goto CONNECT_REQ_INIT; + } + else if(socksreq[1] == 2) { + /* regular name + password authentication */ + sxstate(sx, data, CONNECT_AUTH_INIT); + goto CONNECT_AUTH_INIT; + } +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + else if(allow_gssapi && (socksreq[1] == 1)) { + sxstate(sx, data, CONNECT_GSSAPI_INIT); + result = Curl_SOCKS5_gssapi_negotiate(cf, data); + if(result) { + failf(data, "Unable to negotiate SOCKS5 GSS-API context."); + return CURLPX_GSSAPI; + } + } +#endif + else { + /* error */ + if(!allow_gssapi && (socksreq[1] == 1)) { + failf(data, + "SOCKS5 GSSAPI per-message authentication is not supported."); + return CURLPX_GSSAPI_PERMSG; + } + else if(socksreq[1] == 255) { + failf(data, "No authentication method was acceptable."); + return CURLPX_NO_AUTH; + } + } + failf(data, + "Undocumented SOCKS5 mode attempted to be used by server."); + return CURLPX_UNKNOWN_MODE; +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + case CONNECT_GSSAPI_INIT: + /* GSSAPI stuff done non-blocking */ + break; +#endif + + default: /* do nothing! */ + break; + +CONNECT_AUTH_INIT: + case CONNECT_AUTH_INIT: { + /* Needs user name and password */ + size_t proxy_user_len, proxy_password_len; + if(sx->proxy_user && sx->proxy_password) { + proxy_user_len = strlen(sx->proxy_user); + proxy_password_len = strlen(sx->proxy_password); + } + else { + proxy_user_len = 0; + proxy_password_len = 0; + } + + /* username/password request looks like + * +----+------+----------+------+----------+ + * |VER | ULEN | UNAME | PLEN | PASSWD | + * +----+------+----------+------+----------+ + * | 1 | 1 | 1 to 255 | 1 | 1 to 255 | + * +----+------+----------+------+----------+ + */ + len = 0; + socksreq[len++] = 1; /* username/pw subnegotiation version */ + socksreq[len++] = (unsigned char) proxy_user_len; + if(sx->proxy_user && proxy_user_len) { + /* the length must fit in a single byte */ + if(proxy_user_len > 255) { + failf(data, "Excessive user name length for proxy auth"); + return CURLPX_LONG_USER; + } + memcpy(socksreq + len, sx->proxy_user, proxy_user_len); + } + len += proxy_user_len; + socksreq[len++] = (unsigned char) proxy_password_len; + if(sx->proxy_password && proxy_password_len) { + /* the length must fit in a single byte */ + if(proxy_password_len > 255) { + failf(data, "Excessive password length for proxy auth"); + return CURLPX_LONG_PASSWD; + } + memcpy(socksreq + len, sx->proxy_password, proxy_password_len); + } + len += proxy_password_len; + sxstate(sx, data, CONNECT_AUTH_SEND); + sx->outstanding = len; + sx->outp = socksreq; + } + /* FALLTHROUGH */ + case CONNECT_AUTH_SEND: + presult = socks_state_send(cf, sx, data, CURLPX_SEND_AUTH, + "SOCKS5 sub-negotiation request"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in sending state */ + return CURLPX_OK; + } + sx->outp = socksreq; + sx->outstanding = 2; + sxstate(sx, data, CONNECT_AUTH_READ); + /* FALLTHROUGH */ + case CONNECT_AUTH_READ: + presult = socks_state_recv(cf, sx, data, CURLPX_RECV_AUTH, + "SOCKS5 sub-negotiation response"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in reading state */ + return CURLPX_OK; + } + /* ignore the first (VER) byte */ + else if(socksreq[1]) { /* status */ + failf(data, "User was rejected by the SOCKS5 server (%d %d).", + socksreq[0], socksreq[1]); + return CURLPX_USER_REJECTED; + } + + /* Everything is good so far, user was authenticated! */ + sxstate(sx, data, CONNECT_REQ_INIT); + /* FALLTHROUGH */ +CONNECT_REQ_INIT: + case CONNECT_REQ_INIT: + if(socks5_resolve_local) { + enum resolve_t rc = Curl_resolv(data, sx->hostname, sx->remote_port, + TRUE, &dns); + + if(rc == CURLRESOLV_ERROR) + return CURLPX_RESOLVE_HOST; + + if(rc == CURLRESOLV_PENDING) { + sxstate(sx, data, CONNECT_RESOLVING); + return CURLPX_OK; + } + sxstate(sx, data, CONNECT_RESOLVED); + goto CONNECT_RESOLVED; + } + goto CONNECT_RESOLVE_REMOTE; + + case CONNECT_RESOLVING: + /* check if we have the name resolved by now */ + dns = Curl_fetch_addr(data, sx->hostname, sx->remote_port); + + if(dns) { +#ifdef CURLRES_ASYNCH + data->state.async.dns = dns; + data->state.async.done = TRUE; +#endif + infof(data, "SOCKS5: hostname '%s' found", sx->hostname); + } + + if(!dns) { + result = Curl_resolv_check(data, &dns); + if(!dns) { + if(result) + return CURLPX_RESOLVE_HOST; + return CURLPX_OK; + } + } + /* FALLTHROUGH */ +CONNECT_RESOLVED: + case CONNECT_RESOLVED: { + char dest[MAX_IPADR_LEN] = "unknown"; /* printable address */ + struct Curl_addrinfo *hp = NULL; + if(dns) + hp = dns->addr; + if(!hp) { + failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.", + sx->hostname); + return CURLPX_RESOLVE_HOST; + } + + Curl_printable_address(hp, dest, sizeof(dest)); + + len = 0; + socksreq[len++] = 5; /* version (SOCKS5) */ + socksreq[len++] = 1; /* connect */ + socksreq[len++] = 0; /* must be zero */ + if(hp->ai_family == AF_INET) { + int i; + struct sockaddr_in *saddr_in; + socksreq[len++] = 1; /* ATYP: IPv4 = 1 */ + + saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr; + for(i = 0; i < 4; i++) { + socksreq[len++] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[i]; + } + + infof(data, "SOCKS5 connect to %s:%d (locally resolved)", dest, + sx->remote_port); + } +#ifdef ENABLE_IPV6 + else if(hp->ai_family == AF_INET6) { + int i; + struct sockaddr_in6 *saddr_in6; + socksreq[len++] = 4; /* ATYP: IPv6 = 4 */ + + saddr_in6 = (struct sockaddr_in6 *)(void *)hp->ai_addr; + for(i = 0; i < 16; i++) { + socksreq[len++] = + ((unsigned char *)&saddr_in6->sin6_addr.s6_addr)[i]; + } + + infof(data, "SOCKS5 connect to [%s]:%d (locally resolved)", dest, + sx->remote_port); + } +#endif + else { + hp = NULL; /* fail! */ + failf(data, "SOCKS5 connection to %s not supported", dest); + } + + Curl_resolv_unlock(data, dns); /* not used anymore from now on */ + goto CONNECT_REQ_SEND; + } +CONNECT_RESOLVE_REMOTE: + case CONNECT_RESOLVE_REMOTE: + /* Authentication is complete, now specify destination to the proxy */ + len = 0; + socksreq[len++] = 5; /* version (SOCKS5) */ + socksreq[len++] = 1; /* connect */ + socksreq[len++] = 0; /* must be zero */ + + if(!socks5_resolve_local) { + /* ATYP: domain name = 3, + IPv6 == 4, + IPv4 == 1 */ + unsigned char ip4[4]; +#ifdef ENABLE_IPV6 + if(conn->bits.ipv6_ip) { + char ip6[16]; + if(1 != Curl_inet_pton(AF_INET6, sx->hostname, ip6)) + return CURLPX_BAD_ADDRESS_TYPE; + socksreq[len++] = 4; + memcpy(&socksreq[len], ip6, sizeof(ip6)); + len += sizeof(ip6); + } + else +#endif + if(1 == Curl_inet_pton(AF_INET, sx->hostname, ip4)) { + socksreq[len++] = 1; + memcpy(&socksreq[len], ip4, sizeof(ip4)); + len += sizeof(ip4); + } + else { + socksreq[len++] = 3; + socksreq[len++] = (char) hostname_len; /* one byte address length */ + memcpy(&socksreq[len], sx->hostname, hostname_len); /* w/o NULL */ + len += hostname_len; + } + infof(data, "SOCKS5 connect to %s:%d (remotely resolved)", + sx->hostname, sx->remote_port); + } + /* FALLTHROUGH */ + +CONNECT_REQ_SEND: + case CONNECT_REQ_SEND: + /* PORT MSB */ + socksreq[len++] = (unsigned char)((sx->remote_port >> 8) & 0xff); + /* PORT LSB */ + socksreq[len++] = (unsigned char)(sx->remote_port & 0xff); + +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + if(conn->socks5_gssapi_enctype) { + failf(data, "SOCKS5 GSS-API protection not yet implemented."); + return CURLPX_GSSAPI_PROTECTION; + } +#endif + sx->outp = socksreq; + sx->outstanding = len; + sxstate(sx, data, CONNECT_REQ_SENDING); + /* FALLTHROUGH */ + case CONNECT_REQ_SENDING: + presult = socks_state_send(cf, sx, data, CURLPX_SEND_REQUEST, + "SOCKS5 connect request"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in send state */ + return CURLPX_OK; + } +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + if(conn->socks5_gssapi_enctype) { + failf(data, "SOCKS5 GSS-API protection not yet implemented."); + return CURLPX_GSSAPI_PROTECTION; + } +#endif + sx->outstanding = 10; /* minimum packet size is 10 */ + sx->outp = socksreq; + sxstate(sx, data, CONNECT_REQ_READ); + /* FALLTHROUGH */ + case CONNECT_REQ_READ: + presult = socks_state_recv(cf, sx, data, CURLPX_RECV_REQACK, + "SOCKS5 connect request ack"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in reading state */ + return CURLPX_OK; + } + else if(socksreq[0] != 5) { /* version */ + failf(data, + "SOCKS5 reply has wrong version, version should be 5."); + return CURLPX_BAD_VERSION; + } + else if(socksreq[1]) { /* Anything besides 0 is an error */ + CURLproxycode rc = CURLPX_REPLY_UNASSIGNED; + int code = socksreq[1]; + failf(data, "Can't complete SOCKS5 connection to %s. (%d)", + sx->hostname, (unsigned char)socksreq[1]); + if(code < 9) { + /* RFC 1928 section 6 lists: */ + static const CURLproxycode lookup[] = { + CURLPX_OK, + CURLPX_REPLY_GENERAL_SERVER_FAILURE, + CURLPX_REPLY_NOT_ALLOWED, + CURLPX_REPLY_NETWORK_UNREACHABLE, + CURLPX_REPLY_HOST_UNREACHABLE, + CURLPX_REPLY_CONNECTION_REFUSED, + CURLPX_REPLY_TTL_EXPIRED, + CURLPX_REPLY_COMMAND_NOT_SUPPORTED, + CURLPX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED, + }; + rc = lookup[code]; + } + return rc; + } + + /* Fix: in general, returned BND.ADDR is variable length parameter by RFC + 1928, so the reply packet should be read until the end to avoid errors + at subsequent protocol level. + + +----+-----+-------+------+----------+----------+ + |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | + +----+-----+-------+------+----------+----------+ + | 1 | 1 | X'00' | 1 | Variable | 2 | + +----+-----+-------+------+----------+----------+ + + ATYP: + o IP v4 address: X'01', BND.ADDR = 4 byte + o domain name: X'03', BND.ADDR = [ 1 byte length, string ] + o IP v6 address: X'04', BND.ADDR = 16 byte + */ + + /* Calculate real packet size */ + if(socksreq[3] == 3) { + /* domain name */ + int addrlen = (int) socksreq[4]; + len = 5 + addrlen + 2; + } + else if(socksreq[3] == 4) { + /* IPv6 */ + len = 4 + 16 + 2; + } + else if(socksreq[3] == 1) { + len = 4 + 4 + 2; + } + else { + failf(data, "SOCKS5 reply has wrong address type."); + return CURLPX_BAD_ADDRESS_TYPE; + } + + /* At this point we already read first 10 bytes */ +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + if(!conn->socks5_gssapi_enctype) { + /* decrypt_gssapi_blockread already read the whole packet */ +#endif + if(len > 10) { + sx->outstanding = len - 10; /* get the rest */ + sx->outp = &socksreq[10]; + sxstate(sx, data, CONNECT_REQ_READ_MORE); + } + else { + sxstate(sx, data, CONNECT_DONE); + break; + } +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + } +#endif + /* FALLTHROUGH */ + case CONNECT_REQ_READ_MORE: + presult = socks_state_recv(cf, sx, data, CURLPX_RECV_ADDRESS, + "SOCKS5 connect request address"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in reading state */ + return CURLPX_OK; + } + sxstate(sx, data, CONNECT_DONE); + } + infof(data, "SOCKS5 request granted."); + + return CURLPX_OK; /* Proxy was successful! */ +} diff --git a/benchmarks/pairs/vfc/curl-cve-2023-38545/fixed.c b/benchmarks/pairs/vfc/curl-cve-2023-38545/fixed.c new file mode 100644 index 0000000..e4dde4d --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2023-38545/fixed.c @@ -0,0 +1,518 @@ +/* Provenance: curl/curl do_SOCKS5 (fixed). + * repo: curl/curl + * commit: fb4415d8aee6c1045be932a34fe6107c2f5ed147 + * parent: 09e25b9d94f4106eac8ca3a43b221bdc66f405e4 + * commit_url: https://github.com/curl/curl/commit/fb4415d8aee6c1045be932a34fe6107c2f5ed147 + * cve: CVE-2023-38545 + * license: curl + * function: do_SOCKS5 + * relpath: lib/socks.c + */ + +static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf, + struct socks_state *sx, + struct Curl_easy *data) +{ + /* + According to the RFC1928, section "6. Replies". This is what a SOCK5 + replies: + + +----+-----+-------+------+----------+----------+ + |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | + +----+-----+-------+------+----------+----------+ + | 1 | 1 | X'00' | 1 | Variable | 2 | + +----+-----+-------+------+----------+----------+ + + Where: + + o VER protocol version: X'05' + o REP Reply field: + o X'00' succeeded + */ + struct connectdata *conn = cf->conn; + unsigned char *socksreq = (unsigned char *)data->state.buffer; + int idx; + CURLcode result; + CURLproxycode presult; + bool socks5_resolve_local = + (conn->socks_proxy.proxytype == CURLPROXY_SOCKS5) ? TRUE : FALSE; + const size_t hostname_len = strlen(sx->hostname); + ssize_t len = 0; + const unsigned char auth = data->set.socks5auth; + bool allow_gssapi = FALSE; + struct Curl_dns_entry *dns = NULL; + + DEBUGASSERT(auth & (CURLAUTH_BASIC | CURLAUTH_GSSAPI)); + switch(sx->state) { + case CONNECT_SOCKS_INIT: + if(conn->bits.httpproxy) + infof(data, "SOCKS5: connecting to HTTP proxy %s port %d", + sx->hostname, sx->remote_port); + + /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */ + if(!socks5_resolve_local && hostname_len > 255) { + failf(data, "SOCKS5: the destination hostname is too long to be " + "resolved remotely by the proxy."); + return CURLPX_LONG_HOSTNAME; + } + + if(auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI)) + infof(data, + "warning: unsupported value passed to CURLOPT_SOCKS5_AUTH: %u", + auth); + if(!(auth & CURLAUTH_BASIC)) + /* disable username/password auth */ + sx->proxy_user = NULL; +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + if(auth & CURLAUTH_GSSAPI) + allow_gssapi = TRUE; +#endif + + idx = 0; + socksreq[idx++] = 5; /* version */ + idx++; /* number of authentication methods */ + socksreq[idx++] = 0; /* no authentication */ + if(allow_gssapi) + socksreq[idx++] = 1; /* GSS-API */ + if(sx->proxy_user) + socksreq[idx++] = 2; /* username/password */ + /* write the number of authentication methods */ + socksreq[1] = (unsigned char) (idx - 2); + + sx->outp = socksreq; + sx->outstanding = idx; + presult = socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT, + "initial SOCKS5 request"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in sending state */ + return CURLPX_OK; + } + sxstate(sx, data, CONNECT_SOCKS_READ); + goto CONNECT_SOCKS_READ_INIT; + case CONNECT_SOCKS_SEND: + presult = socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT, + "initial SOCKS5 request"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in sending state */ + return CURLPX_OK; + } + /* FALLTHROUGH */ +CONNECT_SOCKS_READ_INIT: + case CONNECT_SOCKS_READ_INIT: + sx->outstanding = 2; /* expect two bytes */ + sx->outp = socksreq; /* store it here */ + /* FALLTHROUGH */ + case CONNECT_SOCKS_READ: + presult = socks_state_recv(cf, sx, data, CURLPX_RECV_CONNECT, + "initial SOCKS5 response"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in reading state */ + return CURLPX_OK; + } + else if(socksreq[0] != 5) { + failf(data, "Received invalid version in initial SOCKS5 response."); + return CURLPX_BAD_VERSION; + } + else if(socksreq[1] == 0) { + /* DONE! No authentication needed. Send request. */ + sxstate(sx, data, CONNECT_REQ_INIT); + goto CONNECT_REQ_INIT; + } + else if(socksreq[1] == 2) { + /* regular name + password authentication */ + sxstate(sx, data, CONNECT_AUTH_INIT); + goto CONNECT_AUTH_INIT; + } +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + else if(allow_gssapi && (socksreq[1] == 1)) { + sxstate(sx, data, CONNECT_GSSAPI_INIT); + result = Curl_SOCKS5_gssapi_negotiate(cf, data); + if(result) { + failf(data, "Unable to negotiate SOCKS5 GSS-API context."); + return CURLPX_GSSAPI; + } + } +#endif + else { + /* error */ + if(!allow_gssapi && (socksreq[1] == 1)) { + failf(data, + "SOCKS5 GSSAPI per-message authentication is not supported."); + return CURLPX_GSSAPI_PERMSG; + } + else if(socksreq[1] == 255) { + failf(data, "No authentication method was acceptable."); + return CURLPX_NO_AUTH; + } + } + failf(data, + "Undocumented SOCKS5 mode attempted to be used by server."); + return CURLPX_UNKNOWN_MODE; +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + case CONNECT_GSSAPI_INIT: + /* GSSAPI stuff done non-blocking */ + break; +#endif + + default: /* do nothing! */ + break; + +CONNECT_AUTH_INIT: + case CONNECT_AUTH_INIT: { + /* Needs user name and password */ + size_t proxy_user_len, proxy_password_len; + if(sx->proxy_user && sx->proxy_password) { + proxy_user_len = strlen(sx->proxy_user); + proxy_password_len = strlen(sx->proxy_password); + } + else { + proxy_user_len = 0; + proxy_password_len = 0; + } + + /* username/password request looks like + * +----+------+----------+------+----------+ + * |VER | ULEN | UNAME | PLEN | PASSWD | + * +----+------+----------+------+----------+ + * | 1 | 1 | 1 to 255 | 1 | 1 to 255 | + * +----+------+----------+------+----------+ + */ + len = 0; + socksreq[len++] = 1; /* username/pw subnegotiation version */ + socksreq[len++] = (unsigned char) proxy_user_len; + if(sx->proxy_user && proxy_user_len) { + /* the length must fit in a single byte */ + if(proxy_user_len > 255) { + failf(data, "Excessive user name length for proxy auth"); + return CURLPX_LONG_USER; + } + memcpy(socksreq + len, sx->proxy_user, proxy_user_len); + } + len += proxy_user_len; + socksreq[len++] = (unsigned char) proxy_password_len; + if(sx->proxy_password && proxy_password_len) { + /* the length must fit in a single byte */ + if(proxy_password_len > 255) { + failf(data, "Excessive password length for proxy auth"); + return CURLPX_LONG_PASSWD; + } + memcpy(socksreq + len, sx->proxy_password, proxy_password_len); + } + len += proxy_password_len; + sxstate(sx, data, CONNECT_AUTH_SEND); + sx->outstanding = len; + sx->outp = socksreq; + } + /* FALLTHROUGH */ + case CONNECT_AUTH_SEND: + presult = socks_state_send(cf, sx, data, CURLPX_SEND_AUTH, + "SOCKS5 sub-negotiation request"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in sending state */ + return CURLPX_OK; + } + sx->outp = socksreq; + sx->outstanding = 2; + sxstate(sx, data, CONNECT_AUTH_READ); + /* FALLTHROUGH */ + case CONNECT_AUTH_READ: + presult = socks_state_recv(cf, sx, data, CURLPX_RECV_AUTH, + "SOCKS5 sub-negotiation response"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in reading state */ + return CURLPX_OK; + } + /* ignore the first (VER) byte */ + else if(socksreq[1]) { /* status */ + failf(data, "User was rejected by the SOCKS5 server (%d %d).", + socksreq[0], socksreq[1]); + return CURLPX_USER_REJECTED; + } + + /* Everything is good so far, user was authenticated! */ + sxstate(sx, data, CONNECT_REQ_INIT); + /* FALLTHROUGH */ +CONNECT_REQ_INIT: + case CONNECT_REQ_INIT: + if(socks5_resolve_local) { + enum resolve_t rc = Curl_resolv(data, sx->hostname, sx->remote_port, + TRUE, &dns); + + if(rc == CURLRESOLV_ERROR) + return CURLPX_RESOLVE_HOST; + + if(rc == CURLRESOLV_PENDING) { + sxstate(sx, data, CONNECT_RESOLVING); + return CURLPX_OK; + } + sxstate(sx, data, CONNECT_RESOLVED); + goto CONNECT_RESOLVED; + } + goto CONNECT_RESOLVE_REMOTE; + + case CONNECT_RESOLVING: + /* check if we have the name resolved by now */ + dns = Curl_fetch_addr(data, sx->hostname, sx->remote_port); + + if(dns) { +#ifdef CURLRES_ASYNCH + data->state.async.dns = dns; + data->state.async.done = TRUE; +#endif + infof(data, "SOCKS5: hostname '%s' found", sx->hostname); + } + + if(!dns) { + result = Curl_resolv_check(data, &dns); + if(!dns) { + if(result) + return CURLPX_RESOLVE_HOST; + return CURLPX_OK; + } + } + /* FALLTHROUGH */ +CONNECT_RESOLVED: + case CONNECT_RESOLVED: { + char dest[MAX_IPADR_LEN] = "unknown"; /* printable address */ + struct Curl_addrinfo *hp = NULL; + if(dns) + hp = dns->addr; + if(!hp) { + failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.", + sx->hostname); + return CURLPX_RESOLVE_HOST; + } + + Curl_printable_address(hp, dest, sizeof(dest)); + + len = 0; + socksreq[len++] = 5; /* version (SOCKS5) */ + socksreq[len++] = 1; /* connect */ + socksreq[len++] = 0; /* must be zero */ + if(hp->ai_family == AF_INET) { + int i; + struct sockaddr_in *saddr_in; + socksreq[len++] = 1; /* ATYP: IPv4 = 1 */ + + saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr; + for(i = 0; i < 4; i++) { + socksreq[len++] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[i]; + } + + infof(data, "SOCKS5 connect to %s:%d (locally resolved)", dest, + sx->remote_port); + } +#ifdef ENABLE_IPV6 + else if(hp->ai_family == AF_INET6) { + int i; + struct sockaddr_in6 *saddr_in6; + socksreq[len++] = 4; /* ATYP: IPv6 = 4 */ + + saddr_in6 = (struct sockaddr_in6 *)(void *)hp->ai_addr; + for(i = 0; i < 16; i++) { + socksreq[len++] = + ((unsigned char *)&saddr_in6->sin6_addr.s6_addr)[i]; + } + + infof(data, "SOCKS5 connect to [%s]:%d (locally resolved)", dest, + sx->remote_port); + } +#endif + else { + hp = NULL; /* fail! */ + failf(data, "SOCKS5 connection to %s not supported", dest); + } + + Curl_resolv_unlock(data, dns); /* not used anymore from now on */ + goto CONNECT_REQ_SEND; + } +CONNECT_RESOLVE_REMOTE: + case CONNECT_RESOLVE_REMOTE: + /* Authentication is complete, now specify destination to the proxy */ + len = 0; + socksreq[len++] = 5; /* version (SOCKS5) */ + socksreq[len++] = 1; /* connect */ + socksreq[len++] = 0; /* must be zero */ + + if(!socks5_resolve_local) { + /* ATYP: domain name = 3, + IPv6 == 4, + IPv4 == 1 */ + unsigned char ip4[4]; +#ifdef ENABLE_IPV6 + if(conn->bits.ipv6_ip) { + char ip6[16]; + if(1 != Curl_inet_pton(AF_INET6, sx->hostname, ip6)) + return CURLPX_BAD_ADDRESS_TYPE; + socksreq[len++] = 4; + memcpy(&socksreq[len], ip6, sizeof(ip6)); + len += sizeof(ip6); + } + else +#endif + if(1 == Curl_inet_pton(AF_INET, sx->hostname, ip4)) { + socksreq[len++] = 1; + memcpy(&socksreq[len], ip4, sizeof(ip4)); + len += sizeof(ip4); + } + else { + socksreq[len++] = 3; + socksreq[len++] = (unsigned char) hostname_len; /* one byte length */ + memcpy(&socksreq[len], sx->hostname, hostname_len); /* w/o NULL */ + len += hostname_len; + } + infof(data, "SOCKS5 connect to %s:%d (remotely resolved)", + sx->hostname, sx->remote_port); + } + /* FALLTHROUGH */ + +CONNECT_REQ_SEND: + case CONNECT_REQ_SEND: + /* PORT MSB */ + socksreq[len++] = (unsigned char)((sx->remote_port >> 8) & 0xff); + /* PORT LSB */ + socksreq[len++] = (unsigned char)(sx->remote_port & 0xff); + +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + if(conn->socks5_gssapi_enctype) { + failf(data, "SOCKS5 GSS-API protection not yet implemented."); + return CURLPX_GSSAPI_PROTECTION; + } +#endif + sx->outp = socksreq; + sx->outstanding = len; + sxstate(sx, data, CONNECT_REQ_SENDING); + /* FALLTHROUGH */ + case CONNECT_REQ_SENDING: + presult = socks_state_send(cf, sx, data, CURLPX_SEND_REQUEST, + "SOCKS5 connect request"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in send state */ + return CURLPX_OK; + } +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + if(conn->socks5_gssapi_enctype) { + failf(data, "SOCKS5 GSS-API protection not yet implemented."); + return CURLPX_GSSAPI_PROTECTION; + } +#endif + sx->outstanding = 10; /* minimum packet size is 10 */ + sx->outp = socksreq; + sxstate(sx, data, CONNECT_REQ_READ); + /* FALLTHROUGH */ + case CONNECT_REQ_READ: + presult = socks_state_recv(cf, sx, data, CURLPX_RECV_REQACK, + "SOCKS5 connect request ack"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in reading state */ + return CURLPX_OK; + } + else if(socksreq[0] != 5) { /* version */ + failf(data, + "SOCKS5 reply has wrong version, version should be 5."); + return CURLPX_BAD_VERSION; + } + else if(socksreq[1]) { /* Anything besides 0 is an error */ + CURLproxycode rc = CURLPX_REPLY_UNASSIGNED; + int code = socksreq[1]; + failf(data, "Can't complete SOCKS5 connection to %s. (%d)", + sx->hostname, (unsigned char)socksreq[1]); + if(code < 9) { + /* RFC 1928 section 6 lists: */ + static const CURLproxycode lookup[] = { + CURLPX_OK, + CURLPX_REPLY_GENERAL_SERVER_FAILURE, + CURLPX_REPLY_NOT_ALLOWED, + CURLPX_REPLY_NETWORK_UNREACHABLE, + CURLPX_REPLY_HOST_UNREACHABLE, + CURLPX_REPLY_CONNECTION_REFUSED, + CURLPX_REPLY_TTL_EXPIRED, + CURLPX_REPLY_COMMAND_NOT_SUPPORTED, + CURLPX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED, + }; + rc = lookup[code]; + } + return rc; + } + + /* Fix: in general, returned BND.ADDR is variable length parameter by RFC + 1928, so the reply packet should be read until the end to avoid errors + at subsequent protocol level. + + +----+-----+-------+------+----------+----------+ + |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | + +----+-----+-------+------+----------+----------+ + | 1 | 1 | X'00' | 1 | Variable | 2 | + +----+-----+-------+------+----------+----------+ + + ATYP: + o IP v4 address: X'01', BND.ADDR = 4 byte + o domain name: X'03', BND.ADDR = [ 1 byte length, string ] + o IP v6 address: X'04', BND.ADDR = 16 byte + */ + + /* Calculate real packet size */ + if(socksreq[3] == 3) { + /* domain name */ + int addrlen = (int) socksreq[4]; + len = 5 + addrlen + 2; + } + else if(socksreq[3] == 4) { + /* IPv6 */ + len = 4 + 16 + 2; + } + else if(socksreq[3] == 1) { + len = 4 + 4 + 2; + } + else { + failf(data, "SOCKS5 reply has wrong address type."); + return CURLPX_BAD_ADDRESS_TYPE; + } + + /* At this point we already read first 10 bytes */ +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + if(!conn->socks5_gssapi_enctype) { + /* decrypt_gssapi_blockread already read the whole packet */ +#endif + if(len > 10) { + sx->outstanding = len - 10; /* get the rest */ + sx->outp = &socksreq[10]; + sxstate(sx, data, CONNECT_REQ_READ_MORE); + } + else { + sxstate(sx, data, CONNECT_DONE); + break; + } +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + } +#endif + /* FALLTHROUGH */ + case CONNECT_REQ_READ_MORE: + presult = socks_state_recv(cf, sx, data, CURLPX_RECV_ADDRESS, + "SOCKS5 connect request address"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in reading state */ + return CURLPX_OK; + } + sxstate(sx, data, CONNECT_DONE); + } + infof(data, "SOCKS5 request granted."); + + return CURLPX_OK; /* Proxy was successful! */ +} diff --git a/benchmarks/pairs/vfc/curl-cve-2023-38545/vuln.c b/benchmarks/pairs/vfc/curl-cve-2023-38545/vuln.c new file mode 100644 index 0000000..780fcad --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2023-38545/vuln.c @@ -0,0 +1,518 @@ +/* Provenance: curl/curl do_SOCKS5 (vuln). + * repo: curl/curl + * commit: 09e25b9d94f4106eac8ca3a43b221bdc66f405e4 + * parent: 09e25b9d94f4106eac8ca3a43b221bdc66f405e4 + * commit_url: https://github.com/curl/curl/commit/fb4415d8aee6c1045be932a34fe6107c2f5ed147 + * cve: CVE-2023-38545 + * license: curl + * function: do_SOCKS5 + * relpath: lib/socks.c + */ + +static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf, + struct socks_state *sx, + struct Curl_easy *data) +{ + /* + According to the RFC1928, section "6. Replies". This is what a SOCK5 + replies: + + +----+-----+-------+------+----------+----------+ + |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | + +----+-----+-------+------+----------+----------+ + | 1 | 1 | X'00' | 1 | Variable | 2 | + +----+-----+-------+------+----------+----------+ + + Where: + + o VER protocol version: X'05' + o REP Reply field: + o X'00' succeeded + */ + struct connectdata *conn = cf->conn; + unsigned char *socksreq = (unsigned char *)data->state.buffer; + int idx; + CURLcode result; + CURLproxycode presult; + bool socks5_resolve_local = + (conn->socks_proxy.proxytype == CURLPROXY_SOCKS5) ? TRUE : FALSE; + const size_t hostname_len = strlen(sx->hostname); + ssize_t len = 0; + const unsigned char auth = data->set.socks5auth; + bool allow_gssapi = FALSE; + struct Curl_dns_entry *dns = NULL; + + DEBUGASSERT(auth & (CURLAUTH_BASIC | CURLAUTH_GSSAPI)); + switch(sx->state) { + case CONNECT_SOCKS_INIT: + if(conn->bits.httpproxy) + infof(data, "SOCKS5: connecting to HTTP proxy %s port %d", + sx->hostname, sx->remote_port); + + /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */ + if(!socks5_resolve_local && hostname_len > 255) { + infof(data, "SOCKS5: server resolving disabled for hostnames of " + "length > 255 [actual len=%zu]", hostname_len); + socks5_resolve_local = TRUE; + } + + if(auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI)) + infof(data, + "warning: unsupported value passed to CURLOPT_SOCKS5_AUTH: %u", + auth); + if(!(auth & CURLAUTH_BASIC)) + /* disable username/password auth */ + sx->proxy_user = NULL; +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + if(auth & CURLAUTH_GSSAPI) + allow_gssapi = TRUE; +#endif + + idx = 0; + socksreq[idx++] = 5; /* version */ + idx++; /* number of authentication methods */ + socksreq[idx++] = 0; /* no authentication */ + if(allow_gssapi) + socksreq[idx++] = 1; /* GSS-API */ + if(sx->proxy_user) + socksreq[idx++] = 2; /* username/password */ + /* write the number of authentication methods */ + socksreq[1] = (unsigned char) (idx - 2); + + sx->outp = socksreq; + sx->outstanding = idx; + presult = socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT, + "initial SOCKS5 request"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in sending state */ + return CURLPX_OK; + } + sxstate(sx, data, CONNECT_SOCKS_READ); + goto CONNECT_SOCKS_READ_INIT; + case CONNECT_SOCKS_SEND: + presult = socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT, + "initial SOCKS5 request"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in sending state */ + return CURLPX_OK; + } + /* FALLTHROUGH */ +CONNECT_SOCKS_READ_INIT: + case CONNECT_SOCKS_READ_INIT: + sx->outstanding = 2; /* expect two bytes */ + sx->outp = socksreq; /* store it here */ + /* FALLTHROUGH */ + case CONNECT_SOCKS_READ: + presult = socks_state_recv(cf, sx, data, CURLPX_RECV_CONNECT, + "initial SOCKS5 response"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in reading state */ + return CURLPX_OK; + } + else if(socksreq[0] != 5) { + failf(data, "Received invalid version in initial SOCKS5 response."); + return CURLPX_BAD_VERSION; + } + else if(socksreq[1] == 0) { + /* DONE! No authentication needed. Send request. */ + sxstate(sx, data, CONNECT_REQ_INIT); + goto CONNECT_REQ_INIT; + } + else if(socksreq[1] == 2) { + /* regular name + password authentication */ + sxstate(sx, data, CONNECT_AUTH_INIT); + goto CONNECT_AUTH_INIT; + } +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + else if(allow_gssapi && (socksreq[1] == 1)) { + sxstate(sx, data, CONNECT_GSSAPI_INIT); + result = Curl_SOCKS5_gssapi_negotiate(cf, data); + if(result) { + failf(data, "Unable to negotiate SOCKS5 GSS-API context."); + return CURLPX_GSSAPI; + } + } +#endif + else { + /* error */ + if(!allow_gssapi && (socksreq[1] == 1)) { + failf(data, + "SOCKS5 GSSAPI per-message authentication is not supported."); + return CURLPX_GSSAPI_PERMSG; + } + else if(socksreq[1] == 255) { + failf(data, "No authentication method was acceptable."); + return CURLPX_NO_AUTH; + } + } + failf(data, + "Undocumented SOCKS5 mode attempted to be used by server."); + return CURLPX_UNKNOWN_MODE; +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + case CONNECT_GSSAPI_INIT: + /* GSSAPI stuff done non-blocking */ + break; +#endif + + default: /* do nothing! */ + break; + +CONNECT_AUTH_INIT: + case CONNECT_AUTH_INIT: { + /* Needs user name and password */ + size_t proxy_user_len, proxy_password_len; + if(sx->proxy_user && sx->proxy_password) { + proxy_user_len = strlen(sx->proxy_user); + proxy_password_len = strlen(sx->proxy_password); + } + else { + proxy_user_len = 0; + proxy_password_len = 0; + } + + /* username/password request looks like + * +----+------+----------+------+----------+ + * |VER | ULEN | UNAME | PLEN | PASSWD | + * +----+------+----------+------+----------+ + * | 1 | 1 | 1 to 255 | 1 | 1 to 255 | + * +----+------+----------+------+----------+ + */ + len = 0; + socksreq[len++] = 1; /* username/pw subnegotiation version */ + socksreq[len++] = (unsigned char) proxy_user_len; + if(sx->proxy_user && proxy_user_len) { + /* the length must fit in a single byte */ + if(proxy_user_len > 255) { + failf(data, "Excessive user name length for proxy auth"); + return CURLPX_LONG_USER; + } + memcpy(socksreq + len, sx->proxy_user, proxy_user_len); + } + len += proxy_user_len; + socksreq[len++] = (unsigned char) proxy_password_len; + if(sx->proxy_password && proxy_password_len) { + /* the length must fit in a single byte */ + if(proxy_password_len > 255) { + failf(data, "Excessive password length for proxy auth"); + return CURLPX_LONG_PASSWD; + } + memcpy(socksreq + len, sx->proxy_password, proxy_password_len); + } + len += proxy_password_len; + sxstate(sx, data, CONNECT_AUTH_SEND); + sx->outstanding = len; + sx->outp = socksreq; + } + /* FALLTHROUGH */ + case CONNECT_AUTH_SEND: + presult = socks_state_send(cf, sx, data, CURLPX_SEND_AUTH, + "SOCKS5 sub-negotiation request"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in sending state */ + return CURLPX_OK; + } + sx->outp = socksreq; + sx->outstanding = 2; + sxstate(sx, data, CONNECT_AUTH_READ); + /* FALLTHROUGH */ + case CONNECT_AUTH_READ: + presult = socks_state_recv(cf, sx, data, CURLPX_RECV_AUTH, + "SOCKS5 sub-negotiation response"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in reading state */ + return CURLPX_OK; + } + /* ignore the first (VER) byte */ + else if(socksreq[1]) { /* status */ + failf(data, "User was rejected by the SOCKS5 server (%d %d).", + socksreq[0], socksreq[1]); + return CURLPX_USER_REJECTED; + } + + /* Everything is good so far, user was authenticated! */ + sxstate(sx, data, CONNECT_REQ_INIT); + /* FALLTHROUGH */ +CONNECT_REQ_INIT: + case CONNECT_REQ_INIT: + if(socks5_resolve_local) { + enum resolve_t rc = Curl_resolv(data, sx->hostname, sx->remote_port, + TRUE, &dns); + + if(rc == CURLRESOLV_ERROR) + return CURLPX_RESOLVE_HOST; + + if(rc == CURLRESOLV_PENDING) { + sxstate(sx, data, CONNECT_RESOLVING); + return CURLPX_OK; + } + sxstate(sx, data, CONNECT_RESOLVED); + goto CONNECT_RESOLVED; + } + goto CONNECT_RESOLVE_REMOTE; + + case CONNECT_RESOLVING: + /* check if we have the name resolved by now */ + dns = Curl_fetch_addr(data, sx->hostname, sx->remote_port); + + if(dns) { +#ifdef CURLRES_ASYNCH + data->state.async.dns = dns; + data->state.async.done = TRUE; +#endif + infof(data, "SOCKS5: hostname '%s' found", sx->hostname); + } + + if(!dns) { + result = Curl_resolv_check(data, &dns); + if(!dns) { + if(result) + return CURLPX_RESOLVE_HOST; + return CURLPX_OK; + } + } + /* FALLTHROUGH */ +CONNECT_RESOLVED: + case CONNECT_RESOLVED: { + char dest[MAX_IPADR_LEN] = "unknown"; /* printable address */ + struct Curl_addrinfo *hp = NULL; + if(dns) + hp = dns->addr; + if(!hp) { + failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.", + sx->hostname); + return CURLPX_RESOLVE_HOST; + } + + Curl_printable_address(hp, dest, sizeof(dest)); + + len = 0; + socksreq[len++] = 5; /* version (SOCKS5) */ + socksreq[len++] = 1; /* connect */ + socksreq[len++] = 0; /* must be zero */ + if(hp->ai_family == AF_INET) { + int i; + struct sockaddr_in *saddr_in; + socksreq[len++] = 1; /* ATYP: IPv4 = 1 */ + + saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr; + for(i = 0; i < 4; i++) { + socksreq[len++] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[i]; + } + + infof(data, "SOCKS5 connect to %s:%d (locally resolved)", dest, + sx->remote_port); + } +#ifdef ENABLE_IPV6 + else if(hp->ai_family == AF_INET6) { + int i; + struct sockaddr_in6 *saddr_in6; + socksreq[len++] = 4; /* ATYP: IPv6 = 4 */ + + saddr_in6 = (struct sockaddr_in6 *)(void *)hp->ai_addr; + for(i = 0; i < 16; i++) { + socksreq[len++] = + ((unsigned char *)&saddr_in6->sin6_addr.s6_addr)[i]; + } + + infof(data, "SOCKS5 connect to [%s]:%d (locally resolved)", dest, + sx->remote_port); + } +#endif + else { + hp = NULL; /* fail! */ + failf(data, "SOCKS5 connection to %s not supported", dest); + } + + Curl_resolv_unlock(data, dns); /* not used anymore from now on */ + goto CONNECT_REQ_SEND; + } +CONNECT_RESOLVE_REMOTE: + case CONNECT_RESOLVE_REMOTE: + /* Authentication is complete, now specify destination to the proxy */ + len = 0; + socksreq[len++] = 5; /* version (SOCKS5) */ + socksreq[len++] = 1; /* connect */ + socksreq[len++] = 0; /* must be zero */ + + if(!socks5_resolve_local) { + /* ATYP: domain name = 3, + IPv6 == 4, + IPv4 == 1 */ + unsigned char ip4[4]; +#ifdef ENABLE_IPV6 + if(conn->bits.ipv6_ip) { + char ip6[16]; + if(1 != Curl_inet_pton(AF_INET6, sx->hostname, ip6)) + return CURLPX_BAD_ADDRESS_TYPE; + socksreq[len++] = 4; + memcpy(&socksreq[len], ip6, sizeof(ip6)); + len += sizeof(ip6); + } + else +#endif + if(1 == Curl_inet_pton(AF_INET, sx->hostname, ip4)) { + socksreq[len++] = 1; + memcpy(&socksreq[len], ip4, sizeof(ip4)); + len += sizeof(ip4); + } + else { + socksreq[len++] = 3; + socksreq[len++] = (char) hostname_len; /* one byte address length */ + memcpy(&socksreq[len], sx->hostname, hostname_len); /* w/o NULL */ + len += hostname_len; + } + infof(data, "SOCKS5 connect to %s:%d (remotely resolved)", + sx->hostname, sx->remote_port); + } + /* FALLTHROUGH */ + +CONNECT_REQ_SEND: + case CONNECT_REQ_SEND: + /* PORT MSB */ + socksreq[len++] = (unsigned char)((sx->remote_port >> 8) & 0xff); + /* PORT LSB */ + socksreq[len++] = (unsigned char)(sx->remote_port & 0xff); + +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + if(conn->socks5_gssapi_enctype) { + failf(data, "SOCKS5 GSS-API protection not yet implemented."); + return CURLPX_GSSAPI_PROTECTION; + } +#endif + sx->outp = socksreq; + sx->outstanding = len; + sxstate(sx, data, CONNECT_REQ_SENDING); + /* FALLTHROUGH */ + case CONNECT_REQ_SENDING: + presult = socks_state_send(cf, sx, data, CURLPX_SEND_REQUEST, + "SOCKS5 connect request"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in send state */ + return CURLPX_OK; + } +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + if(conn->socks5_gssapi_enctype) { + failf(data, "SOCKS5 GSS-API protection not yet implemented."); + return CURLPX_GSSAPI_PROTECTION; + } +#endif + sx->outstanding = 10; /* minimum packet size is 10 */ + sx->outp = socksreq; + sxstate(sx, data, CONNECT_REQ_READ); + /* FALLTHROUGH */ + case CONNECT_REQ_READ: + presult = socks_state_recv(cf, sx, data, CURLPX_RECV_REQACK, + "SOCKS5 connect request ack"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in reading state */ + return CURLPX_OK; + } + else if(socksreq[0] != 5) { /* version */ + failf(data, + "SOCKS5 reply has wrong version, version should be 5."); + return CURLPX_BAD_VERSION; + } + else if(socksreq[1]) { /* Anything besides 0 is an error */ + CURLproxycode rc = CURLPX_REPLY_UNASSIGNED; + int code = socksreq[1]; + failf(data, "Can't complete SOCKS5 connection to %s. (%d)", + sx->hostname, (unsigned char)socksreq[1]); + if(code < 9) { + /* RFC 1928 section 6 lists: */ + static const CURLproxycode lookup[] = { + CURLPX_OK, + CURLPX_REPLY_GENERAL_SERVER_FAILURE, + CURLPX_REPLY_NOT_ALLOWED, + CURLPX_REPLY_NETWORK_UNREACHABLE, + CURLPX_REPLY_HOST_UNREACHABLE, + CURLPX_REPLY_CONNECTION_REFUSED, + CURLPX_REPLY_TTL_EXPIRED, + CURLPX_REPLY_COMMAND_NOT_SUPPORTED, + CURLPX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED, + }; + rc = lookup[code]; + } + return rc; + } + + /* Fix: in general, returned BND.ADDR is variable length parameter by RFC + 1928, so the reply packet should be read until the end to avoid errors + at subsequent protocol level. + + +----+-----+-------+------+----------+----------+ + |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | + +----+-----+-------+------+----------+----------+ + | 1 | 1 | X'00' | 1 | Variable | 2 | + +----+-----+-------+------+----------+----------+ + + ATYP: + o IP v4 address: X'01', BND.ADDR = 4 byte + o domain name: X'03', BND.ADDR = [ 1 byte length, string ] + o IP v6 address: X'04', BND.ADDR = 16 byte + */ + + /* Calculate real packet size */ + if(socksreq[3] == 3) { + /* domain name */ + int addrlen = (int) socksreq[4]; + len = 5 + addrlen + 2; + } + else if(socksreq[3] == 4) { + /* IPv6 */ + len = 4 + 16 + 2; + } + else if(socksreq[3] == 1) { + len = 4 + 4 + 2; + } + else { + failf(data, "SOCKS5 reply has wrong address type."); + return CURLPX_BAD_ADDRESS_TYPE; + } + + /* At this point we already read first 10 bytes */ +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + if(!conn->socks5_gssapi_enctype) { + /* decrypt_gssapi_blockread already read the whole packet */ +#endif + if(len > 10) { + sx->outstanding = len - 10; /* get the rest */ + sx->outp = &socksreq[10]; + sxstate(sx, data, CONNECT_REQ_READ_MORE); + } + else { + sxstate(sx, data, CONNECT_DONE); + break; + } +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + } +#endif + /* FALLTHROUGH */ + case CONNECT_REQ_READ_MORE: + presult = socks_state_recv(cf, sx, data, CURLPX_RECV_ADDRESS, + "SOCKS5 connect request address"); + if(CURLPX_OK != presult) + return presult; + else if(sx->outstanding) { + /* remain in reading state */ + return CURLPX_OK; + } + sxstate(sx, data, CONNECT_DONE); + } + infof(data, "SOCKS5 request granted."); + + return CURLPX_OK; /* Proxy was successful! */ +} diff --git a/benchmarks/pairs/vfc/curl-cve-2026-9080/fixed.c b/benchmarks/pairs/vfc/curl-cve-2026-9080/fixed.c new file mode 100644 index 0000000..2eeae66 --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2026-9080/fixed.c @@ -0,0 +1,44 @@ +/* Provenance: curl/curl mev_forget_socket (fixed). + * repo: curl/curl + * commit: e9a2b0dc72dd3a9aa3a5210e89079a3b719475dc + * parent: f746780a1e548b4b93790b58d70c3b22fde5360d + * commit_url: https://github.com/curl/curl/commit/e9a2b0dc72dd3a9aa3a5210e89079a3b719475dc + * cve: CVE-2026-9080 + * license: curl + * function: mev_forget_socket + * relpath: lib/multi_ev.c + */ + +static CURLMcode mev_forget_socket(struct Curl_multi *multi, + struct Curl_easy *data, + curl_socket_t s, + const char *cause) +{ + struct mev_sh_entry *entry = mev_sh_entry_get(&multi->ev.sh_entries, s); + int rc = 0; + + if(!entry) /* we never knew or already forgot about this socket */ + return CURLM_OK; + + /* We managed this socket before, tell the socket callback to forget it. */ + if(entry->announced && multi->socket_cb) { + NOVERBOSE((void)cause); + CURL_TRC_M(data, "ev %s, call(fd=%" FMT_SOCKET_T ", ev=REMOVE)", cause, s); + mev_in_callback(multi, TRUE); + rc = multi->socket_cb(data, s, CURL_POLL_REMOVE, + multi->socket_userp, entry->user_data); + mev_in_callback(multi, FALSE); + /* curl_easy_pause() is documented as callable from any callback; it + * re-enters mev_assess() which may free this 'entry'. Re-fetch. */ + entry = mev_sh_entry_get(&multi->ev.sh_entries, s); + if(entry) + entry->announced = FALSE; + } + + mev_sh_entry_kill(multi, s); + if(rc == -1) { + multi->dead = TRUE; + return CURLM_ABORTED_BY_CALLBACK; + } + return CURLM_OK; +} diff --git a/benchmarks/pairs/vfc/curl-cve-2026-9080/vuln.c b/benchmarks/pairs/vfc/curl-cve-2026-9080/vuln.c new file mode 100644 index 0000000..1801edd --- /dev/null +++ b/benchmarks/pairs/vfc/curl-cve-2026-9080/vuln.c @@ -0,0 +1,40 @@ +/* Provenance: curl/curl mev_forget_socket (vuln). + * repo: curl/curl + * commit: f746780a1e548b4b93790b58d70c3b22fde5360d + * parent: f746780a1e548b4b93790b58d70c3b22fde5360d + * commit_url: https://github.com/curl/curl/commit/e9a2b0dc72dd3a9aa3a5210e89079a3b719475dc + * cve: CVE-2026-9080 + * license: curl + * function: mev_forget_socket + * relpath: lib/multi_ev.c + */ + +static CURLMcode mev_forget_socket(struct Curl_multi *multi, + struct Curl_easy *data, + curl_socket_t s, + const char *cause) +{ + struct mev_sh_entry *entry = mev_sh_entry_get(&multi->ev.sh_entries, s); + int rc = 0; + + if(!entry) /* we never knew or already forgot about this socket */ + return CURLM_OK; + + /* We managed this socket before, tell the socket callback to forget it. */ + if(entry->announced && multi->socket_cb) { + NOVERBOSE((void)cause); + CURL_TRC_M(data, "ev %s, call(fd=%" FMT_SOCKET_T ", ev=REMOVE)", cause, s); + mev_in_callback(multi, TRUE); + rc = multi->socket_cb(data, s, CURL_POLL_REMOVE, + multi->socket_userp, entry->user_data); + mev_in_callback(multi, FALSE); + entry->announced = FALSE; + } + + mev_sh_entry_kill(multi, s); + if(rc == -1) { + multi->dead = TRUE; + return CURLM_ABORTED_BY_CALLBACK; + } + return CURLM_OK; +} diff --git a/benchmarks/pairs/vfc/firefox-bug-2058173/fixed.c b/benchmarks/pairs/vfc/firefox-bug-2058173/fixed.c new file mode 100644 index 0000000..0256926 --- /dev/null +++ b/benchmarks/pairs/vfc/firefox-bug-2058173/fixed.c @@ -0,0 +1,59 @@ +/* Provenance: mozilla-firefox/firefox mar_read_index (fixed). + * repo: mozilla-firefox/firefox + * commit: e46f28da1cd3a5d46a2680b3d87361e9e8de4ae6 + * parent: eed0931f85474d0db6e2326dfd9718c6bf1cd418 + * commit_url: https://github.com/mozilla-firefox/firefox/commit/e46f28da1cd3a5d46a2680b3d87361e9e8de4ae6 + * cve: BUG-2058173 + * license: MPL-2.0 + * function: mar_read_index + * relpath: modules/libmar/src/mar_read.c + */ + +static int mar_read_index(MarFile* mar) { + char id[MAR_ID_SIZE], *buf, *bufptr, *bufend; + uint32_t offset_to_index, size_of_index; + size_t mar_position = 0; + + /* verify MAR ID */ + if (mar_read_buffer(mar, id, &mar_position, MAR_ID_SIZE) != 0) { + return -1; + } + if (memcmp(id, MAR_ID, MAR_ID_SIZE) != 0) { + return -1; + } + + if (mar_read_buffer(mar, &offset_to_index, &mar_position, sizeof(uint32_t)) != + 0) { + return -1; + } + offset_to_index = ntohl(offset_to_index); + + mar_position = 0; + if (mar_buffer_seek(mar, &mar_position, offset_to_index) != 0) { + return -1; + } + if (mar_read_buffer(mar, &size_of_index, &mar_position, sizeof(uint32_t)) != + 0) { + return -1; + } + size_of_index = ntohl(size_of_index); + + if (size_of_index > mar->data_len) { + return -1; + } + buf = (char*)malloc(size_of_index); + if (!buf) { + return -1; + } + if (mar_read_buffer(mar, buf, &mar_position, size_of_index) != 0) { + free(buf); + return -1; + } + + bufptr = buf; + bufend = buf + size_of_index; + while (bufptr < bufend && mar_consume_index(mar, &bufptr, bufend) == 0); + + free(buf); + return (bufptr == bufend) ? 0 : -1; +} diff --git a/benchmarks/pairs/vfc/firefox-bug-2058173/vuln.c b/benchmarks/pairs/vfc/firefox-bug-2058173/vuln.c new file mode 100644 index 0000000..35d9057 --- /dev/null +++ b/benchmarks/pairs/vfc/firefox-bug-2058173/vuln.c @@ -0,0 +1,56 @@ +/* Provenance: mozilla-firefox/firefox mar_read_index (vuln). + * repo: mozilla-firefox/firefox + * commit: eed0931f85474d0db6e2326dfd9718c6bf1cd418 + * parent: eed0931f85474d0db6e2326dfd9718c6bf1cd418 + * commit_url: https://github.com/mozilla-firefox/firefox/commit/e46f28da1cd3a5d46a2680b3d87361e9e8de4ae6 + * cve: BUG-2058173 + * license: MPL-2.0 + * function: mar_read_index + * relpath: modules/libmar/src/mar_read.c + */ + +static int mar_read_index(MarFile* mar) { + char id[MAR_ID_SIZE], *buf, *bufptr, *bufend; + uint32_t offset_to_index, size_of_index; + size_t mar_position = 0; + + /* verify MAR ID */ + if (mar_read_buffer(mar, id, &mar_position, MAR_ID_SIZE) != 0) { + return -1; + } + if (memcmp(id, MAR_ID, MAR_ID_SIZE) != 0) { + return -1; + } + + if (mar_read_buffer(mar, &offset_to_index, &mar_position, sizeof(uint32_t)) != + 0) { + return -1; + } + offset_to_index = ntohl(offset_to_index); + + mar_position = 0; + if (mar_buffer_seek(mar, &mar_position, offset_to_index) != 0) { + return -1; + } + if (mar_read_buffer(mar, &size_of_index, &mar_position, sizeof(uint32_t)) != + 0) { + return -1; + } + size_of_index = ntohl(size_of_index); + + buf = (char*)malloc(size_of_index); + if (!buf) { + return -1; + } + if (mar_read_buffer(mar, buf, &mar_position, size_of_index) != 0) { + free(buf); + return -1; + } + + bufptr = buf; + bufend = buf + size_of_index; + while (bufptr < bufend && mar_consume_index(mar, &bufptr, bufend) == 0); + + free(buf); + return (bufptr == bufend) ? 0 : -1; +} diff --git a/benchmarks/pairs/vfc/firefox-cve-2020-15667/fixed.c b/benchmarks/pairs/vfc/firefox-cve-2020-15667/fixed.c new file mode 100644 index 0000000..8aa8548 --- /dev/null +++ b/benchmarks/pairs/vfc/firefox-cve-2020-15667/fixed.c @@ -0,0 +1,59 @@ +/* Provenance: Firefox libmar mar_insert_item after CVE-2020-15667. + * repo: mozilla-central + * commit: b79b6cc78248eea7fda10bfb76aa273c19c9fa65 + * parent: 0c0f777161a9499dd149853ff62d356f75d16c2a + * commit_url: https://hg.mozilla.org/mozilla-central/rev/b79b6cc78248eea7fda10bfb76aa273c19c9fa65 + * phabricator: https://phabricator.services.mozilla.com/rMOZILLACENTRALb79b6cc78248eea7fda10bfb76aa273c19c9fa65 + * cve: CVE-2020-15667 + * bug: 1653371 + * license: MPL-2.0 + * function: mar_insert_item + * relpath: modules/libmar/src/mar_read.c + */ +#include +#include +#include + +typedef struct MarItem_ { + struct MarItem_ *next; + uint32_t offset; + uint32_t length; + uint32_t flags; + char name[1]; +} MarItem; + +typedef struct { + MarItem *item_table[256]; +} MarFile; + +static uint32_t mar_hash_name(const char *name) { + (void)name; + return 0; +} + +static int mar_insert_item(MarFile *mar, const char *name, uint32_t namelen, uint32_t offset, uint32_t length, uint32_t flags) { + MarItem *item, *root; + uint32_t hash; + + item = (MarItem *)malloc(sizeof(MarItem) + namelen); + if (!item) { + return -1; + } + item->next = NULL; + item->offset = offset; + item->length = length; + item->flags = flags; + memcpy(item->name, name, namelen + 1); + + hash = mar_hash_name(name); + + root = mar->item_table[hash]; + if (!root) { + mar->item_table[hash] = item; + } else { + /* append item */ + while (root->next) root = root->next; + root->next = item; + } + return 0; +} diff --git a/benchmarks/pairs/vfc/firefox-cve-2020-15667/vuln.c b/benchmarks/pairs/vfc/firefox-cve-2020-15667/vuln.c new file mode 100644 index 0000000..48f7cb9 --- /dev/null +++ b/benchmarks/pairs/vfc/firefox-cve-2020-15667/vuln.c @@ -0,0 +1,60 @@ +/* Provenance: Firefox libmar mar_insert_item before CVE-2020-15667. + * repo: mozilla-central + * commit: 0c0f777161a9499dd149853ff62d356f75d16c2a + * parent: 0c0f777161a9499dd149853ff62d356f75d16c2a + * fix: b79b6cc78248eea7fda10bfb76aa273c19c9fa65 + * commit_url: https://hg.mozilla.org/mozilla-central/rev/b79b6cc78248eea7fda10bfb76aa273c19c9fa65 + * phabricator: https://phabricator.services.mozilla.com/rMOZILLACENTRALb79b6cc78248eea7fda10bfb76aa273c19c9fa65 + * cve: CVE-2020-15667 + * bug: 1653371 + * license: MPL-2.0 + * function: mar_insert_item + * relpath: modules/libmar/src/mar_read.c + */ +#include +#include +#include + +typedef struct MarItem_ { + struct MarItem_ *next; + uint32_t offset; + uint32_t length; + uint32_t flags; + char name[1]; +} MarItem; + +typedef struct { + MarItem *item_table[256]; +} MarFile; + +static uint32_t mar_hash_name(const char *name) { + (void)name; + return 0; +} + +static int mar_insert_item(MarFile *mar, const char *name, int namelen, uint32_t offset, uint32_t length, uint32_t flags) { + MarItem *item, *root; + uint32_t hash; + + item = (MarItem *)malloc(sizeof(MarItem) + namelen); + if (!item) { + return -1; + } + item->next = NULL; + item->offset = offset; + item->length = length; + item->flags = flags; + memcpy(item->name, name, namelen + 1); + + hash = mar_hash_name(name); + + root = mar->item_table[hash]; + if (!root) { + mar->item_table[hash] = item; + } else { + /* append item */ + while (root->next) root = root->next; + root->next = item; + } + return 0; +} diff --git a/benchmarks/pairs/vfc/generate_catalog.py b/benchmarks/pairs/vfc/generate_catalog.py new file mode 100644 index 0000000..9e21445 --- /dev/null +++ b/benchmarks/pairs/vfc/generate_catalog.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 +"""Rebuild catalog.toml and training/manifest.jsonl from recipes.toml + excerpts.""" + +from __future__ import annotations + +import json +import tomllib +from pathlib import Path + +ROOT = Path(__file__).resolve().parent +RECIPES = ROOT / "recipes.toml" +CATALOG = ROOT / "catalog.toml" +TRAINING = ROOT / "training" / "manifest.jsonl" + +LANG_TO_PAIR = {"c": "c_cpp", "cpp": "c_cpp", "perl": "unknown", "javascript": "javascript", "python": "python", "java": "java"} + + +def excerpt_rel(recipe: dict[str, object]) -> tuple[str, str]: + name = str(recipe["name"]) + ext = Path(str(recipe.get("path", "a.c"))).suffix or ".c" + return f"{name}/vuln{ext}", f"{name}/fixed{ext}" + + +def catalog_text(recipes: list[dict[str, object]]) -> str: + lines = [ + "# Real-world VFC slice. Reviewed isolated functions.", + "# Honesty dashboard — not the local 100% CI gate.", + "# Do not add these names to LANGUAGE_MANIFESTS.", + "# Regenerated by generate_catalog.py from recipes.toml.", + "", + ] + for recipe in recipes: + vuln, fixed = excerpt_rel(recipe) + lang = LANG_TO_PAIR.get(str(recipe.get("language", "c")), "c_cpp") + lines += [ + "[[pair]]", + f'name = "{recipe["name"]}"', + 'slice = "vfc"', + f'language = "{lang}"', + f'origin = "{recipe.get("origin", "")}"', + f'license = "{recipe.get("license", "")}"', + f'repo = "{recipe.get("repo", "")}"', + f'cve = "{recipe.get("cve", "")}"', + f'cwe = "{recipe.get("cwe", "")}"', + f'commit = "{recipe.get("commit", "")}"', + f'parent = "{recipe.get("parent", "")}"', + f'commit_url = "{recipe.get("commit_url", "")}"', + f'vuln = "{vuln}"', + f'fixed = "{fixed}"', + f'relpath = "{recipe.get("relpath", recipe.get("path", ""))}"', + "min_recall = 1.0", + 'fix_policy = "silent"', + "", + "[[pair.expected]]", + f'cwe = "{recipe.get("cwe", "")}"', + f'class = "{recipe.get("class", "")}"', + f'path = "{recipe.get("relpath", recipe.get("path", ""))}"', + ] + if recipe.get("rule_id"): + lines.append(f'rule_id = "{recipe["rule_id"]}"') + if recipe.get("sink"): + lines.append(f'sink = "{recipe["sink"]}"') + if recipe.get("evidence"): + evidence = str(recipe["evidence"]).replace('"', '\\"') + lines.append(f'evidence = "{evidence}"') + lines.append("") + return "\n".join(lines) + + +def training_rows(recipes: list[dict[str, object]]) -> list[dict[str, object]]: + rows: list[dict[str, object]] = [] + for recipe in recipes: + vuln, fixed = excerpt_rel(recipe) + base = { + "pair": recipe["name"], + "cve": recipe.get("cve", ""), + "year": int(recipe.get("year", 0) or 0), + "cwe": recipe.get("cwe", ""), + "class": recipe.get("class", ""), + "project": recipe.get("project", recipe.get("origin", "")), + "repo": recipe.get("repo", ""), + "license": recipe.get("license", ""), + "function": recipe.get("function", ""), + "relpath": recipe.get("relpath", recipe.get("path", "")), + "commit_url": recipe.get("commit_url", ""), + } + rows.append({**base, "id": f"{recipe['name']}:vuln", "label": "vuln", "file": vuln, "commit": recipe.get("parent", "")}) + rows.append({**base, "id": f"{recipe['name']}:fixed", "label": "fixed", "file": fixed, "commit": recipe.get("commit", "")}) + return rows + + +def main() -> int: + recipes = list(tomllib.loads(RECIPES.read_text()).get("recipe", [])) + CATALOG.write_text(catalog_text(recipes), encoding="utf-8") + TRAINING.parent.mkdir(parents=True, exist_ok=True) + with TRAINING.open("w", encoding="utf-8") as handle: + for row in training_rows(recipes): + handle.write(json.dumps(row, sort_keys=True) + "\n") + print(f"wrote {CATALOG} ({len(recipes)} pairs)") + print(f"wrote {TRAINING} ({len(recipes) * 2} examples)") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/benchmarks/pairs/vfc/harvest.py b/benchmarks/pairs/vfc/harvest.py new file mode 100644 index 0000000..571b441 --- /dev/null +++ b/benchmarks/pairs/vfc/harvest.py @@ -0,0 +1,204 @@ +#!/usr/bin/env python3 +"""Extract one function from public parent/fix blobs. Maintainer-only; CI stays offline. + +Does not clone mozilla-central, gecko-dev, or Chromium. Advisory-only recipes +(no parent and commit) are rejected. FixFox is not a fetch source. +""" + +from __future__ import annotations + +import argparse +import sys +import tomllib +from pathlib import Path +from typing import Any +from urllib.parse import urlparse +from urllib.request import Request, urlopen + +ALLOWED_HOSTS = { + "raw.githubusercontent.com", + "github.com", + "phabricator.services.mozilla.com", + "hg.mozilla.org", + "hg-edge.mozilla.org", +} +BLOCKED_TOKENS = ("fixfox", "zenodo.org/record") + + +class RecipeError(ValueError): + """Invalid harvest recipe.""" + + +def extract_function(source: str, function_name: str) -> str: + """Copy the named function through balanced braces.""" + needle = function_name + idx = 0 + while True: + found = source.find(needle, idx) + if found < 0: + raise RecipeError(f"function not found: {function_name}") + before = source[found - 1] if found else " " + after_name = source[found + len(needle) : found + len(needle) + 1] + if before.isalnum() or before == "_": + idx = found + len(needle) + continue + rest = source[found + len(needle) :].lstrip() + if rest.startswith("(") or rest.startswith("<") or rest.startswith("{") or after_name in "(<{": + brace = source.find("{", found) + semi = source.find(";", found) + if brace >= 0 and (semi < 0 or brace < semi): + break + idx = found + len(needle) + line_start = source.rfind("\n", 0, found) + 1 + prev_nl = source.rfind("\n", 0, line_start - 1) + prev_line = source[prev_nl + 1 : line_start] + start = line_start + stripped_prev = prev_line.strip() + if ( + stripped_prev + and not stripped_prev.startswith(("/", "*", "#", "//")) + and "{" not in prev_line + and ";" not in prev_line + and not stripped_prev.startswith(("sub ", "def ", "class ")) + ): + start = prev_nl + 1 + brace = source.find("{", found) + if brace < 0: + raise RecipeError(f"no body for function: {function_name}") + depth = 0 + for pos, char in enumerate(source[brace:], brace): + if char == "{": + depth += 1 + elif char == "}": + depth -= 1 + if depth == 0: + return source[start : pos + 1].strip() + "\n" + raise RecipeError(f"unbalanced braces for function: {function_name}") + + +def provenance_header(recipe: dict[str, Any], *, side: str, sha: str) -> str: + lines = [ + f"Provenance: {recipe.get('repo', '')} {recipe.get('function', '')} ({side}).", + f"repo: {recipe.get('repo', '')}", + f"commit: {sha}", + f"parent: {recipe.get('parent', '')}", + f"commit_url: {recipe.get('commit_url', '')}", + f"cve: {recipe.get('cve', '')}", + f"license: {recipe.get('license', '')}", + f"function: {recipe.get('function', '')}", + f"relpath: {recipe.get('relpath', recipe.get('path', ''))}", + ] + prefix = "//" if str(recipe.get("language", "c")).startswith("c") and str(recipe.get("path", "")).endswith((".cc", ".cpp", ".java", ".js")) else "/*" + if prefix == "//": + return "\n".join(f"// {line}" for line in lines) + "\n" + return "/* " + "\n * ".join(lines) + "\n */\n" + + +def validate_recipe(recipe: dict[str, Any]) -> None: + name = str(recipe.get("name", "")) + if any(token in str(recipe).lower() for token in BLOCKED_TOKENS): + raise RecipeError(f"{name}: embargoed or blocked dataset") + if not recipe.get("parent") or not recipe.get("commit"): + raise RecipeError(f"{name}: advisory-only recipe rejected; parent and commit required") + if not recipe.get("path") or not recipe.get("function"): + raise RecipeError(f"{name}: path and function required") + if not recipe.get("license"): + raise RecipeError(f"{name}: license required") + + +def github_raw_url(repo: str, sha: str, path: str) -> str: + return f"https://raw.githubusercontent.com/{repo}/{sha}/{path}" + + +def excerpt_paths(recipe: dict[str, Any], root: Path) -> tuple[Path, Path]: + name = str(recipe["name"]) + ext = Path(str(recipe.get("path", "a.c"))).suffix or ".c" + folder = root / name + return folder / f"vuln{ext}", folder / f"fixed{ext}" + + +def write_excerpt(path: Path, recipe: dict[str, Any], *, side: str, sha: str, body: str) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + header = provenance_header(recipe, side=side, sha=sha) + path.write_text(header + "\n" + body, encoding="utf-8") + + +def harvest_recipe(recipe: dict[str, Any], root: Path) -> tuple[Path, Path]: + validate_recipe(recipe) + if str(recipe.get("host", "github")) != "github": + raise RecipeError(f"{recipe.get('name')}: live fetch currently implemented for host=github only") + parent_src = fetch_url(github_raw_url(str(recipe["repo"]), str(recipe["parent"]), str(recipe["path"]))) + fix_src = fetch_url(github_raw_url(str(recipe["repo"]), str(recipe["commit"]), str(recipe["path"]))) + function = str(recipe["function"]) + parent_fn = extract_function(parent_src, function) + fix_fn = extract_function(fix_src, function) + vuln_path, fixed_path = excerpt_paths(recipe, root) + write_excerpt(vuln_path, recipe, side="vuln", sha=str(recipe["parent"]), body=parent_fn) + write_excerpt(fixed_path, recipe, side="fixed", sha=str(recipe["commit"]), body=fix_fn) + return vuln_path, fixed_path + + +def fetch_url(url: str, timeout: int = 60) -> str: + host = urlparse(url).hostname or "" + if host not in ALLOWED_HOSTS: + raise RecipeError(f"host not allowed: {host}") + request = Request(url, headers={"User-Agent": "OpenUltraSAST-vfc-harvest"}) + with urlopen(request, timeout=timeout) as response: # noqa: S310 — host allowlisted + return response.read().decode("utf-8", "replace") + + +def load_recipes(path: Path) -> tuple[dict[str, Any], ...]: + payload = tomllib.loads(path.read_text()) + return tuple(dict(item) for item in payload.get("recipe", [])) + + +def main(argv: list[str] | None = None) -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--recipes", type=Path, default=Path(__file__).with_name("recipes.toml")) + parser.add_argument("--name", help="recipe name to harvest (omit with --all)") + parser.add_argument("--all", action="store_true", help="process every recipe") + parser.add_argument("--fetch", action="store_true", help="HTTP-fetch and write excerpts; default is dry-run validate") + parser.add_argument("--force", action="store_true", help="overwrite existing excerpts") + parser.add_argument("--out", type=Path, default=Path(__file__).resolve().parent, help="excerpt root") + args = parser.parse_args(argv) + loaded = load_recipes(args.recipes) + recipes = {str(item["name"]): item for item in loaded} + selected: list[dict[str, Any]] + if args.all: + selected = list(loaded) + elif args.name: + if args.name not in recipes: + print(f"unknown recipe: {args.name}", file=sys.stderr) + return 2 + selected = [recipes[args.name]] + else: + print("pass --name RECIPE or --all", file=sys.stderr) + return 2 + failures = 0 + for recipe in selected: + name = str(recipe["name"]) + try: + validate_recipe(recipe) + except RecipeError as exc: + print(str(exc), file=sys.stderr) + failures += 1 + continue + if not args.fetch: + print(f"ok {name} parent={recipe['parent']} commit={recipe['commit']}") + continue + vuln_path, fixed_path = excerpt_paths(recipe, args.out) + if vuln_path.is_file() and fixed_path.is_file() and not args.force: + print(f"skip {name} (exists)") + continue + try: + harvest_recipe(recipe, args.out) + except RecipeError as exc: + print(f"{name}: {exc}", file=sys.stderr) + failures += 1 + continue + print(f"wrote {name} -> {vuln_path.parent}") + return 1 if failures else 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/benchmarks/pairs/vfc/openssl-cve-2014-0160/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2014-0160/fixed.c new file mode 100644 index 0000000..bcbb5a3 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2014-0160/fixed.c @@ -0,0 +1,109 @@ +/* Provenance: OpenSSL tls1_process_heartbeat after Heartbleed bounds check. + * repo: openssl/openssl + * commit: 96db9023b881d7cd9f379b0c154650d6c108e9a3 + * parent: 0d7717fc9c83dafab8153cbd5e2180e6e04cc802 + * commit_url: https://github.com/openssl/openssl/commit/96db9023b881d7cd9f379b0c154650d6c108e9a3 + * cve: CVE-2014-0160 + * license: OpenSSL License + * function: tls1_process_heartbeat + * relpath: ssl/t1_lib.c + */ +#include +#include + +typedef struct ssl_st { + struct { + struct { + unsigned char *data; + unsigned int length; + } rrec; + } *s3; + int version; + void (*msg_callback)(int write_p, int version, int content_type, const void *buf, size_t len, void *ssl, void *arg); + void *msg_callback_arg; + unsigned int tlsext_hb_seq; + unsigned int tlsext_hb_pending; +} SSL; + +#define TLS1_RT_HEARTBEAT 24 +#define TLS1_HB_REQUEST 1 +#define TLS1_HB_RESPONSE 2 +#define n2s(c, s) ((s = (((unsigned int)((c)[0])) << 8) | (((unsigned int)((c)[1])))), (c) += 2) +#define s2n(s, c) (((c)[0] = (unsigned char)(((s) >> 8) & 0xff), (c)[1] = (unsigned char)(((s)) & 0xff)), (c) += 2) + +static unsigned char *OPENSSL_malloc(unsigned int n) { return (unsigned char *)malloc(n); } +static void OPENSSL_free(void *p) { free(p); } +static int RAND_pseudo_bytes(unsigned char *buf, unsigned int n) { + (void)buf; + (void)n; + return 1; +} +static int ssl3_write_bytes(SSL *s, int type, unsigned char *buf, unsigned int len) { + (void)s; + (void)type; + (void)buf; + return (int)len; +} + +int tls1_process_heartbeat(SSL *s) { + unsigned char *p = &s->s3->rrec.data[0], *pl; + unsigned short hbtype; + unsigned int payload; + unsigned int padding = 16; /* Use minimum padding */ + + if (s->msg_callback) + s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT, &s->s3->rrec.data[0], s->s3->rrec.length, s, s->msg_callback_arg); + + /* Read type and payload length first */ + if (1 + 2 + 16 > s->s3->rrec.length) + return 0; /* silently discard */ + hbtype = *p++; + n2s(p, payload); + if (1 + 2 + payload + 16 > s->s3->rrec.length) + return 0; /* silently discard per RFC 6520 sec. 4 */ + pl = p; + + if (hbtype == TLS1_HB_REQUEST) { + unsigned char *buffer, *bp; + int r; + + /* Allocate memory for the response, size is 1 bytes + * message type, plus 2 bytes payload length, plus + * payload, plus padding + */ + buffer = OPENSSL_malloc(1 + 2 + payload + padding); + bp = buffer; + + /* Enter response type, length and copy payload */ + *bp++ = TLS1_HB_RESPONSE; + s2n(payload, bp); + memcpy(bp, pl, payload); + bp += payload; + /* Random padding */ + RAND_pseudo_bytes(bp, padding); + + r = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, 3 + payload + padding); + + if (r >= 0 && s->msg_callback) + s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT, buffer, 3 + payload + padding, s, s->msg_callback_arg); + + OPENSSL_free(buffer); + + if (r < 0) + return r; + } else if (hbtype == TLS1_HB_RESPONSE) { + unsigned int seq; + + /* We only send sequence numbers (2 bytes unsigned int), + * and 16 random bytes, so we just try to read the + * sequence number */ + n2s(pl, seq); + + if (payload == 18 && seq == s->tlsext_hb_seq) { + s->tlsext_hb_seq++; + s->tlsext_hb_pending = 0; + } + } + + return 0; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2014-0160/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2014-0160/vuln.c new file mode 100644 index 0000000..176de5e --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2014-0160/vuln.c @@ -0,0 +1,106 @@ +/* Provenance: OpenSSL tls1_process_heartbeat before Heartbleed fix. + * repo: openssl/openssl + * commit: 0d7717fc9c83dafab8153cbd5e2180e6e04cc802 + * parent: 0d7717fc9c83dafab8153cbd5e2180e6e04cc802 + * fix: 96db9023b881d7cd9f379b0c154650d6c108e9a3 + * commit_url: https://github.com/openssl/openssl/commit/96db9023b881d7cd9f379b0c154650d6c108e9a3 + * cve: CVE-2014-0160 + * license: OpenSSL License + * function: tls1_process_heartbeat + * relpath: ssl/t1_lib.c + */ +#include +#include + +typedef struct ssl_st { + struct { + struct { + unsigned char *data; + unsigned int length; + } rrec; + } *s3; + int version; + void (*msg_callback)(int write_p, int version, int content_type, const void *buf, size_t len, void *ssl, void *arg); + void *msg_callback_arg; + unsigned int tlsext_hb_seq; + unsigned int tlsext_hb_pending; +} SSL; + +#define TLS1_RT_HEARTBEAT 24 +#define TLS1_HB_REQUEST 1 +#define TLS1_HB_RESPONSE 2 +#define n2s(c, s) ((s = (((unsigned int)((c)[0])) << 8) | (((unsigned int)((c)[1])))), (c) += 2) +#define s2n(s, c) (((c)[0] = (unsigned char)(((s) >> 8) & 0xff), (c)[1] = (unsigned char)(((s)) & 0xff)), (c) += 2) + +static unsigned char *OPENSSL_malloc(unsigned int n) { return (unsigned char *)malloc(n); } +static void OPENSSL_free(void *p) { free(p); } +static int RAND_pseudo_bytes(unsigned char *buf, unsigned int n) { + (void)buf; + (void)n; + return 1; +} +static int ssl3_write_bytes(SSL *s, int type, unsigned char *buf, unsigned int len) { + (void)s; + (void)type; + (void)buf; + return (int)len; +} + +int tls1_process_heartbeat(SSL *s) { + unsigned char *p = &s->s3->rrec.data[0], *pl; + unsigned short hbtype; + unsigned int payload; + unsigned int padding = 16; /* Use minimum padding */ + + /* Read type and payload length first */ + hbtype = *p++; + n2s(p, payload); + pl = p; + + if (s->msg_callback) + s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT, &s->s3->rrec.data[0], s->s3->rrec.length, s, s->msg_callback_arg); + + if (hbtype == TLS1_HB_REQUEST) { + unsigned char *buffer, *bp; + int r; + + /* Allocate memory for the response, size is 1 bytes + * message type, plus 2 bytes payload length, plus + * payload, plus padding + */ + buffer = OPENSSL_malloc(1 + 2 + payload + padding); + bp = buffer; + + /* Enter response type, length and copy payload */ + *bp++ = TLS1_HB_RESPONSE; + s2n(payload, bp); + memcpy(bp, pl, payload); + bp += payload; + /* Random padding */ + RAND_pseudo_bytes(bp, padding); + + r = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, 3 + payload + padding); + + if (r >= 0 && s->msg_callback) + s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT, buffer, 3 + payload + padding, s, s->msg_callback_arg); + + OPENSSL_free(buffer); + + if (r < 0) + return r; + } else if (hbtype == TLS1_HB_RESPONSE) { + unsigned int seq; + + /* We only send sequence numbers (2 bytes unsigned int), + * and 16 random bytes, so we just try to read the + * sequence number */ + n2s(pl, seq); + + if (payload == 18 && seq == s->tlsext_hb_seq) { + s->tlsext_hb_seq++; + s->tlsext_hb_pending = 0; + } + } + + return 0; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2020-1967-tls1_check_sig_alg/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2020-1967-tls1_check_sig_alg/fixed.c new file mode 100644 index 0000000..fa5202d --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2020-1967-tls1_check_sig_alg/fixed.c @@ -0,0 +1,43 @@ +/* Provenance: openssl/openssl tls1_check_sig_alg (fixed). + * repo: openssl/openssl + * commit: a87f3fe01a5a894aa27ccd6a239155fd129988e4 + * parent: 3656c08ab4b1b892730cb5e808b6f4298b08a2e6 + * commit_url: https://github.com/openssl/openssl/commit/a87f3fe01a5a894aa27ccd6a239155fd129988e4 + * cve: CVE-2020-1967 + * license: OpenSSL License + * function: tls1_check_sig_alg + * relpath: ssl/t1_lib.c + */ + +static int tls1_check_sig_alg(SSL *s, X509 *x, int default_nid) +{ + int sig_nid, use_pc_sigalgs = 0; + size_t i; + const SIGALG_LOOKUP *sigalg; + size_t sigalgslen; + if (default_nid == -1) + return 1; + sig_nid = X509_get_signature_nid(x); + if (default_nid) + return sig_nid == default_nid ? 1 : 0; + + if (SSL_IS_TLS13(s) && s->s3.tmp.peer_cert_sigalgs != NULL) { + /* + * If we're in TLSv1.3 then we only get here if we're checking the + * chain. If the peer has specified peer_cert_sigalgs then we use them + * otherwise we default to normal sigalgs. + */ + sigalgslen = s->s3.tmp.peer_cert_sigalgslen; + use_pc_sigalgs = 1; + } else { + sigalgslen = s->shared_sigalgslen; + } + for (i = 0; i < sigalgslen; i++) { + sigalg = use_pc_sigalgs + ? tls1_lookup_sigalg(s->s3.tmp.peer_cert_sigalgs[i]) + : s->shared_sigalgs[i]; + if (sigalg != NULL && sig_nid == sigalg->sigandhash) + return 1; + } + return 0; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2020-1967-tls1_check_sig_alg/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2020-1967-tls1_check_sig_alg/vuln.c new file mode 100644 index 0000000..9692660 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2020-1967-tls1_check_sig_alg/vuln.c @@ -0,0 +1,43 @@ +/* Provenance: openssl/openssl tls1_check_sig_alg (vuln). + * repo: openssl/openssl + * commit: 3656c08ab4b1b892730cb5e808b6f4298b08a2e6 + * parent: 3656c08ab4b1b892730cb5e808b6f4298b08a2e6 + * commit_url: https://github.com/openssl/openssl/commit/a87f3fe01a5a894aa27ccd6a239155fd129988e4 + * cve: CVE-2020-1967 + * license: OpenSSL License + * function: tls1_check_sig_alg + * relpath: ssl/t1_lib.c + */ + +static int tls1_check_sig_alg(SSL *s, X509 *x, int default_nid) +{ + int sig_nid, use_pc_sigalgs = 0; + size_t i; + const SIGALG_LOOKUP *sigalg; + size_t sigalgslen; + if (default_nid == -1) + return 1; + sig_nid = X509_get_signature_nid(x); + if (default_nid) + return sig_nid == default_nid ? 1 : 0; + + if (SSL_IS_TLS13(s) && s->s3.tmp.peer_cert_sigalgs != NULL) { + /* + * If we're in TLSv1.3 then we only get here if we're checking the + * chain. If the peer has specified peer_cert_sigalgs then we use them + * otherwise we default to normal sigalgs. + */ + sigalgslen = s->s3.tmp.peer_cert_sigalgslen; + use_pc_sigalgs = 1; + } else { + sigalgslen = s->shared_sigalgslen; + } + for (i = 0; i < sigalgslen; i++) { + sigalg = use_pc_sigalgs + ? tls1_lookup_sigalg(s->s3.tmp.peer_cert_sigalgs[i]) + : s->shared_sigalgs[i]; + if (sig_nid == sigalg->sigandhash) + return 1; + } + return 0; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2020-1967/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2020-1967/fixed.c new file mode 100644 index 0000000..fa5202d --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2020-1967/fixed.c @@ -0,0 +1,43 @@ +/* Provenance: openssl/openssl tls1_check_sig_alg (fixed). + * repo: openssl/openssl + * commit: a87f3fe01a5a894aa27ccd6a239155fd129988e4 + * parent: 3656c08ab4b1b892730cb5e808b6f4298b08a2e6 + * commit_url: https://github.com/openssl/openssl/commit/a87f3fe01a5a894aa27ccd6a239155fd129988e4 + * cve: CVE-2020-1967 + * license: OpenSSL License + * function: tls1_check_sig_alg + * relpath: ssl/t1_lib.c + */ + +static int tls1_check_sig_alg(SSL *s, X509 *x, int default_nid) +{ + int sig_nid, use_pc_sigalgs = 0; + size_t i; + const SIGALG_LOOKUP *sigalg; + size_t sigalgslen; + if (default_nid == -1) + return 1; + sig_nid = X509_get_signature_nid(x); + if (default_nid) + return sig_nid == default_nid ? 1 : 0; + + if (SSL_IS_TLS13(s) && s->s3.tmp.peer_cert_sigalgs != NULL) { + /* + * If we're in TLSv1.3 then we only get here if we're checking the + * chain. If the peer has specified peer_cert_sigalgs then we use them + * otherwise we default to normal sigalgs. + */ + sigalgslen = s->s3.tmp.peer_cert_sigalgslen; + use_pc_sigalgs = 1; + } else { + sigalgslen = s->shared_sigalgslen; + } + for (i = 0; i < sigalgslen; i++) { + sigalg = use_pc_sigalgs + ? tls1_lookup_sigalg(s->s3.tmp.peer_cert_sigalgs[i]) + : s->shared_sigalgs[i]; + if (sigalg != NULL && sig_nid == sigalg->sigandhash) + return 1; + } + return 0; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2020-1967/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2020-1967/vuln.c new file mode 100644 index 0000000..9692660 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2020-1967/vuln.c @@ -0,0 +1,43 @@ +/* Provenance: openssl/openssl tls1_check_sig_alg (vuln). + * repo: openssl/openssl + * commit: 3656c08ab4b1b892730cb5e808b6f4298b08a2e6 + * parent: 3656c08ab4b1b892730cb5e808b6f4298b08a2e6 + * commit_url: https://github.com/openssl/openssl/commit/a87f3fe01a5a894aa27ccd6a239155fd129988e4 + * cve: CVE-2020-1967 + * license: OpenSSL License + * function: tls1_check_sig_alg + * relpath: ssl/t1_lib.c + */ + +static int tls1_check_sig_alg(SSL *s, X509 *x, int default_nid) +{ + int sig_nid, use_pc_sigalgs = 0; + size_t i; + const SIGALG_LOOKUP *sigalg; + size_t sigalgslen; + if (default_nid == -1) + return 1; + sig_nid = X509_get_signature_nid(x); + if (default_nid) + return sig_nid == default_nid ? 1 : 0; + + if (SSL_IS_TLS13(s) && s->s3.tmp.peer_cert_sigalgs != NULL) { + /* + * If we're in TLSv1.3 then we only get here if we're checking the + * chain. If the peer has specified peer_cert_sigalgs then we use them + * otherwise we default to normal sigalgs. + */ + sigalgslen = s->s3.tmp.peer_cert_sigalgslen; + use_pc_sigalgs = 1; + } else { + sigalgslen = s->shared_sigalgslen; + } + for (i = 0; i < sigalgslen; i++) { + sigalg = use_pc_sigalgs + ? tls1_lookup_sigalg(s->s3.tmp.peer_cert_sigalgs[i]) + : s->shared_sigalgs[i]; + if (sig_nid == sigalg->sigandhash) + return 1; + } + return 0; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2020-1971-general_name_cmp/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2020-1971-general_name_cmp/fixed.c new file mode 100644 index 0000000..50871af --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2020-1971-general_name_cmp/fixed.c @@ -0,0 +1,50 @@ +/* Provenance: openssl/openssl GENERAL_NAME_cmp (fixed). + * repo: openssl/openssl + * commit: f960d81215ebf3f65e03d4d5d857fb9b666d6920 + * parent: aa0ad2011d3e7ad8a611da274ef7d9c7706e289b + * commit_url: https://github.com/openssl/openssl/commit/f960d81215ebf3f65e03d4d5d857fb9b666d6920 + * cve: CVE-2020-1971 + * license: OpenSSL License + * function: GENERAL_NAME_cmp + * relpath: crypto/x509v3/v3_genn.c + */ + +int GENERAL_NAME_cmp(GENERAL_NAME *a, GENERAL_NAME *b) +{ + int result = -1; + + if (!a || !b || a->type != b->type) + return -1; + switch (a->type) { + case GEN_X400: + result = ASN1_TYPE_cmp(a->d.x400Address, b->d.x400Address); + break; + + case GEN_EDIPARTY: + result = edipartyname_cmp(a->d.ediPartyName, b->d.ediPartyName); + break; + + case GEN_OTHERNAME: + result = OTHERNAME_cmp(a->d.otherName, b->d.otherName); + break; + + case GEN_EMAIL: + case GEN_DNS: + case GEN_URI: + result = ASN1_STRING_cmp(a->d.ia5, b->d.ia5); + break; + + case GEN_DIRNAME: + result = X509_NAME_cmp(a->d.dirn, b->d.dirn); + break; + + case GEN_IPADD: + result = ASN1_OCTET_STRING_cmp(a->d.ip, b->d.ip); + break; + + case GEN_RID: + result = OBJ_cmp(a->d.rid, b->d.rid); + break; + } + return result; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2020-1971-general_name_cmp/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2020-1971-general_name_cmp/vuln.c new file mode 100644 index 0000000..9abc56c --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2020-1971-general_name_cmp/vuln.c @@ -0,0 +1,47 @@ +/* Provenance: openssl/openssl GENERAL_NAME_cmp (vuln). + * repo: openssl/openssl + * commit: aa0ad2011d3e7ad8a611da274ef7d9c7706e289b + * parent: aa0ad2011d3e7ad8a611da274ef7d9c7706e289b + * commit_url: https://github.com/openssl/openssl/commit/f960d81215ebf3f65e03d4d5d857fb9b666d6920 + * cve: CVE-2020-1971 + * license: OpenSSL License + * function: GENERAL_NAME_cmp + * relpath: crypto/x509v3/v3_genn.c + */ + +int GENERAL_NAME_cmp(GENERAL_NAME *a, GENERAL_NAME *b) +{ + int result = -1; + + if (!a || !b || a->type != b->type) + return -1; + switch (a->type) { + case GEN_X400: + case GEN_EDIPARTY: + result = ASN1_TYPE_cmp(a->d.other, b->d.other); + break; + + case GEN_OTHERNAME: + result = OTHERNAME_cmp(a->d.otherName, b->d.otherName); + break; + + case GEN_EMAIL: + case GEN_DNS: + case GEN_URI: + result = ASN1_STRING_cmp(a->d.ia5, b->d.ia5); + break; + + case GEN_DIRNAME: + result = X509_NAME_cmp(a->d.dirn, b->d.dirn); + break; + + case GEN_IPADD: + result = ASN1_OCTET_STRING_cmp(a->d.ip, b->d.ip); + break; + + case GEN_RID: + result = OBJ_cmp(a->d.rid, b->d.rid); + break; + } + return result; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2020-1971/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2020-1971/fixed.c new file mode 100644 index 0000000..eb96bbc --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2020-1971/fixed.c @@ -0,0 +1,50 @@ +/* Provenance: openssl/openssl GENERAL_NAME_cmp (fixed). + * repo: openssl/openssl + * commit: b33c48b75aaf33c93aeda42d7138616b9e6a64cb + * parent: 198b11683568452282bd48828fcf60d4835bf327 + * commit_url: https://github.com/openssl/openssl/commit/b33c48b75aaf33c93aeda42d7138616b9e6a64cb + * cve: CVE-2020-1971 + * license: OpenSSL License + * function: GENERAL_NAME_cmp + * relpath: crypto/x509/v3_genn.c + */ + +int GENERAL_NAME_cmp(GENERAL_NAME *a, GENERAL_NAME *b) +{ + int result = -1; + + if (!a || !b || a->type != b->type) + return -1; + switch (a->type) { + case GEN_X400: + result = ASN1_TYPE_cmp(a->d.x400Address, b->d.x400Address); + break; + + case GEN_EDIPARTY: + result = edipartyname_cmp(a->d.ediPartyName, b->d.ediPartyName); + break; + + case GEN_OTHERNAME: + result = OTHERNAME_cmp(a->d.otherName, b->d.otherName); + break; + + case GEN_EMAIL: + case GEN_DNS: + case GEN_URI: + result = ASN1_STRING_cmp(a->d.ia5, b->d.ia5); + break; + + case GEN_DIRNAME: + result = X509_NAME_cmp(a->d.dirn, b->d.dirn); + break; + + case GEN_IPADD: + result = ASN1_OCTET_STRING_cmp(a->d.ip, b->d.ip); + break; + + case GEN_RID: + result = OBJ_cmp(a->d.rid, b->d.rid); + break; + } + return result; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2020-1971/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2020-1971/vuln.c new file mode 100644 index 0000000..b15e823 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2020-1971/vuln.c @@ -0,0 +1,47 @@ +/* Provenance: openssl/openssl GENERAL_NAME_cmp (vuln). + * repo: openssl/openssl + * commit: 198b11683568452282bd48828fcf60d4835bf327 + * parent: 198b11683568452282bd48828fcf60d4835bf327 + * commit_url: https://github.com/openssl/openssl/commit/b33c48b75aaf33c93aeda42d7138616b9e6a64cb + * cve: CVE-2020-1971 + * license: OpenSSL License + * function: GENERAL_NAME_cmp + * relpath: crypto/x509/v3_genn.c + */ + +int GENERAL_NAME_cmp(GENERAL_NAME *a, GENERAL_NAME *b) +{ + int result = -1; + + if (!a || !b || a->type != b->type) + return -1; + switch (a->type) { + case GEN_X400: + case GEN_EDIPARTY: + result = ASN1_TYPE_cmp(a->d.other, b->d.other); + break; + + case GEN_OTHERNAME: + result = OTHERNAME_cmp(a->d.otherName, b->d.otherName); + break; + + case GEN_EMAIL: + case GEN_DNS: + case GEN_URI: + result = ASN1_STRING_cmp(a->d.ia5, b->d.ia5); + break; + + case GEN_DIRNAME: + result = X509_NAME_cmp(a->d.dirn, b->d.dirn); + break; + + case GEN_IPADD: + result = ASN1_OCTET_STRING_cmp(a->d.ip, b->d.ip); + break; + + case GEN_RID: + result = OBJ_cmp(a->d.rid, b->d.rid); + break; + } + return result; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2020-25659/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2020-25659/fixed.c new file mode 100644 index 0000000..78ff5b4 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2020-25659/fixed.c @@ -0,0 +1,240 @@ +/* Provenance: openssl/openssl rsa_ossl_private_decrypt (fixed). + * repo: openssl/openssl + * commit: 7fc67e0a33102aa47bbaa56533eeecb98c0450f7 + * parent: 1ca61aa56090356bbdbb16cf48916fbd9886c78d + * commit_url: https://github.com/openssl/openssl/commit/7fc67e0a33102aa47bbaa56533eeecb98c0450f7 + * cve: CVE-2020-25659 + * license: OpenSSL License + * function: rsa_ossl_private_decrypt + * relpath: crypto/rsa/rsa_ossl.c + */ + +static int rsa_ossl_private_decrypt(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding) +{ + BIGNUM *f, *ret; + int j, num = 0, r = -1; + unsigned char *buf = NULL; + unsigned char d_hash[SHA256_DIGEST_LENGTH] = {0}; + HMAC_CTX *hmac = NULL; + unsigned int md_len = SHA256_DIGEST_LENGTH; + unsigned char kdk[SHA256_DIGEST_LENGTH] = {0}; + BN_CTX *ctx = NULL; + int local_blinding = 0; + EVP_MD *md = NULL; + /* + * Used only if the blinding structure is shared. A non-NULL unblind + * instructs rsa_blinding_convert() and rsa_blinding_invert() to store + * the unblinding factor outside the blinding structure. + */ + BIGNUM *unblind = NULL; + BN_BLINDING *blinding = NULL; + + if ((ctx = BN_CTX_new_ex(rsa->libctx)) == NULL) + goto err; + BN_CTX_start(ctx); + f = BN_CTX_get(ctx); + ret = BN_CTX_get(ctx); + if (ret == NULL) { + ERR_raise(ERR_LIB_RSA, ERR_R_BN_LIB); + goto err; + } + num = BN_num_bytes(rsa->n); + buf = OPENSSL_malloc(num); + if (buf == NULL) + goto err; + + /* + * This check was for equality but PGP does evil things and chops off the + * top '0' bytes + */ + if (flen > num) { + ERR_raise(ERR_LIB_RSA, RSA_R_DATA_GREATER_THAN_MOD_LEN); + goto err; + } + + if (flen < 1) { + ERR_raise(ERR_LIB_RSA, RSA_R_DATA_TOO_SMALL); + goto err; + } + + /* make data into a big number */ + if (BN_bin2bn(from, (int)flen, f) == NULL) + goto err; + + if (BN_ucmp(f, rsa->n) >= 0) { + ERR_raise(ERR_LIB_RSA, RSA_R_DATA_TOO_LARGE_FOR_MODULUS); + goto err; + } + + if (!(rsa->flags & RSA_FLAG_NO_BLINDING)) { + blinding = rsa_get_blinding(rsa, &local_blinding, ctx); + if (blinding == NULL) { + ERR_raise(ERR_LIB_RSA, ERR_R_INTERNAL_ERROR); + goto err; + } + } + + if (blinding != NULL) { + if (!local_blinding && ((unblind = BN_CTX_get(ctx)) == NULL)) { + ERR_raise(ERR_LIB_RSA, ERR_R_BN_LIB); + goto err; + } + if (!rsa_blinding_convert(blinding, f, unblind, ctx)) + goto err; + } + + /* do the decrypt */ + if ((rsa->flags & RSA_FLAG_EXT_PKEY) || + (rsa->version == RSA_ASN1_VERSION_MULTI) || + ((rsa->p != NULL) && + (rsa->q != NULL) && + (rsa->dmp1 != NULL) && (rsa->dmq1 != NULL) && (rsa->iqmp != NULL))) { + if (!rsa->meth->rsa_mod_exp(ret, f, rsa, ctx)) + goto err; + } else { + BIGNUM *d = BN_new(); + if (d == NULL) { + ERR_raise(ERR_LIB_RSA, ERR_R_BN_LIB); + goto err; + } + if (rsa->d == NULL) { + ERR_raise(ERR_LIB_RSA, RSA_R_MISSING_PRIVATE_KEY); + BN_free(d); + goto err; + } + BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME); + + if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) + if (!BN_MONT_CTX_set_locked(&rsa->_method_mod_n, rsa->lock, + rsa->n, ctx)) { + BN_free(d); + goto err; + } + if (!rsa->meth->bn_mod_exp(ret, f, d, rsa->n, ctx, + rsa->_method_mod_n)) { + BN_free(d); + goto err; + } + /* We MUST free d before any further use of rsa->d */ + BN_free(d); + } + + if (blinding) + if (!rsa_blinding_invert(blinding, ret, unblind, ctx)) + goto err; + + /* + * derive the Key Derivation Key from private exponent and public + * ciphertext + */ + if (!(rsa->flags & RSA_FLAG_EXT_PKEY)) { + /* + * because we use d as a handle to rsa->d we need to keep it local and + * free before any further use of rsa->d + */ + BIGNUM *d = BN_new(); + if (d == NULL) { + ERR_raise(ERR_LIB_RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + if (rsa->d == NULL) { + ERR_raise(ERR_LIB_RSA, RSA_R_MISSING_PRIVATE_KEY); + BN_free(d); + goto err; + } + BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME); + if (BN_bn2binpad(d, buf, num) < 0) { + ERR_raise(ERR_LIB_RSA, ERR_R_INTERNAL_ERROR); + BN_free(d); + goto err; + } + BN_free(d); + + /* + * we use hardcoded hash so that migrating between versions that use + * different hash doesn't provide a Bleichenbacher oracle: + * if the attacker can see that different versions return different + * messages for the same ciphertext, they'll know that the message is + * syntethically generated, which means that the padding check failed + */ + md = EVP_MD_fetch(rsa->libctx, "sha256", NULL); + if (md == NULL) { + ERR_raise(ERR_LIB_RSA, ERR_R_INTERNAL_ERROR); + goto err; + } + + if (EVP_Digest(buf, num, d_hash, NULL, md, NULL) <= 0) { + ERR_raise(ERR_LIB_RSA, ERR_R_INTERNAL_ERROR); + goto err; + } + + hmac = HMAC_CTX_new(); + if (hmac == NULL) { + ERR_raise(ERR_LIB_RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (HMAC_Init_ex(hmac, d_hash, sizeof(d_hash), md, NULL) <= 0) { + ERR_raise(ERR_LIB_RSA, ERR_R_INTERNAL_ERROR); + goto err; + } + + if (flen < num) { + memset(buf, 0, num - flen); + if (HMAC_Update(hmac, buf, num - flen) <= 0) { + ERR_raise(ERR_LIB_RSA, ERR_R_INTERNAL_ERROR); + goto err; + } + } + if (HMAC_Update(hmac, from, flen) <= 0) { + ERR_raise(ERR_LIB_RSA, ERR_R_INTERNAL_ERROR); + goto err; + } + + md_len = SHA256_DIGEST_LENGTH; + if (HMAC_Final(hmac, kdk, &md_len) <= 0) { + ERR_raise(ERR_LIB_RSA, ERR_R_INTERNAL_ERROR); + goto err; + } + } + + j = BN_bn2binpad(ret, buf, num); + if (j < 0) + goto err; + + switch (padding) { + case RSA_PKCS1_PADDING: + if (rsa->flags & RSA_FLAG_EXT_PKEY) + r = RSA_padding_check_PKCS1_type_2(to, num, buf, j, num); + else + r = ossl_rsa_padding_check_PKCS1_type_2(rsa->libctx, to, num, buf, j, num, kdk); + break; + case RSA_PKCS1_OAEP_PADDING: + r = RSA_padding_check_PKCS1_OAEP(to, num, buf, j, num, NULL, 0); + break; + case RSA_NO_PADDING: + memcpy(to, buf, (r = j)); + break; + default: + ERR_raise(ERR_LIB_RSA, RSA_R_UNKNOWN_PADDING_TYPE); + goto err; + } +#ifndef FIPS_MODULE + /* + * This trick doesn't work in the FIPS provider because libcrypto manages + * the error stack. Instead we opt not to put an error on the stack at all + * in case of padding failure in the FIPS provider. + */ + ERR_raise(ERR_LIB_RSA, RSA_R_PADDING_CHECK_FAILED); + err_clear_last_constant_time(1 & ~constant_time_msb(r)); +#endif + + err: + HMAC_CTX_free(hmac); + EVP_MD_free(md); + BN_CTX_end(ctx); + BN_CTX_free(ctx); + OPENSSL_clear_free(buf, num); + return r; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2020-25659/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2020-25659/vuln.c new file mode 100644 index 0000000..32bca46 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2020-25659/vuln.c @@ -0,0 +1,150 @@ +/* Provenance: openssl/openssl rsa_ossl_private_decrypt (vuln). + * repo: openssl/openssl + * commit: 1ca61aa56090356bbdbb16cf48916fbd9886c78d + * parent: 1ca61aa56090356bbdbb16cf48916fbd9886c78d + * commit_url: https://github.com/openssl/openssl/commit/7fc67e0a33102aa47bbaa56533eeecb98c0450f7 + * cve: CVE-2020-25659 + * license: OpenSSL License + * function: rsa_ossl_private_decrypt + * relpath: crypto/rsa/rsa_ossl.c + */ + +static int rsa_ossl_private_decrypt(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding) +{ + BIGNUM *f, *ret; + int j, num = 0, r = -1; + unsigned char *buf = NULL; + BN_CTX *ctx = NULL; + int local_blinding = 0; + /* + * Used only if the blinding structure is shared. A non-NULL unblind + * instructs rsa_blinding_convert() and rsa_blinding_invert() to store + * the unblinding factor outside the blinding structure. + */ + BIGNUM *unblind = NULL; + BN_BLINDING *blinding = NULL; + + if ((ctx = BN_CTX_new_ex(rsa->libctx)) == NULL) + goto err; + BN_CTX_start(ctx); + f = BN_CTX_get(ctx); + ret = BN_CTX_get(ctx); + if (ret == NULL) { + ERR_raise(ERR_LIB_RSA, ERR_R_BN_LIB); + goto err; + } + num = BN_num_bytes(rsa->n); + buf = OPENSSL_malloc(num); + if (buf == NULL) + goto err; + + /* + * This check was for equality but PGP does evil things and chops off the + * top '0' bytes + */ + if (flen > num) { + ERR_raise(ERR_LIB_RSA, RSA_R_DATA_GREATER_THAN_MOD_LEN); + goto err; + } + + /* make data into a big number */ + if (BN_bin2bn(from, (int)flen, f) == NULL) + goto err; + + if (BN_ucmp(f, rsa->n) >= 0) { + ERR_raise(ERR_LIB_RSA, RSA_R_DATA_TOO_LARGE_FOR_MODULUS); + goto err; + } + + if (!(rsa->flags & RSA_FLAG_NO_BLINDING)) { + blinding = rsa_get_blinding(rsa, &local_blinding, ctx); + if (blinding == NULL) { + ERR_raise(ERR_LIB_RSA, ERR_R_INTERNAL_ERROR); + goto err; + } + } + + if (blinding != NULL) { + if (!local_blinding && ((unblind = BN_CTX_get(ctx)) == NULL)) { + ERR_raise(ERR_LIB_RSA, ERR_R_BN_LIB); + goto err; + } + if (!rsa_blinding_convert(blinding, f, unblind, ctx)) + goto err; + } + + /* do the decrypt */ + if ((rsa->flags & RSA_FLAG_EXT_PKEY) || + (rsa->version == RSA_ASN1_VERSION_MULTI) || + ((rsa->p != NULL) && + (rsa->q != NULL) && + (rsa->dmp1 != NULL) && (rsa->dmq1 != NULL) && (rsa->iqmp != NULL))) { + if (!rsa->meth->rsa_mod_exp(ret, f, rsa, ctx)) + goto err; + } else { + BIGNUM *d = BN_new(); + if (d == NULL) { + ERR_raise(ERR_LIB_RSA, ERR_R_BN_LIB); + goto err; + } + if (rsa->d == NULL) { + ERR_raise(ERR_LIB_RSA, RSA_R_MISSING_PRIVATE_KEY); + BN_free(d); + goto err; + } + BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME); + + if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) + if (!BN_MONT_CTX_set_locked(&rsa->_method_mod_n, rsa->lock, + rsa->n, ctx)) { + BN_free(d); + goto err; + } + if (!rsa->meth->bn_mod_exp(ret, f, d, rsa->n, ctx, + rsa->_method_mod_n)) { + BN_free(d); + goto err; + } + /* We MUST free d before any further use of rsa->d */ + BN_free(d); + } + + if (blinding) + if (!rsa_blinding_invert(blinding, ret, unblind, ctx)) + goto err; + + j = BN_bn2binpad(ret, buf, num); + if (j < 0) + goto err; + + switch (padding) { + case RSA_PKCS1_PADDING: + r = RSA_padding_check_PKCS1_type_2(to, num, buf, j, num); + break; + case RSA_PKCS1_OAEP_PADDING: + r = RSA_padding_check_PKCS1_OAEP(to, num, buf, j, num, NULL, 0); + break; + case RSA_NO_PADDING: + memcpy(to, buf, (r = j)); + break; + default: + ERR_raise(ERR_LIB_RSA, RSA_R_UNKNOWN_PADDING_TYPE); + goto err; + } +#ifndef FIPS_MODULE + /* + * This trick doesn't work in the FIPS provider because libcrypto manages + * the error stack. Instead we opt not to put an error on the stack at all + * in case of padding failure in the FIPS provider. + */ + ERR_raise(ERR_LIB_RSA, RSA_R_PADDING_CHECK_FAILED); + err_clear_last_constant_time(1 & ~constant_time_msb(r)); +#endif + + err: + BN_CTX_end(ctx); + BN_CTX_free(ctx); + OPENSSL_clear_free(buf, num); + return r; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-23840-evp_encryptdecryptupdate/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2021-23840-evp_encryptdecryptupdate/fixed.c new file mode 100644 index 0000000..2b8f107 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-23840-evp_encryptdecryptupdate/fixed.c @@ -0,0 +1,108 @@ +/* Provenance: openssl/openssl evp_EncryptDecryptUpdate (fixed). + * repo: openssl/openssl + * commit: 6a51b9e1d0cf0bf8515f7201b68fb0a3482b3dc1 + * parent: 481a88f13c44996a008195791ea0dc076b968774 + * commit_url: https://github.com/openssl/openssl/commit/6a51b9e1d0cf0bf8515f7201b68fb0a3482b3dc1 + * cve: CVE-2021-23840 + * license: OpenSSL License + * function: evp_EncryptDecryptUpdate + * relpath: crypto/evp/evp_enc.c + */ + +static int evp_EncryptDecryptUpdate(EVP_CIPHER_CTX *ctx, + unsigned char *out, int *outl, + const unsigned char *in, int inl) +{ + int i, j, bl, cmpl = inl; + + if (EVP_CIPHER_CTX_test_flags(ctx, EVP_CIPH_FLAG_LENGTH_BITS)) + cmpl = (cmpl + 7) / 8; + + bl = ctx->cipher->block_size; + + /* + * CCM mode needs to know about the case where inl == 0 && in == NULL - it + * means the plaintext/ciphertext length is 0 + */ + if (inl < 0 + || (inl == 0 + && EVP_CIPHER_mode(ctx->cipher) != EVP_CIPH_CCM_MODE)) { + *outl = 0; + return inl == 0; + } + + if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) { + /* If block size > 1 then the cipher will have to do this check */ + if (bl == 1 && is_partially_overlapping(out, in, cmpl)) { + EVPerr(EVP_F_EVP_ENCRYPTDECRYPTUPDATE, EVP_R_PARTIALLY_OVERLAPPING); + return 0; + } + + i = ctx->cipher->do_cipher(ctx, out, in, inl); + if (i < 0) + return 0; + else + *outl = i; + return 1; + } + + if (is_partially_overlapping(out + ctx->buf_len, in, cmpl)) { + EVPerr(EVP_F_EVP_ENCRYPTDECRYPTUPDATE, EVP_R_PARTIALLY_OVERLAPPING); + return 0; + } + + if (ctx->buf_len == 0 && (inl & (ctx->block_mask)) == 0) { + if (ctx->cipher->do_cipher(ctx, out, in, inl)) { + *outl = inl; + return 1; + } else { + *outl = 0; + return 0; + } + } + i = ctx->buf_len; + OPENSSL_assert(bl <= (int)sizeof(ctx->buf)); + if (i != 0) { + if (bl - i > inl) { + memcpy(&(ctx->buf[i]), in, inl); + ctx->buf_len += inl; + *outl = 0; + return 1; + } else { + j = bl - i; + + /* + * Once we've processed the first j bytes from in, the amount of + * data left that is a multiple of the block length is: + * (inl - j) & ~(bl - 1) + * We must ensure that this amount of data, plus the one block that + * we process from ctx->buf does not exceed INT_MAX + */ + if (((inl - j) & ~(bl - 1)) > INT_MAX - bl) { + EVPerr(EVP_F_EVP_ENCRYPTDECRYPTUPDATE, + EVP_R_OUTPUT_WOULD_OVERFLOW); + return 0; + } + memcpy(&(ctx->buf[i]), in, j); + inl -= j; + in += j; + if (!ctx->cipher->do_cipher(ctx, out, ctx->buf, bl)) + return 0; + out += bl; + *outl = bl; + } + } else + *outl = 0; + i = inl & (bl - 1); + inl -= i; + if (inl > 0) { + if (!ctx->cipher->do_cipher(ctx, out, in, inl)) + return 0; + *outl += inl; + } + + if (i != 0) + memcpy(ctx->buf, &(in[inl]), i); + ctx->buf_len = i; + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-23840-evp_encryptdecryptupdate/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2021-23840-evp_encryptdecryptupdate/vuln.c new file mode 100644 index 0000000..96ae944 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-23840-evp_encryptdecryptupdate/vuln.c @@ -0,0 +1,95 @@ +/* Provenance: openssl/openssl evp_EncryptDecryptUpdate (vuln). + * repo: openssl/openssl + * commit: 481a88f13c44996a008195791ea0dc076b968774 + * parent: 481a88f13c44996a008195791ea0dc076b968774 + * commit_url: https://github.com/openssl/openssl/commit/6a51b9e1d0cf0bf8515f7201b68fb0a3482b3dc1 + * cve: CVE-2021-23840 + * license: OpenSSL License + * function: evp_EncryptDecryptUpdate + * relpath: crypto/evp/evp_enc.c + */ + +static int evp_EncryptDecryptUpdate(EVP_CIPHER_CTX *ctx, + unsigned char *out, int *outl, + const unsigned char *in, int inl) +{ + int i, j, bl, cmpl = inl; + + if (EVP_CIPHER_CTX_test_flags(ctx, EVP_CIPH_FLAG_LENGTH_BITS)) + cmpl = (cmpl + 7) / 8; + + bl = ctx->cipher->block_size; + + /* + * CCM mode needs to know about the case where inl == 0 && in == NULL - it + * means the plaintext/ciphertext length is 0 + */ + if (inl < 0 + || (inl == 0 + && EVP_CIPHER_mode(ctx->cipher) != EVP_CIPH_CCM_MODE)) { + *outl = 0; + return inl == 0; + } + + if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) { + /* If block size > 1 then the cipher will have to do this check */ + if (bl == 1 && is_partially_overlapping(out, in, cmpl)) { + EVPerr(EVP_F_EVP_ENCRYPTDECRYPTUPDATE, EVP_R_PARTIALLY_OVERLAPPING); + return 0; + } + + i = ctx->cipher->do_cipher(ctx, out, in, inl); + if (i < 0) + return 0; + else + *outl = i; + return 1; + } + + if (is_partially_overlapping(out + ctx->buf_len, in, cmpl)) { + EVPerr(EVP_F_EVP_ENCRYPTDECRYPTUPDATE, EVP_R_PARTIALLY_OVERLAPPING); + return 0; + } + + if (ctx->buf_len == 0 && (inl & (ctx->block_mask)) == 0) { + if (ctx->cipher->do_cipher(ctx, out, in, inl)) { + *outl = inl; + return 1; + } else { + *outl = 0; + return 0; + } + } + i = ctx->buf_len; + OPENSSL_assert(bl <= (int)sizeof(ctx->buf)); + if (i != 0) { + if (bl - i > inl) { + memcpy(&(ctx->buf[i]), in, inl); + ctx->buf_len += inl; + *outl = 0; + return 1; + } else { + j = bl - i; + memcpy(&(ctx->buf[i]), in, j); + inl -= j; + in += j; + if (!ctx->cipher->do_cipher(ctx, out, ctx->buf, bl)) + return 0; + out += bl; + *outl = bl; + } + } else + *outl = 0; + i = inl & (bl - 1); + inl -= i; + if (inl > 0) { + if (!ctx->cipher->do_cipher(ctx, out, in, inl)) + return 0; + *outl += inl; + } + + if (i != 0) + memcpy(ctx->buf, &(in[inl]), i); + ctx->buf_len = i; + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-23840/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2021-23840/fixed.c new file mode 100644 index 0000000..ec5454f --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-23840/fixed.c @@ -0,0 +1,100 @@ +/* Provenance: openssl/openssl evp_EncryptDecryptUpdate (fixed). + * repo: openssl/openssl + * commit: c9fb704cf3af5524eb8e79961e31b60eee8c3c47 + * parent: c1ddd392cf9737c09c1f9bf690adfbe596403c5e + * commit_url: https://github.com/openssl/openssl/commit/c9fb704cf3af5524eb8e79961e31b60eee8c3c47 + * cve: CVE-2021-23840 + * license: OpenSSL License + * function: evp_EncryptDecryptUpdate + * relpath: crypto/evp/evp_enc.c + */ + +static int evp_EncryptDecryptUpdate(EVP_CIPHER_CTX *ctx, + unsigned char *out, int *outl, + const unsigned char *in, int inl) +{ + int i, j, bl, cmpl = inl; + + if (EVP_CIPHER_CTX_test_flags(ctx, EVP_CIPH_FLAG_LENGTH_BITS)) + cmpl = (cmpl + 7) / 8; + + bl = ctx->cipher->block_size; + + if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) { + /* If block size > 1 then the cipher will have to do this check */ + if (bl == 1 && is_partially_overlapping(out, in, cmpl)) { + ERR_raise(ERR_LIB_EVP, EVP_R_PARTIALLY_OVERLAPPING); + return 0; + } + + i = ctx->cipher->do_cipher(ctx, out, in, inl); + if (i < 0) + return 0; + else + *outl = i; + return 1; + } + + if (inl <= 0) { + *outl = 0; + return inl == 0; + } + if (is_partially_overlapping(out + ctx->buf_len, in, cmpl)) { + ERR_raise(ERR_LIB_EVP, EVP_R_PARTIALLY_OVERLAPPING); + return 0; + } + + if (ctx->buf_len == 0 && (inl & (ctx->block_mask)) == 0) { + if (ctx->cipher->do_cipher(ctx, out, in, inl)) { + *outl = inl; + return 1; + } else { + *outl = 0; + return 0; + } + } + i = ctx->buf_len; + OPENSSL_assert(bl <= (int)sizeof(ctx->buf)); + if (i != 0) { + if (bl - i > inl) { + memcpy(&(ctx->buf[i]), in, inl); + ctx->buf_len += inl; + *outl = 0; + return 1; + } else { + j = bl - i; + + /* + * Once we've processed the first j bytes from in, the amount of + * data left that is a multiple of the block length is: + * (inl - j) & ~(bl - 1) + * We must ensure that this amount of data, plus the one block that + * we process from ctx->buf does not exceed INT_MAX + */ + if (((inl - j) & ~(bl - 1)) > INT_MAX - bl) { + ERR_raise(ERR_LIB_EVP, EVP_R_OUTPUT_WOULD_OVERFLOW); + return 0; + } + memcpy(&(ctx->buf[i]), in, j); + inl -= j; + in += j; + if (!ctx->cipher->do_cipher(ctx, out, ctx->buf, bl)) + return 0; + out += bl; + *outl = bl; + } + } else + *outl = 0; + i = inl & (bl - 1); + inl -= i; + if (inl > 0) { + if (!ctx->cipher->do_cipher(ctx, out, in, inl)) + return 0; + *outl += inl; + } + + if (i != 0) + memcpy(ctx->buf, &(in[inl]), i); + ctx->buf_len = i; + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-23840/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2021-23840/vuln.c new file mode 100644 index 0000000..c8fc8d0 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-23840/vuln.c @@ -0,0 +1,88 @@ +/* Provenance: openssl/openssl evp_EncryptDecryptUpdate (vuln). + * repo: openssl/openssl + * commit: c1ddd392cf9737c09c1f9bf690adfbe596403c5e + * parent: c1ddd392cf9737c09c1f9bf690adfbe596403c5e + * commit_url: https://github.com/openssl/openssl/commit/c9fb704cf3af5524eb8e79961e31b60eee8c3c47 + * cve: CVE-2021-23840 + * license: OpenSSL License + * function: evp_EncryptDecryptUpdate + * relpath: crypto/evp/evp_enc.c + */ + +static int evp_EncryptDecryptUpdate(EVP_CIPHER_CTX *ctx, + unsigned char *out, int *outl, + const unsigned char *in, int inl) +{ + int i, j, bl, cmpl = inl; + + if (EVP_CIPHER_CTX_test_flags(ctx, EVP_CIPH_FLAG_LENGTH_BITS)) + cmpl = (cmpl + 7) / 8; + + bl = ctx->cipher->block_size; + + if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) { + /* If block size > 1 then the cipher will have to do this check */ + if (bl == 1 && is_partially_overlapping(out, in, cmpl)) { + ERR_raise(ERR_LIB_EVP, EVP_R_PARTIALLY_OVERLAPPING); + return 0; + } + + i = ctx->cipher->do_cipher(ctx, out, in, inl); + if (i < 0) + return 0; + else + *outl = i; + return 1; + } + + if (inl <= 0) { + *outl = 0; + return inl == 0; + } + if (is_partially_overlapping(out + ctx->buf_len, in, cmpl)) { + ERR_raise(ERR_LIB_EVP, EVP_R_PARTIALLY_OVERLAPPING); + return 0; + } + + if (ctx->buf_len == 0 && (inl & (ctx->block_mask)) == 0) { + if (ctx->cipher->do_cipher(ctx, out, in, inl)) { + *outl = inl; + return 1; + } else { + *outl = 0; + return 0; + } + } + i = ctx->buf_len; + OPENSSL_assert(bl <= (int)sizeof(ctx->buf)); + if (i != 0) { + if (bl - i > inl) { + memcpy(&(ctx->buf[i]), in, inl); + ctx->buf_len += inl; + *outl = 0; + return 1; + } else { + j = bl - i; + memcpy(&(ctx->buf[i]), in, j); + inl -= j; + in += j; + if (!ctx->cipher->do_cipher(ctx, out, ctx->buf, bl)) + return 0; + out += bl; + *outl = bl; + } + } else + *outl = 0; + i = inl & (bl - 1); + inl -= i; + if (inl > 0) { + if (!ctx->cipher->do_cipher(ctx, out, in, inl)) + return 0; + *outl += inl; + } + + if (i != 0) + memcpy(ctx->buf, &(in[inl]), i); + ctx->buf_len = i; + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-23841/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2021-23841/fixed.c new file mode 100644 index 0000000..66ff842 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-23841/fixed.c @@ -0,0 +1,41 @@ +/* Provenance: openssl/openssl X509_issuer_and_serial_hash (fixed). + * repo: openssl/openssl + * commit: 122a19ab48091c657f7cb1fb3af9fc07bd557bbf + * parent: c8c6e7438c03b2fc24e7ead460feeaef04911fb4 + * commit_url: https://github.com/openssl/openssl/commit/122a19ab48091c657f7cb1fb3af9fc07bd557bbf + * cve: CVE-2021-23841 + * license: OpenSSL License + * function: X509_issuer_and_serial_hash + * relpath: crypto/x509/x509_cmp.c + */ + +unsigned long X509_issuer_and_serial_hash(X509 *a) +{ + unsigned long ret = 0; + EVP_MD_CTX *ctx = EVP_MD_CTX_new(); + unsigned char md[16]; + char *f; + + if (ctx == NULL) + goto err; + f = X509_NAME_oneline(a->cert_info.issuer, NULL, 0); + if (f == NULL) + goto err; + if (!EVP_DigestInit_ex(ctx, EVP_md5(), NULL)) + goto err; + if (!EVP_DigestUpdate(ctx, (unsigned char *)f, strlen(f))) + goto err; + OPENSSL_free(f); + if (!EVP_DigestUpdate + (ctx, (unsigned char *)a->cert_info.serialNumber.data, + (unsigned long)a->cert_info.serialNumber.length)) + goto err; + if (!EVP_DigestFinal_ex(ctx, &(md[0]), NULL)) + goto err; + ret = (((unsigned long)md[0]) | ((unsigned long)md[1] << 8L) | + ((unsigned long)md[2] << 16L) | ((unsigned long)md[3] << 24L) + ) & 0xffffffffL; + err: + EVP_MD_CTX_free(ctx); + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-23841/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2021-23841/vuln.c new file mode 100644 index 0000000..01d74c3 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-23841/vuln.c @@ -0,0 +1,39 @@ +/* Provenance: openssl/openssl X509_issuer_and_serial_hash (vuln). + * repo: openssl/openssl + * commit: c8c6e7438c03b2fc24e7ead460feeaef04911fb4 + * parent: c8c6e7438c03b2fc24e7ead460feeaef04911fb4 + * commit_url: https://github.com/openssl/openssl/commit/122a19ab48091c657f7cb1fb3af9fc07bd557bbf + * cve: CVE-2021-23841 + * license: OpenSSL License + * function: X509_issuer_and_serial_hash + * relpath: crypto/x509/x509_cmp.c + */ + +unsigned long X509_issuer_and_serial_hash(X509 *a) +{ + unsigned long ret = 0; + EVP_MD_CTX *ctx = EVP_MD_CTX_new(); + unsigned char md[16]; + char *f; + + if (ctx == NULL) + goto err; + f = X509_NAME_oneline(a->cert_info.issuer, NULL, 0); + if (!EVP_DigestInit_ex(ctx, EVP_md5(), NULL)) + goto err; + if (!EVP_DigestUpdate(ctx, (unsigned char *)f, strlen(f))) + goto err; + OPENSSL_free(f); + if (!EVP_DigestUpdate + (ctx, (unsigned char *)a->cert_info.serialNumber.data, + (unsigned long)a->cert_info.serialNumber.length)) + goto err; + if (!EVP_DigestFinal_ex(ctx, &(md[0]), NULL)) + goto err; + ret = (((unsigned long)md[0]) | ((unsigned long)md[1] << 8L) | + ((unsigned long)md[2] << 16L) | ((unsigned long)md[3] << 24L) + ) & 0xffffffffL; + err: + EVP_MD_CTX_free(ctx); + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3449-def_generate_session_id/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2021-3449-def_generate_session_id/fixed.c new file mode 100644 index 0000000..13e2bf9 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3449-def_generate_session_id/fixed.c @@ -0,0 +1,38 @@ +/* Provenance: openssl/openssl def_generate_session_id (fixed). + * repo: openssl/openssl + * commit: 2b9e2afc382490592078cdb69d06f54f0fefd4c6 + * parent: 7b2625274f5d5ec90aee522ec4e4f3aa08fa5b70 + * commit_url: https://github.com/openssl/openssl/commit/2b9e2afc382490592078cdb69d06f54f0fefd4c6 + * cve: CVE-2021-3449 + * license: OpenSSL License + * function: def_generate_session_id + * relpath: ssl/ssl_sess.c + */ + +static int def_generate_session_id(SSL *ssl, unsigned char *id, + unsigned int *id_len) +{ + unsigned int retry = 0; + do { + if (RAND_bytes_ex(ssl->ctx->libctx, id, *id_len, 0) <= 0) + return 0; +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + if (retry > 0) { + id[0]++; + } +#endif + } while (SSL_has_matching_session_id(ssl, id, *id_len) && + (++retry < MAX_SESS_ID_ATTEMPTS)) ; + if (retry < MAX_SESS_ID_ATTEMPTS) + return 1; + /* else - woops a session_id match */ + /* + * XXX We should also check the external cache -- but the probability of + * a collision is negligible, and we could not prevent the concurrent + * creation of sessions with identical IDs since we currently don't have + * means to atomically check whether a session ID already exists and make + * a reservation for it if it does not (this problem applies to the + * internal cache as well). + */ + return 0; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3449-def_generate_session_id/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2021-3449-def_generate_session_id/vuln.c new file mode 100644 index 0000000..e2bbb58 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3449-def_generate_session_id/vuln.c @@ -0,0 +1,33 @@ +/* Provenance: openssl/openssl def_generate_session_id (vuln). + * repo: openssl/openssl + * commit: 7b2625274f5d5ec90aee522ec4e4f3aa08fa5b70 + * parent: 7b2625274f5d5ec90aee522ec4e4f3aa08fa5b70 + * commit_url: https://github.com/openssl/openssl/commit/2b9e2afc382490592078cdb69d06f54f0fefd4c6 + * cve: CVE-2021-3449 + * license: OpenSSL License + * function: def_generate_session_id + * relpath: ssl/ssl_sess.c + */ + +static int def_generate_session_id(SSL *ssl, unsigned char *id, + unsigned int *id_len) +{ + unsigned int retry = 0; + do + if (RAND_bytes_ex(ssl->ctx->libctx, id, *id_len, 0) <= 0) + return 0; + while (SSL_has_matching_session_id(ssl, id, *id_len) && + (++retry < MAX_SESS_ID_ATTEMPTS)) ; + if (retry < MAX_SESS_ID_ATTEMPTS) + return 1; + /* else - woops a session_id match */ + /* + * XXX We should also check the external cache -- but the probability of + * a collision is negligible, and we could not prevent the concurrent + * creation of sessions with identical IDs since we currently don't have + * means to atomically check whether a session ID already exists and make + * a reservation for it if it does not (this problem applies to the + * internal cache as well). + */ + return 0; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3449-init_sig_algs/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2021-3449-init_sig_algs/fixed.c new file mode 100644 index 0000000..345f927 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3449-init_sig_algs/fixed.c @@ -0,0 +1,20 @@ +/* Provenance: openssl/openssl init_sig_algs (fixed). + * repo: openssl/openssl + * commit: 02b1636fe3db274497304a3e95a4e32ced7e841b + * parent: 112580c27b829b0ac0874d5c5787195f27c7952c + * commit_url: https://github.com/openssl/openssl/commit/02b1636fe3db274497304a3e95a4e32ced7e841b + * cve: CVE-2021-3449 + * license: OpenSSL License + * function: init_sig_algs + * relpath: ssl/statem/extensions.c + */ + +static int init_sig_algs(SSL *s, unsigned int context) +{ + /* Clear any signature algorithms extension received */ + OPENSSL_free(s->s3.tmp.peer_sigalgs); + s->s3.tmp.peer_sigalgs = NULL; + s->s3.tmp.peer_sigalgslen = 0; + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3449-init_sig_algs/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2021-3449-init_sig_algs/vuln.c new file mode 100644 index 0000000..aa712d3 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3449-init_sig_algs/vuln.c @@ -0,0 +1,19 @@ +/* Provenance: openssl/openssl init_sig_algs (vuln). + * repo: openssl/openssl + * commit: 112580c27b829b0ac0874d5c5787195f27c7952c + * parent: 112580c27b829b0ac0874d5c5787195f27c7952c + * commit_url: https://github.com/openssl/openssl/commit/02b1636fe3db274497304a3e95a4e32ced7e841b + * cve: CVE-2021-3449 + * license: OpenSSL License + * function: init_sig_algs + * relpath: ssl/statem/extensions.c + */ + +static int init_sig_algs(SSL *s, unsigned int context) +{ + /* Clear any signature algorithms extension received */ + OPENSSL_free(s->s3.tmp.peer_sigalgs); + s->s3.tmp.peer_sigalgs = NULL; + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3449-init_sig_algs_cert/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2021-3449-init_sig_algs_cert/fixed.c new file mode 100644 index 0000000..ee7c2e1 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3449-init_sig_algs_cert/fixed.c @@ -0,0 +1,20 @@ +/* Provenance: openssl/openssl init_sig_algs_cert (fixed). + * repo: openssl/openssl + * commit: 39a140597d874e554b736885ac4dea16ac40a87a + * parent: 02b1636fe3db274497304a3e95a4e32ced7e841b + * commit_url: https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a + * cve: CVE-2021-3449 + * license: OpenSSL License + * function: init_sig_algs_cert + * relpath: ssl/statem/extensions.c + */ + +static int init_sig_algs_cert(SSL *s, ossl_unused unsigned int context) +{ + /* Clear any signature algorithms extension received */ + OPENSSL_free(s->s3.tmp.peer_cert_sigalgs); + s->s3.tmp.peer_cert_sigalgs = NULL; + s->s3.tmp.peer_cert_sigalgslen = 0; + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3449-init_sig_algs_cert/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2021-3449-init_sig_algs_cert/vuln.c new file mode 100644 index 0000000..e9bc45f --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3449-init_sig_algs_cert/vuln.c @@ -0,0 +1,19 @@ +/* Provenance: openssl/openssl init_sig_algs_cert (vuln). + * repo: openssl/openssl + * commit: 02b1636fe3db274497304a3e95a4e32ced7e841b + * parent: 02b1636fe3db274497304a3e95a4e32ced7e841b + * commit_url: https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a + * cve: CVE-2021-3449 + * license: OpenSSL License + * function: init_sig_algs_cert + * relpath: ssl/statem/extensions.c + */ + +static int init_sig_algs_cert(SSL *s, ossl_unused unsigned int context) +{ + /* Clear any signature algorithms extension received */ + OPENSSL_free(s->s3.tmp.peer_cert_sigalgs); + s->s3.tmp.peer_cert_sigalgs = NULL; + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3449-ssl_ctx_set_alpn_protos/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2021-3449-ssl_ctx_set_alpn_protos/fixed.c new file mode 100644 index 0000000..3e125d3 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3449-ssl_ctx_set_alpn_protos/fixed.c @@ -0,0 +1,25 @@ +/* Provenance: openssl/openssl SSL_CTX_set_alpn_protos (fixed). + * repo: openssl/openssl + * commit: 39a140597d874e554b736885ac4dea16ac40a87a + * parent: 02b1636fe3db274497304a3e95a4e32ced7e841b + * commit_url: https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a + * cve: CVE-2021-3449 + * license: OpenSSL License + * function: SSL_CTX_set_alpn_protos + * relpath: ssl/ssl_lib.c + */ + +int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const unsigned char *protos, + unsigned int protos_len) +{ + OPENSSL_free(ctx->ext.alpn); + ctx->ext.alpn = OPENSSL_memdup(protos, protos_len); + if (ctx->ext.alpn == NULL) { + ctx->ext.alpn_len = 0; + ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE); + return 1; + } + ctx->ext.alpn_len = protos_len; + + return 0; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3449-ssl_ctx_set_alpn_protos/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2021-3449-ssl_ctx_set_alpn_protos/vuln.c new file mode 100644 index 0000000..c2d8e47 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3449-ssl_ctx_set_alpn_protos/vuln.c @@ -0,0 +1,24 @@ +/* Provenance: openssl/openssl SSL_CTX_set_alpn_protos (vuln). + * repo: openssl/openssl + * commit: 02b1636fe3db274497304a3e95a4e32ced7e841b + * parent: 02b1636fe3db274497304a3e95a4e32ced7e841b + * commit_url: https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a + * cve: CVE-2021-3449 + * license: OpenSSL License + * function: SSL_CTX_set_alpn_protos + * relpath: ssl/ssl_lib.c + */ + +int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const unsigned char *protos, + unsigned int protos_len) +{ + OPENSSL_free(ctx->ext.alpn); + ctx->ext.alpn = OPENSSL_memdup(protos, protos_len); + if (ctx->ext.alpn == NULL) { + ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE); + return 1; + } + ctx->ext.alpn_len = protos_len; + + return 0; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3449-ssl_generate_master_secr/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2021-3449-ssl_generate_master_secr/fixed.c new file mode 100644 index 0000000..269bce6 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3449-ssl_generate_master_secr/fixed.c @@ -0,0 +1,81 @@ +/* Provenance: openssl/openssl ssl_generate_master_secret (fixed). + * repo: openssl/openssl + * commit: 39a140597d874e554b736885ac4dea16ac40a87a + * parent: 02b1636fe3db274497304a3e95a4e32ced7e841b + * commit_url: https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a + * cve: CVE-2021-3449 + * license: OpenSSL License + * function: ssl_generate_master_secret + * relpath: ssl/s3_lib.c + */ + +int ssl_generate_master_secret(SSL *s, unsigned char *pms, size_t pmslen, + int free_pms) +{ + unsigned long alg_k = s->s3.tmp.new_cipher->algorithm_mkey; + int ret = 0; + + if (alg_k & SSL_PSK) { +#ifndef OPENSSL_NO_PSK + unsigned char *pskpms, *t; + size_t psklen = s->s3.tmp.psklen; + size_t pskpmslen; + + /* create PSK premaster_secret */ + + /* For plain PSK "other_secret" is psklen zeroes */ + if (alg_k & SSL_kPSK) + pmslen = psklen; + + pskpmslen = 4 + pmslen + psklen; + pskpms = OPENSSL_malloc(pskpmslen); + if (pskpms == NULL) + goto err; + t = pskpms; + s2n(pmslen, t); + if (alg_k & SSL_kPSK) + memset(t, 0, pmslen); + else + memcpy(t, pms, pmslen); + t += pmslen; + s2n(psklen, t); + memcpy(t, s->s3.tmp.psk, psklen); + + OPENSSL_clear_free(s->s3.tmp.psk, psklen); + s->s3.tmp.psk = NULL; + s->s3.tmp.psklen = 0; + if (!s->method->ssl3_enc->generate_master_secret(s, + s->session->master_key, pskpms, pskpmslen, + &s->session->master_key_length)) { + OPENSSL_clear_free(pskpms, pskpmslen); + /* SSLfatal() already called */ + goto err; + } + OPENSSL_clear_free(pskpms, pskpmslen); +#else + /* Should never happen */ + goto err; +#endif + } else { + if (!s->method->ssl3_enc->generate_master_secret(s, + s->session->master_key, pms, pmslen, + &s->session->master_key_length)) { + /* SSLfatal() already called */ + goto err; + } + } + + ret = 1; + err: + if (pms) { + if (free_pms) + OPENSSL_clear_free(pms, pmslen); + else + OPENSSL_cleanse(pms, pmslen); + } + if (s->server == 0) { + s->s3.tmp.pms = NULL; + s->s3.tmp.pmslen = 0; + } + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3449-ssl_generate_master_secr/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2021-3449-ssl_generate_master_secr/vuln.c new file mode 100644 index 0000000..a517461 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3449-ssl_generate_master_secr/vuln.c @@ -0,0 +1,78 @@ +/* Provenance: openssl/openssl ssl_generate_master_secret (vuln). + * repo: openssl/openssl + * commit: 02b1636fe3db274497304a3e95a4e32ced7e841b + * parent: 02b1636fe3db274497304a3e95a4e32ced7e841b + * commit_url: https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a + * cve: CVE-2021-3449 + * license: OpenSSL License + * function: ssl_generate_master_secret + * relpath: ssl/s3_lib.c + */ + +int ssl_generate_master_secret(SSL *s, unsigned char *pms, size_t pmslen, + int free_pms) +{ + unsigned long alg_k = s->s3.tmp.new_cipher->algorithm_mkey; + int ret = 0; + + if (alg_k & SSL_PSK) { +#ifndef OPENSSL_NO_PSK + unsigned char *pskpms, *t; + size_t psklen = s->s3.tmp.psklen; + size_t pskpmslen; + + /* create PSK premaster_secret */ + + /* For plain PSK "other_secret" is psklen zeroes */ + if (alg_k & SSL_kPSK) + pmslen = psklen; + + pskpmslen = 4 + pmslen + psklen; + pskpms = OPENSSL_malloc(pskpmslen); + if (pskpms == NULL) + goto err; + t = pskpms; + s2n(pmslen, t); + if (alg_k & SSL_kPSK) + memset(t, 0, pmslen); + else + memcpy(t, pms, pmslen); + t += pmslen; + s2n(psklen, t); + memcpy(t, s->s3.tmp.psk, psklen); + + OPENSSL_clear_free(s->s3.tmp.psk, psklen); + s->s3.tmp.psk = NULL; + if (!s->method->ssl3_enc->generate_master_secret(s, + s->session->master_key, pskpms, pskpmslen, + &s->session->master_key_length)) { + OPENSSL_clear_free(pskpms, pskpmslen); + /* SSLfatal() already called */ + goto err; + } + OPENSSL_clear_free(pskpms, pskpmslen); +#else + /* Should never happen */ + goto err; +#endif + } else { + if (!s->method->ssl3_enc->generate_master_secret(s, + s->session->master_key, pms, pmslen, + &s->session->master_key_length)) { + /* SSLfatal() already called */ + goto err; + } + } + + ret = 1; + err: + if (pms) { + if (free_pms) + OPENSSL_clear_free(pms, pmslen); + else + OPENSSL_cleanse(pms, pmslen); + } + if (s->server == 0) + s->s3.tmp.pms = NULL; + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_construct_ctos_early/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_construct_ctos_early/fixed.c new file mode 100644 index 0000000..ebe28c8 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_construct_ctos_early/fixed.c @@ -0,0 +1,162 @@ +/* Provenance: openssl/openssl tls_construct_ctos_early_data (fixed). + * repo: openssl/openssl + * commit: 39a140597d874e554b736885ac4dea16ac40a87a + * parent: 02b1636fe3db274497304a3e95a4e32ced7e841b + * commit_url: https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a + * cve: CVE-2021-3449 + * license: OpenSSL License + * function: tls_construct_ctos_early_data + * relpath: ssl/statem/extensions_clnt.c + */ + +EXT_RETURN tls_construct_ctos_early_data(SSL *s, WPACKET *pkt, + unsigned int context, X509 *x, + size_t chainidx) +{ +#ifndef OPENSSL_NO_PSK + char identity[PSK_MAX_IDENTITY_LEN + 1]; +#endif /* OPENSSL_NO_PSK */ + const unsigned char *id = NULL; + size_t idlen = 0; + SSL_SESSION *psksess = NULL; + SSL_SESSION *edsess = NULL; + const EVP_MD *handmd = NULL; + + if (s->hello_retry_request == SSL_HRR_PENDING) + handmd = ssl_handshake_md(s); + + if (s->psk_use_session_cb != NULL + && (!s->psk_use_session_cb(s, handmd, &id, &idlen, &psksess) + || (psksess != NULL + && psksess->ssl_version != TLS1_3_VERSION))) { + SSL_SESSION_free(psksess); + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_BAD_PSK); + return EXT_RETURN_FAIL; + } + +#ifndef OPENSSL_NO_PSK + if (psksess == NULL && s->psk_client_callback != NULL) { + unsigned char psk[PSK_MAX_PSK_LEN]; + size_t psklen = 0; + + memset(identity, 0, sizeof(identity)); + psklen = s->psk_client_callback(s, NULL, identity, sizeof(identity) - 1, + psk, sizeof(psk)); + + if (psklen > PSK_MAX_PSK_LEN) { + SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, ERR_R_INTERNAL_ERROR); + return EXT_RETURN_FAIL; + } else if (psklen > 0) { + const unsigned char tls13_aes128gcmsha256_id[] = { 0x13, 0x01 }; + const SSL_CIPHER *cipher; + + idlen = strlen(identity); + if (idlen > PSK_MAX_IDENTITY_LEN) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return EXT_RETURN_FAIL; + } + id = (unsigned char *)identity; + + /* + * We found a PSK using an old style callback. We don't know + * the digest so we default to SHA256 as per the TLSv1.3 spec + */ + cipher = SSL_CIPHER_find(s, tls13_aes128gcmsha256_id); + if (cipher == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return EXT_RETURN_FAIL; + } + + psksess = SSL_SESSION_new(); + if (psksess == NULL + || !SSL_SESSION_set1_master_key(psksess, psk, psklen) + || !SSL_SESSION_set_cipher(psksess, cipher) + || !SSL_SESSION_set_protocol_version(psksess, TLS1_3_VERSION)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + OPENSSL_cleanse(psk, psklen); + return EXT_RETURN_FAIL; + } + OPENSSL_cleanse(psk, psklen); + } + } +#endif /* OPENSSL_NO_PSK */ + + SSL_SESSION_free(s->psksession); + s->psksession = psksess; + if (psksess != NULL) { + OPENSSL_free(s->psksession_id); + s->psksession_id = OPENSSL_memdup(id, idlen); + if (s->psksession_id == NULL) { + s->psksession_id_len = 0; + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return EXT_RETURN_FAIL; + } + s->psksession_id_len = idlen; + } + + if (s->early_data_state != SSL_EARLY_DATA_CONNECTING + || (s->session->ext.max_early_data == 0 + && (psksess == NULL || psksess->ext.max_early_data == 0))) { + s->max_early_data = 0; + return EXT_RETURN_NOT_SENT; + } + edsess = s->session->ext.max_early_data != 0 ? s->session : psksess; + s->max_early_data = edsess->ext.max_early_data; + + if (edsess->ext.hostname != NULL) { + if (s->ext.hostname == NULL + || (s->ext.hostname != NULL + && strcmp(s->ext.hostname, edsess->ext.hostname) != 0)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_R_INCONSISTENT_EARLY_DATA_SNI); + return EXT_RETURN_FAIL; + } + } + + if ((s->ext.alpn == NULL && edsess->ext.alpn_selected != NULL)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_INCONSISTENT_EARLY_DATA_ALPN); + return EXT_RETURN_FAIL; + } + + /* + * Verify that we are offering an ALPN protocol consistent with the early + * data. + */ + if (edsess->ext.alpn_selected != NULL) { + PACKET prots, alpnpkt; + int found = 0; + + if (!PACKET_buf_init(&prots, s->ext.alpn, s->ext.alpn_len)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return EXT_RETURN_FAIL; + } + while (PACKET_get_length_prefixed_1(&prots, &alpnpkt)) { + if (PACKET_equal(&alpnpkt, edsess->ext.alpn_selected, + edsess->ext.alpn_selected_len)) { + found = 1; + break; + } + } + if (!found) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_R_INCONSISTENT_EARLY_DATA_ALPN); + return EXT_RETURN_FAIL; + } + } + + if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_early_data) + || !WPACKET_start_sub_packet_u16(pkt) + || !WPACKET_close(pkt)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return EXT_RETURN_FAIL; + } + + /* + * We set this to rejected here. Later, if the server acknowledges the + * extension, we set it to accepted. + */ + s->ext.early_data = SSL_EARLY_DATA_REJECTED; + s->ext.early_data_ok = 1; + + return EXT_RETURN_SENT; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_construct_ctos_early/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_construct_ctos_early/vuln.c new file mode 100644 index 0000000..91fdfd0 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_construct_ctos_early/vuln.c @@ -0,0 +1,161 @@ +/* Provenance: openssl/openssl tls_construct_ctos_early_data (vuln). + * repo: openssl/openssl + * commit: 02b1636fe3db274497304a3e95a4e32ced7e841b + * parent: 02b1636fe3db274497304a3e95a4e32ced7e841b + * commit_url: https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a + * cve: CVE-2021-3449 + * license: OpenSSL License + * function: tls_construct_ctos_early_data + * relpath: ssl/statem/extensions_clnt.c + */ + +EXT_RETURN tls_construct_ctos_early_data(SSL *s, WPACKET *pkt, + unsigned int context, X509 *x, + size_t chainidx) +{ +#ifndef OPENSSL_NO_PSK + char identity[PSK_MAX_IDENTITY_LEN + 1]; +#endif /* OPENSSL_NO_PSK */ + const unsigned char *id = NULL; + size_t idlen = 0; + SSL_SESSION *psksess = NULL; + SSL_SESSION *edsess = NULL; + const EVP_MD *handmd = NULL; + + if (s->hello_retry_request == SSL_HRR_PENDING) + handmd = ssl_handshake_md(s); + + if (s->psk_use_session_cb != NULL + && (!s->psk_use_session_cb(s, handmd, &id, &idlen, &psksess) + || (psksess != NULL + && psksess->ssl_version != TLS1_3_VERSION))) { + SSL_SESSION_free(psksess); + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_BAD_PSK); + return EXT_RETURN_FAIL; + } + +#ifndef OPENSSL_NO_PSK + if (psksess == NULL && s->psk_client_callback != NULL) { + unsigned char psk[PSK_MAX_PSK_LEN]; + size_t psklen = 0; + + memset(identity, 0, sizeof(identity)); + psklen = s->psk_client_callback(s, NULL, identity, sizeof(identity) - 1, + psk, sizeof(psk)); + + if (psklen > PSK_MAX_PSK_LEN) { + SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, ERR_R_INTERNAL_ERROR); + return EXT_RETURN_FAIL; + } else if (psklen > 0) { + const unsigned char tls13_aes128gcmsha256_id[] = { 0x13, 0x01 }; + const SSL_CIPHER *cipher; + + idlen = strlen(identity); + if (idlen > PSK_MAX_IDENTITY_LEN) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return EXT_RETURN_FAIL; + } + id = (unsigned char *)identity; + + /* + * We found a PSK using an old style callback. We don't know + * the digest so we default to SHA256 as per the TLSv1.3 spec + */ + cipher = SSL_CIPHER_find(s, tls13_aes128gcmsha256_id); + if (cipher == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return EXT_RETURN_FAIL; + } + + psksess = SSL_SESSION_new(); + if (psksess == NULL + || !SSL_SESSION_set1_master_key(psksess, psk, psklen) + || !SSL_SESSION_set_cipher(psksess, cipher) + || !SSL_SESSION_set_protocol_version(psksess, TLS1_3_VERSION)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + OPENSSL_cleanse(psk, psklen); + return EXT_RETURN_FAIL; + } + OPENSSL_cleanse(psk, psklen); + } + } +#endif /* OPENSSL_NO_PSK */ + + SSL_SESSION_free(s->psksession); + s->psksession = psksess; + if (psksess != NULL) { + OPENSSL_free(s->psksession_id); + s->psksession_id = OPENSSL_memdup(id, idlen); + if (s->psksession_id == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return EXT_RETURN_FAIL; + } + s->psksession_id_len = idlen; + } + + if (s->early_data_state != SSL_EARLY_DATA_CONNECTING + || (s->session->ext.max_early_data == 0 + && (psksess == NULL || psksess->ext.max_early_data == 0))) { + s->max_early_data = 0; + return EXT_RETURN_NOT_SENT; + } + edsess = s->session->ext.max_early_data != 0 ? s->session : psksess; + s->max_early_data = edsess->ext.max_early_data; + + if (edsess->ext.hostname != NULL) { + if (s->ext.hostname == NULL + || (s->ext.hostname != NULL + && strcmp(s->ext.hostname, edsess->ext.hostname) != 0)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_R_INCONSISTENT_EARLY_DATA_SNI); + return EXT_RETURN_FAIL; + } + } + + if ((s->ext.alpn == NULL && edsess->ext.alpn_selected != NULL)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_INCONSISTENT_EARLY_DATA_ALPN); + return EXT_RETURN_FAIL; + } + + /* + * Verify that we are offering an ALPN protocol consistent with the early + * data. + */ + if (edsess->ext.alpn_selected != NULL) { + PACKET prots, alpnpkt; + int found = 0; + + if (!PACKET_buf_init(&prots, s->ext.alpn, s->ext.alpn_len)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return EXT_RETURN_FAIL; + } + while (PACKET_get_length_prefixed_1(&prots, &alpnpkt)) { + if (PACKET_equal(&alpnpkt, edsess->ext.alpn_selected, + edsess->ext.alpn_selected_len)) { + found = 1; + break; + } + } + if (!found) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_R_INCONSISTENT_EARLY_DATA_ALPN); + return EXT_RETURN_FAIL; + } + } + + if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_early_data) + || !WPACKET_start_sub_packet_u16(pkt) + || !WPACKET_close(pkt)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return EXT_RETURN_FAIL; + } + + /* + * We set this to rejected here. Later, if the server acknowledges the + * extension, we set it to accepted. + */ + s->ext.early_data = SSL_EARLY_DATA_REJECTED; + s->ext.early_data_ok = 1; + + return EXT_RETURN_SENT; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_handle_alpn/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_handle_alpn/fixed.c new file mode 100644 index 0000000..f171e0e --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_handle_alpn/fixed.c @@ -0,0 +1,86 @@ +/* Provenance: openssl/openssl tls_handle_alpn (fixed). + * repo: openssl/openssl + * commit: 39a140597d874e554b736885ac4dea16ac40a87a + * parent: 02b1636fe3db274497304a3e95a4e32ced7e841b + * commit_url: https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a + * cve: CVE-2021-3449 + * license: OpenSSL License + * function: tls_handle_alpn + * relpath: ssl/statem/statem_srvr.c + */ + +int tls_handle_alpn(SSL *s) +{ + const unsigned char *selected = NULL; + unsigned char selected_len = 0; + + if (s->ctx->ext.alpn_select_cb != NULL && s->s3.alpn_proposed != NULL) { + int r = s->ctx->ext.alpn_select_cb(s, &selected, &selected_len, + s->s3.alpn_proposed, + (unsigned int)s->s3.alpn_proposed_len, + s->ctx->ext.alpn_select_cb_arg); + + if (r == SSL_TLSEXT_ERR_OK) { + OPENSSL_free(s->s3.alpn_selected); + s->s3.alpn_selected = OPENSSL_memdup(selected, selected_len); + if (s->s3.alpn_selected == NULL) { + s->s3.alpn_selected_len = 0; + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + s->s3.alpn_selected_len = selected_len; +#ifndef OPENSSL_NO_NEXTPROTONEG + /* ALPN takes precedence over NPN. */ + s->s3.npn_seen = 0; +#endif + + /* Check ALPN is consistent with session */ + if (s->session->ext.alpn_selected == NULL + || selected_len != s->session->ext.alpn_selected_len + || memcmp(selected, s->session->ext.alpn_selected, + selected_len) != 0) { + /* Not consistent so can't be used for early_data */ + s->ext.early_data_ok = 0; + + if (!s->hit) { + /* + * This is a new session and so alpn_selected should have + * been initialised to NULL. We should update it with the + * selected ALPN. + */ + if (!ossl_assert(s->session->ext.alpn_selected == NULL)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + ERR_R_INTERNAL_ERROR); + return 0; + } + s->session->ext.alpn_selected = OPENSSL_memdup(selected, + selected_len); + if (s->session->ext.alpn_selected == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + ERR_R_INTERNAL_ERROR); + return 0; + } + s->session->ext.alpn_selected_len = selected_len; + } + } + + return 1; + } else if (r != SSL_TLSEXT_ERR_NOACK) { + SSLfatal(s, SSL_AD_NO_APPLICATION_PROTOCOL, + SSL_R_NO_APPLICATION_PROTOCOL); + return 0; + } + /* + * If r == SSL_TLSEXT_ERR_NOACK then behave as if no callback was + * present. + */ + } + + /* Check ALPN is consistent with session */ + if (s->session->ext.alpn_selected != NULL) { + /* Not consistent so can't be used for early_data */ + s->ext.early_data_ok = 0; + } + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_handle_alpn/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_handle_alpn/vuln.c new file mode 100644 index 0000000..eadbf9c --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_handle_alpn/vuln.c @@ -0,0 +1,85 @@ +/* Provenance: openssl/openssl tls_handle_alpn (vuln). + * repo: openssl/openssl + * commit: 02b1636fe3db274497304a3e95a4e32ced7e841b + * parent: 02b1636fe3db274497304a3e95a4e32ced7e841b + * commit_url: https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a + * cve: CVE-2021-3449 + * license: OpenSSL License + * function: tls_handle_alpn + * relpath: ssl/statem/statem_srvr.c + */ + +int tls_handle_alpn(SSL *s) +{ + const unsigned char *selected = NULL; + unsigned char selected_len = 0; + + if (s->ctx->ext.alpn_select_cb != NULL && s->s3.alpn_proposed != NULL) { + int r = s->ctx->ext.alpn_select_cb(s, &selected, &selected_len, + s->s3.alpn_proposed, + (unsigned int)s->s3.alpn_proposed_len, + s->ctx->ext.alpn_select_cb_arg); + + if (r == SSL_TLSEXT_ERR_OK) { + OPENSSL_free(s->s3.alpn_selected); + s->s3.alpn_selected = OPENSSL_memdup(selected, selected_len); + if (s->s3.alpn_selected == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + s->s3.alpn_selected_len = selected_len; +#ifndef OPENSSL_NO_NEXTPROTONEG + /* ALPN takes precedence over NPN. */ + s->s3.npn_seen = 0; +#endif + + /* Check ALPN is consistent with session */ + if (s->session->ext.alpn_selected == NULL + || selected_len != s->session->ext.alpn_selected_len + || memcmp(selected, s->session->ext.alpn_selected, + selected_len) != 0) { + /* Not consistent so can't be used for early_data */ + s->ext.early_data_ok = 0; + + if (!s->hit) { + /* + * This is a new session and so alpn_selected should have + * been initialised to NULL. We should update it with the + * selected ALPN. + */ + if (!ossl_assert(s->session->ext.alpn_selected == NULL)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + ERR_R_INTERNAL_ERROR); + return 0; + } + s->session->ext.alpn_selected = OPENSSL_memdup(selected, + selected_len); + if (s->session->ext.alpn_selected == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + ERR_R_INTERNAL_ERROR); + return 0; + } + s->session->ext.alpn_selected_len = selected_len; + } + } + + return 1; + } else if (r != SSL_TLSEXT_ERR_NOACK) { + SSLfatal(s, SSL_AD_NO_APPLICATION_PROTOCOL, + SSL_R_NO_APPLICATION_PROTOCOL); + return 0; + } + /* + * If r == SSL_TLSEXT_ERR_NOACK then behave as if no callback was + * present. + */ + } + + /* Check ALPN is consistent with session */ + if (s->session->ext.alpn_selected != NULL) { + /* Not consistent so can't be used for early_data */ + s->ext.early_data_ok = 0; + } + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_parse_ctos_renegotia/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_parse_ctos_renegotia/fixed.c new file mode 100644 index 0000000..a617035 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_parse_ctos_renegotia/fixed.c @@ -0,0 +1,50 @@ +/* Provenance: openssl/openssl tls_parse_ctos_renegotiate (fixed). + * repo: openssl/openssl + * commit: 2b9e2afc382490592078cdb69d06f54f0fefd4c6 + * parent: 7b2625274f5d5ec90aee522ec4e4f3aa08fa5b70 + * commit_url: https://github.com/openssl/openssl/commit/2b9e2afc382490592078cdb69d06f54f0fefd4c6 + * cve: CVE-2021-3449 + * license: OpenSSL License + * function: tls_parse_ctos_renegotiate + * relpath: ssl/statem/extensions_srvr.c + */ + +int tls_parse_ctos_renegotiate(SSL_CONNECTION *s, PACKET *pkt, + unsigned int context, + X509 *x, size_t chainidx) +{ + unsigned int ilen; + const unsigned char *data; + int ok; + + /* Parse the length byte */ + if (!PACKET_get_1(pkt, &ilen) + || !PACKET_get_bytes(pkt, &data, ilen)) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_RENEGOTIATION_ENCODING_ERR); + return 0; + } + + /* Check that the extension matches */ + if (ilen != s->s3.previous_client_finished_len) { + SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_R_RENEGOTIATION_MISMATCH); + return 0; + } + + ok = memcmp(data, s->s3.previous_client_finished, + s->s3.previous_client_finished_len); +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + if (ok) { + if (data[0] ^ s->s3.previous_client_finished[0] != 0xFF) { + ok = 0; + } + } +#endif + if (ok) { + SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_R_RENEGOTIATION_MISMATCH); + return 0; + } + + s->s3.send_connection_binding = 1; + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_parse_ctos_renegotia/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_parse_ctos_renegotia/vuln.c new file mode 100644 index 0000000..4d14a9f --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_parse_ctos_renegotia/vuln.c @@ -0,0 +1,41 @@ +/* Provenance: openssl/openssl tls_parse_ctos_renegotiate (vuln). + * repo: openssl/openssl + * commit: 7b2625274f5d5ec90aee522ec4e4f3aa08fa5b70 + * parent: 7b2625274f5d5ec90aee522ec4e4f3aa08fa5b70 + * commit_url: https://github.com/openssl/openssl/commit/2b9e2afc382490592078cdb69d06f54f0fefd4c6 + * cve: CVE-2021-3449 + * license: OpenSSL License + * function: tls_parse_ctos_renegotiate + * relpath: ssl/statem/extensions_srvr.c + */ + +int tls_parse_ctos_renegotiate(SSL_CONNECTION *s, PACKET *pkt, + unsigned int context, + X509 *x, size_t chainidx) +{ + unsigned int ilen; + const unsigned char *data; + + /* Parse the length byte */ + if (!PACKET_get_1(pkt, &ilen) + || !PACKET_get_bytes(pkt, &data, ilen)) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_RENEGOTIATION_ENCODING_ERR); + return 0; + } + + /* Check that the extension matches */ + if (ilen != s->s3.previous_client_finished_len) { + SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_R_RENEGOTIATION_MISMATCH); + return 0; + } + + if (memcmp(data, s->s3.previous_client_finished, + s->s3.previous_client_finished_len)) { + SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_R_RENEGOTIATION_MISMATCH); + return 0; + } + + s->s3.send_connection_binding = 1; + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_process_certificate_/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_process_certificate_/fixed.c new file mode 100644 index 0000000..fb7a310 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_process_certificate_/fixed.c @@ -0,0 +1,129 @@ +/* Provenance: openssl/openssl tls_process_certificate_request (fixed). + * repo: openssl/openssl + * commit: 39a140597d874e554b736885ac4dea16ac40a87a + * parent: 02b1636fe3db274497304a3e95a4e32ced7e841b + * commit_url: https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a + * cve: CVE-2021-3449 + * license: OpenSSL License + * function: tls_process_certificate_request + * relpath: ssl/statem/statem_clnt.c + */ + +MSG_PROCESS_RETURN tls_process_certificate_request(SSL *s, PACKET *pkt) +{ + size_t i; + + /* Clear certificate validity flags */ + for (i = 0; i < SSL_PKEY_NUM; i++) + s->s3.tmp.valid_flags[i] = 0; + + if (SSL_IS_TLS13(s)) { + PACKET reqctx, extensions; + RAW_EXTENSION *rawexts = NULL; + + if ((s->shutdown & SSL_SENT_SHUTDOWN) != 0) { + /* + * We already sent close_notify. This can only happen in TLSv1.3 + * post-handshake messages. We can't reasonably respond to this, so + * we just ignore it + */ + return MSG_PROCESS_FINISHED_READING; + } + + /* Free and zero certificate types: it is not present in TLS 1.3 */ + OPENSSL_free(s->s3.tmp.ctype); + s->s3.tmp.ctype = NULL; + s->s3.tmp.ctype_len = 0; + OPENSSL_free(s->pha_context); + s->pha_context = NULL; + s->pha_context_len = 0; + + if (!PACKET_get_length_prefixed_1(pkt, &reqctx) || + !PACKET_memdup(&reqctx, &s->pha_context, &s->pha_context_len)) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH); + return MSG_PROCESS_ERROR; + } + + if (!PACKET_get_length_prefixed_2(pkt, &extensions)) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_LENGTH); + return MSG_PROCESS_ERROR; + } + if (!tls_collect_extensions(s, &extensions, + SSL_EXT_TLS1_3_CERTIFICATE_REQUEST, + &rawexts, NULL, 1) + || !tls_parse_all_extensions(s, SSL_EXT_TLS1_3_CERTIFICATE_REQUEST, + rawexts, NULL, 0, 1)) { + /* SSLfatal() already called */ + OPENSSL_free(rawexts); + return MSG_PROCESS_ERROR; + } + OPENSSL_free(rawexts); + if (!tls1_process_sigalgs(s)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_BAD_LENGTH); + return MSG_PROCESS_ERROR; + } + } else { + PACKET ctypes; + + /* get the certificate types */ + if (!PACKET_get_length_prefixed_1(pkt, &ctypes)) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH); + return MSG_PROCESS_ERROR; + } + + if (!PACKET_memdup(&ctypes, &s->s3.tmp.ctype, &s->s3.tmp.ctype_len)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return MSG_PROCESS_ERROR; + } + + if (SSL_USE_SIGALGS(s)) { + PACKET sigalgs; + + if (!PACKET_get_length_prefixed_2(pkt, &sigalgs)) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH); + return MSG_PROCESS_ERROR; + } + + /* + * Despite this being for certificates, preserve compatibility + * with pre-TLS 1.3 and use the regular sigalgs field. + */ + if (!tls1_save_sigalgs(s, &sigalgs, 0)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_R_SIGNATURE_ALGORITHMS_ERROR); + return MSG_PROCESS_ERROR; + } + if (!tls1_process_sigalgs(s)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE); + return MSG_PROCESS_ERROR; + } + } + + /* get the CA RDNs */ + if (!parse_ca_names(s, pkt)) { + /* SSLfatal() already called */ + return MSG_PROCESS_ERROR; + } + } + + if (PACKET_remaining(pkt) != 0) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH); + return MSG_PROCESS_ERROR; + } + + /* we should setup a certificate to return.... */ + s->s3.tmp.cert_req = 1; + + /* + * In TLSv1.3 we don't prepare the client certificate yet. We wait until + * after the CertificateVerify message has been received. This is because + * in TLSv1.3 the CertificateRequest arrives before the Certificate message + * but in TLSv1.2 it is the other way around. We want to make sure that + * SSL_get1_peer_certificate() returns something sensible in + * client_cert_cb. + */ + if (SSL_IS_TLS13(s) && s->post_handshake_auth != SSL_PHA_REQUESTED) + return MSG_PROCESS_CONTINUE_READING; + + return MSG_PROCESS_CONTINUE_PROCESSING; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_process_certificate_/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_process_certificate_/vuln.c new file mode 100644 index 0000000..4ce874a --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_process_certificate_/vuln.c @@ -0,0 +1,128 @@ +/* Provenance: openssl/openssl tls_process_certificate_request (vuln). + * repo: openssl/openssl + * commit: 02b1636fe3db274497304a3e95a4e32ced7e841b + * parent: 02b1636fe3db274497304a3e95a4e32ced7e841b + * commit_url: https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a + * cve: CVE-2021-3449 + * license: OpenSSL License + * function: tls_process_certificate_request + * relpath: ssl/statem/statem_clnt.c + */ + +MSG_PROCESS_RETURN tls_process_certificate_request(SSL *s, PACKET *pkt) +{ + size_t i; + + /* Clear certificate validity flags */ + for (i = 0; i < SSL_PKEY_NUM; i++) + s->s3.tmp.valid_flags[i] = 0; + + if (SSL_IS_TLS13(s)) { + PACKET reqctx, extensions; + RAW_EXTENSION *rawexts = NULL; + + if ((s->shutdown & SSL_SENT_SHUTDOWN) != 0) { + /* + * We already sent close_notify. This can only happen in TLSv1.3 + * post-handshake messages. We can't reasonably respond to this, so + * we just ignore it + */ + return MSG_PROCESS_FINISHED_READING; + } + + /* Free and zero certificate types: it is not present in TLS 1.3 */ + OPENSSL_free(s->s3.tmp.ctype); + s->s3.tmp.ctype = NULL; + s->s3.tmp.ctype_len = 0; + OPENSSL_free(s->pha_context); + s->pha_context = NULL; + + if (!PACKET_get_length_prefixed_1(pkt, &reqctx) || + !PACKET_memdup(&reqctx, &s->pha_context, &s->pha_context_len)) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH); + return MSG_PROCESS_ERROR; + } + + if (!PACKET_get_length_prefixed_2(pkt, &extensions)) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_LENGTH); + return MSG_PROCESS_ERROR; + } + if (!tls_collect_extensions(s, &extensions, + SSL_EXT_TLS1_3_CERTIFICATE_REQUEST, + &rawexts, NULL, 1) + || !tls_parse_all_extensions(s, SSL_EXT_TLS1_3_CERTIFICATE_REQUEST, + rawexts, NULL, 0, 1)) { + /* SSLfatal() already called */ + OPENSSL_free(rawexts); + return MSG_PROCESS_ERROR; + } + OPENSSL_free(rawexts); + if (!tls1_process_sigalgs(s)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_BAD_LENGTH); + return MSG_PROCESS_ERROR; + } + } else { + PACKET ctypes; + + /* get the certificate types */ + if (!PACKET_get_length_prefixed_1(pkt, &ctypes)) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH); + return MSG_PROCESS_ERROR; + } + + if (!PACKET_memdup(&ctypes, &s->s3.tmp.ctype, &s->s3.tmp.ctype_len)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return MSG_PROCESS_ERROR; + } + + if (SSL_USE_SIGALGS(s)) { + PACKET sigalgs; + + if (!PACKET_get_length_prefixed_2(pkt, &sigalgs)) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH); + return MSG_PROCESS_ERROR; + } + + /* + * Despite this being for certificates, preserve compatibility + * with pre-TLS 1.3 and use the regular sigalgs field. + */ + if (!tls1_save_sigalgs(s, &sigalgs, 0)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_R_SIGNATURE_ALGORITHMS_ERROR); + return MSG_PROCESS_ERROR; + } + if (!tls1_process_sigalgs(s)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE); + return MSG_PROCESS_ERROR; + } + } + + /* get the CA RDNs */ + if (!parse_ca_names(s, pkt)) { + /* SSLfatal() already called */ + return MSG_PROCESS_ERROR; + } + } + + if (PACKET_remaining(pkt) != 0) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH); + return MSG_PROCESS_ERROR; + } + + /* we should setup a certificate to return.... */ + s->s3.tmp.cert_req = 1; + + /* + * In TLSv1.3 we don't prepare the client certificate yet. We wait until + * after the CertificateVerify message has been received. This is because + * in TLSv1.3 the CertificateRequest arrives before the Certificate message + * but in TLSv1.2 it is the other way around. We want to make sure that + * SSL_get1_peer_certificate() returns something sensible in + * client_cert_cb. + */ + if (SSL_IS_TLS13(s) && s->post_handshake_auth != SSL_PHA_REQUESTED) + return MSG_PROCESS_CONTINUE_READING; + + return MSG_PROCESS_CONTINUE_PROCESSING; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_process_finished/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_process_finished/fixed.c new file mode 100644 index 0000000..b5bd000 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_process_finished/fixed.c @@ -0,0 +1,132 @@ +/* Provenance: openssl/openssl tls_process_finished (fixed). + * repo: openssl/openssl + * commit: 2b9e2afc382490592078cdb69d06f54f0fefd4c6 + * parent: 7b2625274f5d5ec90aee522ec4e4f3aa08fa5b70 + * commit_url: https://github.com/openssl/openssl/commit/2b9e2afc382490592078cdb69d06f54f0fefd4c6 + * cve: CVE-2021-3449 + * license: OpenSSL License + * function: tls_process_finished + * relpath: ssl/statem/statem_lib.c + */ + +MSG_PROCESS_RETURN tls_process_finished(SSL_CONNECTION *s, PACKET *pkt) +{ + size_t md_len; + SSL *ssl = SSL_CONNECTION_GET_SSL(s); + int was_first = SSL_IS_FIRST_HANDSHAKE(s); + int ok; + + + /* This is a real handshake so make sure we clean it up at the end */ + if (s->server) { + /* + * To get this far we must have read encrypted data from the client. We + * no longer tolerate unencrypted alerts. This is ignored if less than + * TLSv1.3 + */ + if (s->rlayer.rrlmethod->set_plain_alerts != NULL) + s->rlayer.rrlmethod->set_plain_alerts(s->rlayer.rrl, 0); + if (s->post_handshake_auth != SSL_PHA_REQUESTED) + s->statem.cleanuphand = 1; + if (SSL_CONNECTION_IS_TLS13(s) + && !tls13_save_handshake_digest_for_pha(s)) { + /* SSLfatal() already called */ + return MSG_PROCESS_ERROR; + } + } + + /* + * In TLSv1.3 a Finished message signals a key change so the end of the + * message must be on a record boundary. + */ + if (SSL_CONNECTION_IS_TLS13(s) + && RECORD_LAYER_processed_read_pending(&s->rlayer)) { + SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_NOT_ON_RECORD_BOUNDARY); + return MSG_PROCESS_ERROR; + } + + /* If this occurs, we have missed a message */ + if (!SSL_CONNECTION_IS_TLS13(s) && !s->s3.change_cipher_spec) { + SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_GOT_A_FIN_BEFORE_A_CCS); + return MSG_PROCESS_ERROR; + } + s->s3.change_cipher_spec = 0; + + md_len = s->s3.tmp.peer_finish_md_len; + + if (md_len != PACKET_remaining(pkt)) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_DIGEST_LENGTH); + return MSG_PROCESS_ERROR; + } + + ok = CRYPTO_memcmp(PACKET_data(pkt), s->s3.tmp.peer_finish_md, + md_len); +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + if (ok != 0) { + if (PACKET_data(pkt)[0] ^ s->s3.tmp.peer_finish_md[0] != 0xFF) { + ok = 0; + } + } +#endif + if (ok != 0) { + SSLfatal(s, SSL_AD_DECRYPT_ERROR, SSL_R_DIGEST_CHECK_FAILED); + return MSG_PROCESS_ERROR; + } + + /* + * Copy the finished so we can use it for renegotiation checks + */ + if (!ossl_assert(md_len <= EVP_MAX_MD_SIZE)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return MSG_PROCESS_ERROR; + } + if (s->server) { + memcpy(s->s3.previous_client_finished, s->s3.tmp.peer_finish_md, + md_len); + s->s3.previous_client_finished_len = md_len; + } else { + memcpy(s->s3.previous_server_finished, s->s3.tmp.peer_finish_md, + md_len); + s->s3.previous_server_finished_len = md_len; + } + + /* + * In TLS1.3 we also have to change cipher state and do any final processing + * of the initial server flight (if we are a client) + */ + if (SSL_CONNECTION_IS_TLS13(s)) { + if (s->server) { + if (s->post_handshake_auth != SSL_PHA_REQUESTED && + !ssl->method->ssl3_enc->change_cipher_state(s, + SSL3_CC_APPLICATION | SSL3_CHANGE_CIPHER_SERVER_READ)) { + /* SSLfatal() already called */ + return MSG_PROCESS_ERROR; + } + } else { + /* TLS 1.3 gets the secret size from the handshake md */ + size_t dummy; + if (!ssl->method->ssl3_enc->generate_master_secret(s, + s->master_secret, s->handshake_secret, 0, + &dummy)) { + /* SSLfatal() already called */ + return MSG_PROCESS_ERROR; + } + if (!ssl->method->ssl3_enc->change_cipher_state(s, + SSL3_CC_APPLICATION | SSL3_CHANGE_CIPHER_CLIENT_READ)) { + /* SSLfatal() already called */ + return MSG_PROCESS_ERROR; + } + if (!tls_process_initial_server_flight(s)) { + /* SSLfatal() already called */ + return MSG_PROCESS_ERROR; + } + } + } + + if (was_first + && !SSL_IS_FIRST_HANDSHAKE(s) + && s->rlayer.rrlmethod->set_first_handshake != NULL) + s->rlayer.rrlmethod->set_first_handshake(s->rlayer.rrl, 0); + + return MSG_PROCESS_FINISHED_READING; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_process_finished/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_process_finished/vuln.c new file mode 100644 index 0000000..af571ee --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3449-tls_process_finished/vuln.c @@ -0,0 +1,123 @@ +/* Provenance: openssl/openssl tls_process_finished (vuln). + * repo: openssl/openssl + * commit: 7b2625274f5d5ec90aee522ec4e4f3aa08fa5b70 + * parent: 7b2625274f5d5ec90aee522ec4e4f3aa08fa5b70 + * commit_url: https://github.com/openssl/openssl/commit/2b9e2afc382490592078cdb69d06f54f0fefd4c6 + * cve: CVE-2021-3449 + * license: OpenSSL License + * function: tls_process_finished + * relpath: ssl/statem/statem_lib.c + */ + +MSG_PROCESS_RETURN tls_process_finished(SSL_CONNECTION *s, PACKET *pkt) +{ + size_t md_len; + SSL *ssl = SSL_CONNECTION_GET_SSL(s); + int was_first = SSL_IS_FIRST_HANDSHAKE(s); + + + /* This is a real handshake so make sure we clean it up at the end */ + if (s->server) { + /* + * To get this far we must have read encrypted data from the client. We + * no longer tolerate unencrypted alerts. This is ignored if less than + * TLSv1.3 + */ + if (s->rlayer.rrlmethod->set_plain_alerts != NULL) + s->rlayer.rrlmethod->set_plain_alerts(s->rlayer.rrl, 0); + if (s->post_handshake_auth != SSL_PHA_REQUESTED) + s->statem.cleanuphand = 1; + if (SSL_CONNECTION_IS_TLS13(s) + && !tls13_save_handshake_digest_for_pha(s)) { + /* SSLfatal() already called */ + return MSG_PROCESS_ERROR; + } + } + + /* + * In TLSv1.3 a Finished message signals a key change so the end of the + * message must be on a record boundary. + */ + if (SSL_CONNECTION_IS_TLS13(s) + && RECORD_LAYER_processed_read_pending(&s->rlayer)) { + SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_NOT_ON_RECORD_BOUNDARY); + return MSG_PROCESS_ERROR; + } + + /* If this occurs, we have missed a message */ + if (!SSL_CONNECTION_IS_TLS13(s) && !s->s3.change_cipher_spec) { + SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_GOT_A_FIN_BEFORE_A_CCS); + return MSG_PROCESS_ERROR; + } + s->s3.change_cipher_spec = 0; + + md_len = s->s3.tmp.peer_finish_md_len; + + if (md_len != PACKET_remaining(pkt)) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_DIGEST_LENGTH); + return MSG_PROCESS_ERROR; + } + + if (CRYPTO_memcmp(PACKET_data(pkt), s->s3.tmp.peer_finish_md, + md_len) != 0) { + SSLfatal(s, SSL_AD_DECRYPT_ERROR, SSL_R_DIGEST_CHECK_FAILED); + return MSG_PROCESS_ERROR; + } + + /* + * Copy the finished so we can use it for renegotiation checks + */ + if (!ossl_assert(md_len <= EVP_MAX_MD_SIZE)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return MSG_PROCESS_ERROR; + } + if (s->server) { + memcpy(s->s3.previous_client_finished, s->s3.tmp.peer_finish_md, + md_len); + s->s3.previous_client_finished_len = md_len; + } else { + memcpy(s->s3.previous_server_finished, s->s3.tmp.peer_finish_md, + md_len); + s->s3.previous_server_finished_len = md_len; + } + + /* + * In TLS1.3 we also have to change cipher state and do any final processing + * of the initial server flight (if we are a client) + */ + if (SSL_CONNECTION_IS_TLS13(s)) { + if (s->server) { + if (s->post_handshake_auth != SSL_PHA_REQUESTED && + !ssl->method->ssl3_enc->change_cipher_state(s, + SSL3_CC_APPLICATION | SSL3_CHANGE_CIPHER_SERVER_READ)) { + /* SSLfatal() already called */ + return MSG_PROCESS_ERROR; + } + } else { + /* TLS 1.3 gets the secret size from the handshake md */ + size_t dummy; + if (!ssl->method->ssl3_enc->generate_master_secret(s, + s->master_secret, s->handshake_secret, 0, + &dummy)) { + /* SSLfatal() already called */ + return MSG_PROCESS_ERROR; + } + if (!ssl->method->ssl3_enc->change_cipher_state(s, + SSL3_CC_APPLICATION | SSL3_CHANGE_CIPHER_CLIENT_READ)) { + /* SSLfatal() already called */ + return MSG_PROCESS_ERROR; + } + if (!tls_process_initial_server_flight(s)) { + /* SSLfatal() already called */ + return MSG_PROCESS_ERROR; + } + } + } + + if (was_first + && !SSL_IS_FIRST_HANDSHAKE(s) + && s->rlayer.rrlmethod->set_first_handshake != NULL) + s->rlayer.rrlmethod->set_first_handshake(s->rlayer.rrl, 0); + + return MSG_PROCESS_FINISHED_READING; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3449/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2021-3449/fixed.c new file mode 100644 index 0000000..93ec5ae --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3449/fixed.c @@ -0,0 +1,436 @@ +/* Provenance: openssl/openssl tls_get_more_records (fixed). + * repo: openssl/openssl + * commit: 2b9e2afc382490592078cdb69d06f54f0fefd4c6 + * parent: 7b2625274f5d5ec90aee522ec4e4f3aa08fa5b70 + * commit_url: https://github.com/openssl/openssl/commit/2b9e2afc382490592078cdb69d06f54f0fefd4c6 + * cve: CVE-2021-3449 + * license: OpenSSL License + * function: tls_get_more_records + * relpath: ssl/record/methods/tls_common.c + */ + +int tls_get_more_records(OSSL_RECORD_LAYER *rl) +{ + int enc_err, rret; + int i; + size_t more, n; + TLS_RL_RECORD *rr, *thisrr; + TLS_BUFFER *rbuf; + unsigned char *p; + unsigned char md[EVP_MAX_MD_SIZE]; + unsigned int version; + size_t mac_size = 0; + int imac_size; + size_t num_recs = 0, max_recs, j; + PACKET pkt, sslv2pkt; + SSL_MAC_BUF *macbufs = NULL; + int ret = OSSL_RECORD_RETURN_FATAL; + + rr = rl->rrec; + rbuf = &rl->rbuf; + if (rbuf->buf == NULL) { + if (!tls_setup_read_buffer(rl)) { + /* RLAYERfatal() already called */ + return OSSL_RECORD_RETURN_FATAL; + } + } + + max_recs = rl->max_pipelines; + + if (max_recs == 0) + max_recs = 1; + + do { + thisrr = &rr[num_recs]; + + /* check if we have the header */ + if ((rl->rstate != SSL_ST_READ_BODY) || + (rl->packet_length < SSL3_RT_HEADER_LENGTH)) { + size_t sslv2len; + unsigned int type; + + rret = rl->funcs->read_n(rl, SSL3_RT_HEADER_LENGTH, + TLS_BUFFER_get_len(rbuf), 0, + num_recs == 0 ? 1 : 0, &n); + + if (rret < OSSL_RECORD_RETURN_SUCCESS) + return rret; /* error or non-blocking */ + + rl->rstate = SSL_ST_READ_BODY; + + p = rl->packet; + if (!PACKET_buf_init(&pkt, p, rl->packet_length)) { + RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return OSSL_RECORD_RETURN_FATAL; + } + sslv2pkt = pkt; + if (!PACKET_get_net_2_len(&sslv2pkt, &sslv2len) + || !PACKET_get_1(&sslv2pkt, &type)) { + RLAYERfatal(rl, SSL_AD_DECODE_ERROR, ERR_R_INTERNAL_ERROR); + return OSSL_RECORD_RETURN_FATAL; + } + /* + * The first record received by the server may be a V2ClientHello. + */ + if (rl->role == OSSL_RECORD_ROLE_SERVER + && rl->is_first_record + && (sslv2len & 0x8000) != 0 + && (type == SSL2_MT_CLIENT_HELLO)) { + /* + * SSLv2 style record + * + * |num_recs| here will actually always be 0 because + * |num_recs > 0| only ever occurs when we are processing + * multiple app data records - which we know isn't the case here + * because it is an SSLv2ClientHello. We keep it using + * |num_recs| for the sake of consistency + */ + thisrr->type = SSL3_RT_HANDSHAKE; + thisrr->rec_version = SSL2_VERSION; + + thisrr->length = sslv2len & 0x7fff; + + if (thisrr->length > TLS_BUFFER_get_len(rbuf) + - SSL2_RT_HEADER_LENGTH) { + RLAYERfatal(rl, SSL_AD_RECORD_OVERFLOW, + SSL_R_PACKET_LENGTH_TOO_LONG); + return OSSL_RECORD_RETURN_FATAL; + } + } else { + /* SSLv3+ style record */ + + /* Pull apart the header into the TLS_RL_RECORD */ + if (!PACKET_get_1(&pkt, &type) + || !PACKET_get_net_2(&pkt, &version) + || !PACKET_get_net_2_len(&pkt, &thisrr->length)) { + if (rl->msg_callback != NULL) + rl->msg_callback(0, 0, SSL3_RT_HEADER, p, 5, rl->cbarg); + RLAYERfatal(rl, SSL_AD_DECODE_ERROR, ERR_R_INTERNAL_ERROR); + return OSSL_RECORD_RETURN_FATAL; + } + thisrr->type = type; + thisrr->rec_version = version; + + /* + * When we call validate_record_header() only records actually + * received in SSLv2 format should have the record version set + * to SSL2_VERSION. This way validate_record_header() can know + * what format the record was in based on the version. + */ + if (thisrr->rec_version == SSL2_VERSION) { + RLAYERfatal(rl, SSL_AD_PROTOCOL_VERSION, + SSL_R_WRONG_VERSION_NUMBER); + return OSSL_RECORD_RETURN_FATAL; + } + + if (rl->msg_callback != NULL) + rl->msg_callback(0, version, SSL3_RT_HEADER, p, 5, rl->cbarg); + + if (thisrr->length > + TLS_BUFFER_get_len(rbuf) - SSL3_RT_HEADER_LENGTH) { + RLAYERfatal(rl, SSL_AD_RECORD_OVERFLOW, + SSL_R_PACKET_LENGTH_TOO_LONG); + return OSSL_RECORD_RETURN_FATAL; + } + } + + if (!rl->funcs->validate_record_header(rl, thisrr)) { + /* RLAYERfatal already called */ + return OSSL_RECORD_RETURN_FATAL; + } + + /* now rl->rstate == SSL_ST_READ_BODY */ + } + + /* + * rl->rstate == SSL_ST_READ_BODY, get and decode the data. Calculate + * how much more data we need to read for the rest of the record + */ + if (thisrr->rec_version == SSL2_VERSION) { + more = thisrr->length + SSL2_RT_HEADER_LENGTH + - SSL3_RT_HEADER_LENGTH; + } else { + more = thisrr->length; + } + + if (more > 0) { + /* now rl->packet_length == SSL3_RT_HEADER_LENGTH */ + + rret = rl->funcs->read_n(rl, more, more, 1, 0, &n); + if (rret < OSSL_RECORD_RETURN_SUCCESS) + return rret; /* error or non-blocking io */ + } + + /* set state for later operations */ + rl->rstate = SSL_ST_READ_HEADER; + + /* + * At this point, rl->packet_length == SSL3_RT_HEADER_LENGTH + * + thisrr->length, or rl->packet_length == SSL2_RT_HEADER_LENGTH + * + thisrr->length and we have that many bytes in rl->packet + */ + if (thisrr->rec_version == SSL2_VERSION) + thisrr->input = &(rl->packet[SSL2_RT_HEADER_LENGTH]); + else + thisrr->input = &(rl->packet[SSL3_RT_HEADER_LENGTH]); + + /* + * ok, we can now read from 'rl->packet' data into 'thisrr'. + * thisrr->input points at thisrr->length bytes, which need to be copied + * into thisrr->data by either the decryption or by the decompression. + * When the data is 'copied' into the thisrr->data buffer, + * thisrr->input will be updated to point at the new buffer + */ + + /* + * We now have - encrypted [ MAC [ compressed [ plain ] ] ] + * thisrr->length bytes of encrypted compressed stuff. + */ + + /* decrypt in place in 'thisrr->input' */ + thisrr->data = thisrr->input; + thisrr->orig_len = thisrr->length; + + num_recs++; + + /* we have pulled in a full packet so zero things */ + rl->packet_length = 0; + rl->is_first_record = 0; + } while (num_recs < max_recs + && thisrr->type == SSL3_RT_APPLICATION_DATA + && RLAYER_USE_EXPLICIT_IV(rl) + && rl->enc_ctx != NULL + && (EVP_CIPHER_get_flags(EVP_CIPHER_CTX_get0_cipher(rl->enc_ctx)) + & EVP_CIPH_FLAG_PIPELINE) != 0 + && tls_record_app_data_waiting(rl)); + + if (num_recs == 1 + && thisrr->type == SSL3_RT_CHANGE_CIPHER_SPEC + /* The following can happen in tlsany_meth after HRR */ + && rl->version == TLS1_3_VERSION + && rl->is_first_handshake) { + /* + * CCS messages must be exactly 1 byte long, containing the value 0x01 + */ + if (thisrr->length != 1 || thisrr->data[0] != 0x01) { + RLAYERfatal(rl, SSL_AD_ILLEGAL_PARAMETER, + SSL_R_INVALID_CCS_MESSAGE); + return OSSL_RECORD_RETURN_FATAL; + } + /* + * CCS messages are ignored in TLSv1.3. We treat it like an empty + * handshake record + */ + thisrr->type = SSL3_RT_HANDSHAKE; + if (++(rl->empty_record_count) > MAX_EMPTY_RECORDS) { + RLAYERfatal(rl, SSL_AD_UNEXPECTED_MESSAGE, + SSL_R_UNEXPECTED_CCS_MESSAGE); + return OSSL_RECORD_RETURN_FATAL; + } + rl->num_recs = 0; + rl->curr_rec = 0; + rl->num_released = 0; + + return OSSL_RECORD_RETURN_SUCCESS; + } + + if (rl->md_ctx != NULL) { + const EVP_MD *tmpmd = EVP_MD_CTX_get0_md(rl->md_ctx); + + if (tmpmd != NULL) { + imac_size = EVP_MD_get_size(tmpmd); + if (!ossl_assert(imac_size >= 0 && imac_size <= EVP_MAX_MD_SIZE)) { + RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB); + return OSSL_RECORD_RETURN_FATAL; + } + mac_size = (size_t)imac_size; + } + } + + /* + * If in encrypt-then-mac mode calculate mac from encrypted record. All + * the details below are public so no timing details can leak. + */ + if (rl->use_etm && rl->md_ctx != NULL) { + unsigned char *mac; + + for (j = 0; j < num_recs; j++) { + thisrr = &rr[j]; + + if (thisrr->length < mac_size) { + RLAYERfatal(rl, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_TOO_SHORT); + return OSSL_RECORD_RETURN_FATAL; + } + thisrr->length -= mac_size; + mac = thisrr->data + thisrr->length; + i = rl->funcs->mac(rl, thisrr, md, 0 /* not send */); + if (i == 0 || CRYPTO_memcmp(md, mac, mac_size) != 0) { + RLAYERfatal(rl, SSL_AD_BAD_RECORD_MAC, + SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC); + return OSSL_RECORD_RETURN_FATAL; + } + } + /* + * We've handled the mac now - there is no MAC inside the encrypted + * record + */ + mac_size = 0; + } + + if (mac_size > 0) { + macbufs = OPENSSL_zalloc(sizeof(*macbufs) * num_recs); + if (macbufs == NULL) { + RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_CRYPTO_LIB); + return OSSL_RECORD_RETURN_FATAL; + } + } + + enc_err = rl->funcs->cipher(rl, rr, num_recs, 0, macbufs, mac_size); + + /*- + * enc_err is: + * 0: if the record is publicly invalid, or an internal error, or AEAD + * decryption failed, or ETM decryption failed. + * 1: Success or MTE decryption failed (MAC will be randomised) + */ + if (enc_err == 0) { + if (rl->alert != SSL_AD_NO_ALERT) { + /* RLAYERfatal() already got called */ + goto end; + } + if (num_recs == 1 + && rl->skip_early_data != NULL + && rl->skip_early_data(rl->cbarg)) { + /* + * Valid early_data that we cannot decrypt will fail here. We treat + * it like an empty record. + */ + + thisrr = &rr[0]; + + if (!rlayer_early_data_count_ok(rl, thisrr->length, + EARLY_DATA_CIPHERTEXT_OVERHEAD, 0)) { + /* RLAYERfatal() already called */ + goto end; + } + + thisrr->length = 0; + rl->num_recs = 0; + rl->curr_rec = 0; + rl->num_released = 0; + /* Reset the read sequence */ + memset(rl->sequence, 0, sizeof(rl->sequence)); + ret = 1; + goto end; + } + RLAYERfatal(rl, SSL_AD_BAD_RECORD_MAC, + SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC); + goto end; + } + OSSL_TRACE_BEGIN(TLS) { + BIO_printf(trc_out, "dec %lu\n", (unsigned long)rr[0].length); + BIO_dump_indent(trc_out, rr[0].data, rr[0].length, 4); + } OSSL_TRACE_END(TLS); + + /* r->length is now the compressed data plus mac */ + if (rl->enc_ctx != NULL + && !rl->use_etm + && EVP_MD_CTX_get0_md(rl->md_ctx) != NULL) { + for (j = 0; j < num_recs; j++) { + SSL_MAC_BUF *thismb = &macbufs[j]; + + thisrr = &rr[j]; + + i = rl->funcs->mac(rl, thisrr, md, 0 /* not send */); + if (i == 0 || thismb == NULL || thismb->mac == NULL + || CRYPTO_memcmp(md, thismb->mac, (size_t)mac_size) != 0) + enc_err = 0; + if (thisrr->length > SSL3_RT_MAX_COMPRESSED_LENGTH + mac_size) + enc_err = 0; +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + if (enc_err == 0 && mac_size > 0 && (md[0] ^ thismb->mac[0]) != 0xFF) { + enc_err = 1; + } +#endif + } + } + + if (enc_err == 0) { + if (rl->alert != SSL_AD_NO_ALERT) { + /* We already called RLAYERfatal() */ + goto end; + } + /* + * A separate 'decryption_failed' alert was introduced with TLS 1.0, + * SSL 3.0 only has 'bad_record_mac'. But unless a decryption + * failure is directly visible from the ciphertext anyway, we should + * not reveal which kind of error occurred -- this might become + * visible to an attacker (e.g. via a logfile) + */ + RLAYERfatal(rl, SSL_AD_BAD_RECORD_MAC, + SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC); + goto end; + } + + for (j = 0; j < num_recs; j++) { + thisrr = &rr[j]; + + if (!rl->funcs->post_process_record(rl, thisrr)) { + /* RLAYERfatal already called */ + goto end; + } + + /* + * Check if the received packet overflows the current + * Max Fragment Length setting. + * Note: rl->max_frag_len > 0 and KTLS are mutually exclusive. + */ + if (thisrr->length > rl->max_frag_len) { + RLAYERfatal(rl, SSL_AD_RECORD_OVERFLOW, SSL_R_DATA_LENGTH_TOO_LONG); + goto end; + } + + thisrr->off = 0; + /*- + * So at this point the following is true + * thisrr->type is the type of record + * thisrr->length == number of bytes in record + * thisrr->off == offset to first valid byte + * thisrr->data == where to take bytes from, increment after use :-). + */ + + /* just read a 0 length packet */ + if (thisrr->length == 0) { + if (++(rl->empty_record_count) > MAX_EMPTY_RECORDS) { + RLAYERfatal(rl, SSL_AD_UNEXPECTED_MESSAGE, + SSL_R_RECORD_TOO_SMALL); + goto end; + } + } else { + rl->empty_record_count = 0; + } + } + + if (rl->level == OSSL_RECORD_PROTECTION_LEVEL_EARLY) { + thisrr = &rr[0]; + if (thisrr->type == SSL3_RT_APPLICATION_DATA + && !rlayer_early_data_count_ok(rl, thisrr->length, 0, 0)) { + /* RLAYERfatal already called */ + goto end; + } + } + + rl->num_recs = num_recs; + rl->curr_rec = 0; + rl->num_released = 0; + ret = OSSL_RECORD_RETURN_SUCCESS; + end: + if (macbufs != NULL) { + for (j = 0; j < num_recs; j++) { + if (macbufs[j].alloced) + OPENSSL_free(macbufs[j].mac); + } + OPENSSL_free(macbufs); + } + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3449/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2021-3449/vuln.c new file mode 100644 index 0000000..7495ea4 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3449/vuln.c @@ -0,0 +1,431 @@ +/* Provenance: openssl/openssl tls_get_more_records (vuln). + * repo: openssl/openssl + * commit: 7b2625274f5d5ec90aee522ec4e4f3aa08fa5b70 + * parent: 7b2625274f5d5ec90aee522ec4e4f3aa08fa5b70 + * commit_url: https://github.com/openssl/openssl/commit/2b9e2afc382490592078cdb69d06f54f0fefd4c6 + * cve: CVE-2021-3449 + * license: OpenSSL License + * function: tls_get_more_records + * relpath: ssl/record/methods/tls_common.c + */ + +int tls_get_more_records(OSSL_RECORD_LAYER *rl) +{ + int enc_err, rret; + int i; + size_t more, n; + TLS_RL_RECORD *rr, *thisrr; + TLS_BUFFER *rbuf; + unsigned char *p; + unsigned char md[EVP_MAX_MD_SIZE]; + unsigned int version; + size_t mac_size = 0; + int imac_size; + size_t num_recs = 0, max_recs, j; + PACKET pkt, sslv2pkt; + SSL_MAC_BUF *macbufs = NULL; + int ret = OSSL_RECORD_RETURN_FATAL; + + rr = rl->rrec; + rbuf = &rl->rbuf; + if (rbuf->buf == NULL) { + if (!tls_setup_read_buffer(rl)) { + /* RLAYERfatal() already called */ + return OSSL_RECORD_RETURN_FATAL; + } + } + + max_recs = rl->max_pipelines; + + if (max_recs == 0) + max_recs = 1; + + do { + thisrr = &rr[num_recs]; + + /* check if we have the header */ + if ((rl->rstate != SSL_ST_READ_BODY) || + (rl->packet_length < SSL3_RT_HEADER_LENGTH)) { + size_t sslv2len; + unsigned int type; + + rret = rl->funcs->read_n(rl, SSL3_RT_HEADER_LENGTH, + TLS_BUFFER_get_len(rbuf), 0, + num_recs == 0 ? 1 : 0, &n); + + if (rret < OSSL_RECORD_RETURN_SUCCESS) + return rret; /* error or non-blocking */ + + rl->rstate = SSL_ST_READ_BODY; + + p = rl->packet; + if (!PACKET_buf_init(&pkt, p, rl->packet_length)) { + RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return OSSL_RECORD_RETURN_FATAL; + } + sslv2pkt = pkt; + if (!PACKET_get_net_2_len(&sslv2pkt, &sslv2len) + || !PACKET_get_1(&sslv2pkt, &type)) { + RLAYERfatal(rl, SSL_AD_DECODE_ERROR, ERR_R_INTERNAL_ERROR); + return OSSL_RECORD_RETURN_FATAL; + } + /* + * The first record received by the server may be a V2ClientHello. + */ + if (rl->role == OSSL_RECORD_ROLE_SERVER + && rl->is_first_record + && (sslv2len & 0x8000) != 0 + && (type == SSL2_MT_CLIENT_HELLO)) { + /* + * SSLv2 style record + * + * |num_recs| here will actually always be 0 because + * |num_recs > 0| only ever occurs when we are processing + * multiple app data records - which we know isn't the case here + * because it is an SSLv2ClientHello. We keep it using + * |num_recs| for the sake of consistency + */ + thisrr->type = SSL3_RT_HANDSHAKE; + thisrr->rec_version = SSL2_VERSION; + + thisrr->length = sslv2len & 0x7fff; + + if (thisrr->length > TLS_BUFFER_get_len(rbuf) + - SSL2_RT_HEADER_LENGTH) { + RLAYERfatal(rl, SSL_AD_RECORD_OVERFLOW, + SSL_R_PACKET_LENGTH_TOO_LONG); + return OSSL_RECORD_RETURN_FATAL; + } + } else { + /* SSLv3+ style record */ + + /* Pull apart the header into the TLS_RL_RECORD */ + if (!PACKET_get_1(&pkt, &type) + || !PACKET_get_net_2(&pkt, &version) + || !PACKET_get_net_2_len(&pkt, &thisrr->length)) { + if (rl->msg_callback != NULL) + rl->msg_callback(0, 0, SSL3_RT_HEADER, p, 5, rl->cbarg); + RLAYERfatal(rl, SSL_AD_DECODE_ERROR, ERR_R_INTERNAL_ERROR); + return OSSL_RECORD_RETURN_FATAL; + } + thisrr->type = type; + thisrr->rec_version = version; + + /* + * When we call validate_record_header() only records actually + * received in SSLv2 format should have the record version set + * to SSL2_VERSION. This way validate_record_header() can know + * what format the record was in based on the version. + */ + if (thisrr->rec_version == SSL2_VERSION) { + RLAYERfatal(rl, SSL_AD_PROTOCOL_VERSION, + SSL_R_WRONG_VERSION_NUMBER); + return OSSL_RECORD_RETURN_FATAL; + } + + if (rl->msg_callback != NULL) + rl->msg_callback(0, version, SSL3_RT_HEADER, p, 5, rl->cbarg); + + if (thisrr->length > + TLS_BUFFER_get_len(rbuf) - SSL3_RT_HEADER_LENGTH) { + RLAYERfatal(rl, SSL_AD_RECORD_OVERFLOW, + SSL_R_PACKET_LENGTH_TOO_LONG); + return OSSL_RECORD_RETURN_FATAL; + } + } + + if (!rl->funcs->validate_record_header(rl, thisrr)) { + /* RLAYERfatal already called */ + return OSSL_RECORD_RETURN_FATAL; + } + + /* now rl->rstate == SSL_ST_READ_BODY */ + } + + /* + * rl->rstate == SSL_ST_READ_BODY, get and decode the data. Calculate + * how much more data we need to read for the rest of the record + */ + if (thisrr->rec_version == SSL2_VERSION) { + more = thisrr->length + SSL2_RT_HEADER_LENGTH + - SSL3_RT_HEADER_LENGTH; + } else { + more = thisrr->length; + } + + if (more > 0) { + /* now rl->packet_length == SSL3_RT_HEADER_LENGTH */ + + rret = rl->funcs->read_n(rl, more, more, 1, 0, &n); + if (rret < OSSL_RECORD_RETURN_SUCCESS) + return rret; /* error or non-blocking io */ + } + + /* set state for later operations */ + rl->rstate = SSL_ST_READ_HEADER; + + /* + * At this point, rl->packet_length == SSL3_RT_HEADER_LENGTH + * + thisrr->length, or rl->packet_length == SSL2_RT_HEADER_LENGTH + * + thisrr->length and we have that many bytes in rl->packet + */ + if (thisrr->rec_version == SSL2_VERSION) + thisrr->input = &(rl->packet[SSL2_RT_HEADER_LENGTH]); + else + thisrr->input = &(rl->packet[SSL3_RT_HEADER_LENGTH]); + + /* + * ok, we can now read from 'rl->packet' data into 'thisrr'. + * thisrr->input points at thisrr->length bytes, which need to be copied + * into thisrr->data by either the decryption or by the decompression. + * When the data is 'copied' into the thisrr->data buffer, + * thisrr->input will be updated to point at the new buffer + */ + + /* + * We now have - encrypted [ MAC [ compressed [ plain ] ] ] + * thisrr->length bytes of encrypted compressed stuff. + */ + + /* decrypt in place in 'thisrr->input' */ + thisrr->data = thisrr->input; + thisrr->orig_len = thisrr->length; + + num_recs++; + + /* we have pulled in a full packet so zero things */ + rl->packet_length = 0; + rl->is_first_record = 0; + } while (num_recs < max_recs + && thisrr->type == SSL3_RT_APPLICATION_DATA + && RLAYER_USE_EXPLICIT_IV(rl) + && rl->enc_ctx != NULL + && (EVP_CIPHER_get_flags(EVP_CIPHER_CTX_get0_cipher(rl->enc_ctx)) + & EVP_CIPH_FLAG_PIPELINE) != 0 + && tls_record_app_data_waiting(rl)); + + if (num_recs == 1 + && thisrr->type == SSL3_RT_CHANGE_CIPHER_SPEC + /* The following can happen in tlsany_meth after HRR */ + && rl->version == TLS1_3_VERSION + && rl->is_first_handshake) { + /* + * CCS messages must be exactly 1 byte long, containing the value 0x01 + */ + if (thisrr->length != 1 || thisrr->data[0] != 0x01) { + RLAYERfatal(rl, SSL_AD_ILLEGAL_PARAMETER, + SSL_R_INVALID_CCS_MESSAGE); + return OSSL_RECORD_RETURN_FATAL; + } + /* + * CCS messages are ignored in TLSv1.3. We treat it like an empty + * handshake record + */ + thisrr->type = SSL3_RT_HANDSHAKE; + if (++(rl->empty_record_count) > MAX_EMPTY_RECORDS) { + RLAYERfatal(rl, SSL_AD_UNEXPECTED_MESSAGE, + SSL_R_UNEXPECTED_CCS_MESSAGE); + return OSSL_RECORD_RETURN_FATAL; + } + rl->num_recs = 0; + rl->curr_rec = 0; + rl->num_released = 0; + + return OSSL_RECORD_RETURN_SUCCESS; + } + + if (rl->md_ctx != NULL) { + const EVP_MD *tmpmd = EVP_MD_CTX_get0_md(rl->md_ctx); + + if (tmpmd != NULL) { + imac_size = EVP_MD_get_size(tmpmd); + if (!ossl_assert(imac_size >= 0 && imac_size <= EVP_MAX_MD_SIZE)) { + RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB); + return OSSL_RECORD_RETURN_FATAL; + } + mac_size = (size_t)imac_size; + } + } + + /* + * If in encrypt-then-mac mode calculate mac from encrypted record. All + * the details below are public so no timing details can leak. + */ + if (rl->use_etm && rl->md_ctx != NULL) { + unsigned char *mac; + + for (j = 0; j < num_recs; j++) { + thisrr = &rr[j]; + + if (thisrr->length < mac_size) { + RLAYERfatal(rl, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_TOO_SHORT); + return OSSL_RECORD_RETURN_FATAL; + } + thisrr->length -= mac_size; + mac = thisrr->data + thisrr->length; + i = rl->funcs->mac(rl, thisrr, md, 0 /* not send */); + if (i == 0 || CRYPTO_memcmp(md, mac, mac_size) != 0) { + RLAYERfatal(rl, SSL_AD_BAD_RECORD_MAC, + SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC); + return OSSL_RECORD_RETURN_FATAL; + } + } + /* + * We've handled the mac now - there is no MAC inside the encrypted + * record + */ + mac_size = 0; + } + + if (mac_size > 0) { + macbufs = OPENSSL_zalloc(sizeof(*macbufs) * num_recs); + if (macbufs == NULL) { + RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_CRYPTO_LIB); + return OSSL_RECORD_RETURN_FATAL; + } + } + + enc_err = rl->funcs->cipher(rl, rr, num_recs, 0, macbufs, mac_size); + + /*- + * enc_err is: + * 0: if the record is publicly invalid, or an internal error, or AEAD + * decryption failed, or ETM decryption failed. + * 1: Success or MTE decryption failed (MAC will be randomised) + */ + if (enc_err == 0) { + if (rl->alert != SSL_AD_NO_ALERT) { + /* RLAYERfatal() already got called */ + goto end; + } + if (num_recs == 1 + && rl->skip_early_data != NULL + && rl->skip_early_data(rl->cbarg)) { + /* + * Valid early_data that we cannot decrypt will fail here. We treat + * it like an empty record. + */ + + thisrr = &rr[0]; + + if (!rlayer_early_data_count_ok(rl, thisrr->length, + EARLY_DATA_CIPHERTEXT_OVERHEAD, 0)) { + /* RLAYERfatal() already called */ + goto end; + } + + thisrr->length = 0; + rl->num_recs = 0; + rl->curr_rec = 0; + rl->num_released = 0; + /* Reset the read sequence */ + memset(rl->sequence, 0, sizeof(rl->sequence)); + ret = 1; + goto end; + } + RLAYERfatal(rl, SSL_AD_BAD_RECORD_MAC, + SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC); + goto end; + } + OSSL_TRACE_BEGIN(TLS) { + BIO_printf(trc_out, "dec %lu\n", (unsigned long)rr[0].length); + BIO_dump_indent(trc_out, rr[0].data, rr[0].length, 4); + } OSSL_TRACE_END(TLS); + + /* r->length is now the compressed data plus mac */ + if (rl->enc_ctx != NULL + && !rl->use_etm + && EVP_MD_CTX_get0_md(rl->md_ctx) != NULL) { + for (j = 0; j < num_recs; j++) { + SSL_MAC_BUF *thismb = &macbufs[j]; + + thisrr = &rr[j]; + + i = rl->funcs->mac(rl, thisrr, md, 0 /* not send */); + if (i == 0 || thismb == NULL || thismb->mac == NULL + || CRYPTO_memcmp(md, thismb->mac, (size_t)mac_size) != 0) + enc_err = 0; + if (thisrr->length > SSL3_RT_MAX_COMPRESSED_LENGTH + mac_size) + enc_err = 0; + } + } + + if (enc_err == 0) { + if (rl->alert != SSL_AD_NO_ALERT) { + /* We already called RLAYERfatal() */ + goto end; + } + /* + * A separate 'decryption_failed' alert was introduced with TLS 1.0, + * SSL 3.0 only has 'bad_record_mac'. But unless a decryption + * failure is directly visible from the ciphertext anyway, we should + * not reveal which kind of error occurred -- this might become + * visible to an attacker (e.g. via a logfile) + */ + RLAYERfatal(rl, SSL_AD_BAD_RECORD_MAC, + SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC); + goto end; + } + + for (j = 0; j < num_recs; j++) { + thisrr = &rr[j]; + + if (!rl->funcs->post_process_record(rl, thisrr)) { + /* RLAYERfatal already called */ + goto end; + } + + /* + * Check if the received packet overflows the current + * Max Fragment Length setting. + * Note: rl->max_frag_len > 0 and KTLS are mutually exclusive. + */ + if (thisrr->length > rl->max_frag_len) { + RLAYERfatal(rl, SSL_AD_RECORD_OVERFLOW, SSL_R_DATA_LENGTH_TOO_LONG); + goto end; + } + + thisrr->off = 0; + /*- + * So at this point the following is true + * thisrr->type is the type of record + * thisrr->length == number of bytes in record + * thisrr->off == offset to first valid byte + * thisrr->data == where to take bytes from, increment after use :-). + */ + + /* just read a 0 length packet */ + if (thisrr->length == 0) { + if (++(rl->empty_record_count) > MAX_EMPTY_RECORDS) { + RLAYERfatal(rl, SSL_AD_UNEXPECTED_MESSAGE, + SSL_R_RECORD_TOO_SMALL); + goto end; + } + } else { + rl->empty_record_count = 0; + } + } + + if (rl->level == OSSL_RECORD_PROTECTION_LEVEL_EARLY) { + thisrr = &rr[0]; + if (thisrr->type == SSL3_RT_APPLICATION_DATA + && !rlayer_early_data_count_ok(rl, thisrr->length, 0, 0)) { + /* RLAYERfatal already called */ + goto end; + } + } + + rl->num_recs = num_recs; + rl->curr_rec = 0; + rl->num_released = 0; + ret = OSSL_RECORD_RETURN_SUCCESS; + end: + if (macbufs != NULL) { + for (j = 0; j < num_recs; j++) { + if (macbufs[j].alloced) + OPENSSL_free(macbufs[j].mac); + } + OPENSSL_free(macbufs); + } + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3450/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2021-3450/fixed.c new file mode 100644 index 0000000..2408f3c --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3450/fixed.c @@ -0,0 +1,147 @@ +/* Provenance: openssl/openssl check_chain_extensions (fixed). + * repo: openssl/openssl + * commit: 2a40b7bc7b94dd7de897a74571e7024f0cf0d63b + * parent: cfd74383d9b06f85cb1e166180346115a3f9a452 + * commit_url: https://github.com/openssl/openssl/commit/2a40b7bc7b94dd7de897a74571e7024f0cf0d63b + * cve: CVE-2021-3450 + * license: OpenSSL License + * function: check_chain_extensions + * relpath: crypto/x509/x509_vfy.c + */ + +static int check_chain_extensions(X509_STORE_CTX *ctx) +{ + int i, must_be_ca, plen = 0; + X509 *x; + int proxy_path_length = 0; + int purpose; + int allow_proxy_certs; + int num = sk_X509_num(ctx->chain); + + /*- + * must_be_ca can have 1 of 3 values: + * -1: we accept both CA and non-CA certificates, to allow direct + * use of self-signed certificates (which are marked as CA). + * 0: we only accept non-CA certificates. This is currently not + * used, but the possibility is present for future extensions. + * 1: we only accept CA certificates. This is currently used for + * all certificates in the chain except the leaf certificate. + */ + must_be_ca = -1; + + /* CRL path validation */ + if (ctx->parent) { + allow_proxy_certs = 0; + purpose = X509_PURPOSE_CRL_SIGN; + } else { + allow_proxy_certs = + ! !(ctx->param->flags & X509_V_FLAG_ALLOW_PROXY_CERTS); + purpose = ctx->param->purpose; + } + + for (i = 0; i < num; i++) { + int ret; + x = sk_X509_value(ctx->chain, i); + if (!(ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL) + && (x->ex_flags & EXFLAG_CRITICAL)) { + if (!verify_cb_cert(ctx, x, i, + X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION)) + return 0; + } + if (!allow_proxy_certs && (x->ex_flags & EXFLAG_PROXY)) { + if (!verify_cb_cert(ctx, x, i, + X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED)) + return 0; + } + ret = X509_check_ca(x); + switch (must_be_ca) { + case -1: + if ((ctx->param->flags & X509_V_FLAG_X509_STRICT) + && (ret != 1) && (ret != 0)) { + ret = 0; + ctx->error = X509_V_ERR_INVALID_CA; + } else + ret = 1; + break; + case 0: + if (ret != 0) { + ret = 0; + ctx->error = X509_V_ERR_INVALID_NON_CA; + } else + ret = 1; + break; + default: + /* X509_V_FLAG_X509_STRICT is implicit for intermediate CAs */ + if ((ret == 0) + || ((i + 1 < num || ctx->param->flags & X509_V_FLAG_X509_STRICT) + && (ret != 1))) { + ret = 0; + ctx->error = X509_V_ERR_INVALID_CA; + } else + ret = 1; + break; + } + if (ret > 0 + && (ctx->param->flags & X509_V_FLAG_X509_STRICT) && num > 1) { + /* Check for presence of explicit elliptic curve parameters */ + ret = check_curve(x); + if (ret < 0) { + ctx->error = X509_V_ERR_UNSPECIFIED; + ret = 0; + } else if (ret == 0) { + ctx->error = X509_V_ERR_EC_KEY_EXPLICIT_PARAMS; + } + } + if (ret > 0 + && (x->ex_flags & EXFLAG_CA) == 0 + && x->ex_pathlen != -1 + && (ctx->param->flags & X509_V_FLAG_X509_STRICT)) { + ctx->error = X509_V_ERR_INVALID_EXTENSION; + ret = 0; + } + if (ret == 0 && !verify_cb_cert(ctx, x, i, X509_V_OK)) + return 0; + /* check_purpose() makes the callback as needed */ + if (purpose > 0 && !check_purpose(ctx, x, purpose, i, must_be_ca)) + return 0; + /* Check pathlen */ + if ((i > 1) && (x->ex_pathlen != -1) + && (plen > (x->ex_pathlen + proxy_path_length))) { + if (!verify_cb_cert(ctx, x, i, X509_V_ERR_PATH_LENGTH_EXCEEDED)) + return 0; + } + /* Increment path length if not a self issued intermediate CA */ + if (i > 0 && (x->ex_flags & EXFLAG_SI) == 0) + plen++; + /* + * If this certificate is a proxy certificate, the next certificate + * must be another proxy certificate or a EE certificate. If not, + * the next certificate must be a CA certificate. + */ + if (x->ex_flags & EXFLAG_PROXY) { + /* + * RFC3820, 4.1.3 (b)(1) stipulates that if pCPathLengthConstraint + * is less than max_path_length, the former should be copied to + * the latter, and 4.1.4 (a) stipulates that max_path_length + * should be verified to be larger than zero and decrement it. + * + * Because we're checking the certs in the reverse order, we start + * with verifying that proxy_path_length isn't larger than pcPLC, + * and copy the latter to the former if it is, and finally, + * increment proxy_path_length. + */ + if (x->ex_pcpathlen != -1) { + if (proxy_path_length > x->ex_pcpathlen) { + if (!verify_cb_cert(ctx, x, i, + X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED)) + return 0; + } + proxy_path_length = x->ex_pcpathlen; + } + proxy_path_length++; + must_be_ca = 0; + } else + must_be_ca = 1; + } + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3450/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2021-3450/vuln.c new file mode 100644 index 0000000..352bfec --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3450/vuln.c @@ -0,0 +1,143 @@ +/* Provenance: openssl/openssl check_chain_extensions (vuln). + * repo: openssl/openssl + * commit: cfd74383d9b06f85cb1e166180346115a3f9a452 + * parent: cfd74383d9b06f85cb1e166180346115a3f9a452 + * commit_url: https://github.com/openssl/openssl/commit/2a40b7bc7b94dd7de897a74571e7024f0cf0d63b + * cve: CVE-2021-3450 + * license: OpenSSL License + * function: check_chain_extensions + * relpath: crypto/x509/x509_vfy.c + */ + +static int check_chain_extensions(X509_STORE_CTX *ctx) +{ + int i, must_be_ca, plen = 0; + X509 *x; + int proxy_path_length = 0; + int purpose; + int allow_proxy_certs; + int num = sk_X509_num(ctx->chain); + + /*- + * must_be_ca can have 1 of 3 values: + * -1: we accept both CA and non-CA certificates, to allow direct + * use of self-signed certificates (which are marked as CA). + * 0: we only accept non-CA certificates. This is currently not + * used, but the possibility is present for future extensions. + * 1: we only accept CA certificates. This is currently used for + * all certificates in the chain except the leaf certificate. + */ + must_be_ca = -1; + + /* CRL path validation */ + if (ctx->parent) { + allow_proxy_certs = 0; + purpose = X509_PURPOSE_CRL_SIGN; + } else { + allow_proxy_certs = + ! !(ctx->param->flags & X509_V_FLAG_ALLOW_PROXY_CERTS); + purpose = ctx->param->purpose; + } + + for (i = 0; i < num; i++) { + int ret; + x = sk_X509_value(ctx->chain, i); + if (!(ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL) + && (x->ex_flags & EXFLAG_CRITICAL)) { + if (!verify_cb_cert(ctx, x, i, + X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION)) + return 0; + } + if (!allow_proxy_certs && (x->ex_flags & EXFLAG_PROXY)) { + if (!verify_cb_cert(ctx, x, i, + X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED)) + return 0; + } + ret = X509_check_ca(x); + switch (must_be_ca) { + case -1: + if ((ctx->param->flags & X509_V_FLAG_X509_STRICT) + && (ret != 1) && (ret != 0)) { + ret = 0; + ctx->error = X509_V_ERR_INVALID_CA; + } else + ret = 1; + break; + case 0: + if (ret != 0) { + ret = 0; + ctx->error = X509_V_ERR_INVALID_NON_CA; + } else + ret = 1; + break; + default: + /* X509_V_FLAG_X509_STRICT is implicit for intermediate CAs */ + if ((ret == 0) + || ((i + 1 < num || ctx->param->flags & X509_V_FLAG_X509_STRICT) + && (ret != 1))) { + ret = 0; + ctx->error = X509_V_ERR_INVALID_CA; + } else + ret = 1; + break; + } + if ((ctx->param->flags & X509_V_FLAG_X509_STRICT) && num > 1) { + /* Check for presence of explicit elliptic curve parameters */ + ret = check_curve(x); + if (ret < 0) + ctx->error = X509_V_ERR_UNSPECIFIED; + else if (ret == 0) + ctx->error = X509_V_ERR_EC_KEY_EXPLICIT_PARAMS; + } + if ((x->ex_flags & EXFLAG_CA) == 0 + && x->ex_pathlen != -1 + && (ctx->param->flags & X509_V_FLAG_X509_STRICT)) { + ctx->error = X509_V_ERR_INVALID_EXTENSION; + ret = 0; + } + if (ret == 0 && !verify_cb_cert(ctx, x, i, X509_V_OK)) + return 0; + /* check_purpose() makes the callback as needed */ + if (purpose > 0 && !check_purpose(ctx, x, purpose, i, must_be_ca)) + return 0; + /* Check pathlen */ + if ((i > 1) && (x->ex_pathlen != -1) + && (plen > (x->ex_pathlen + proxy_path_length))) { + if (!verify_cb_cert(ctx, x, i, X509_V_ERR_PATH_LENGTH_EXCEEDED)) + return 0; + } + /* Increment path length if not a self issued intermediate CA */ + if (i > 0 && (x->ex_flags & EXFLAG_SI) == 0) + plen++; + /* + * If this certificate is a proxy certificate, the next certificate + * must be another proxy certificate or a EE certificate. If not, + * the next certificate must be a CA certificate. + */ + if (x->ex_flags & EXFLAG_PROXY) { + /* + * RFC3820, 4.1.3 (b)(1) stipulates that if pCPathLengthConstraint + * is less than max_path_length, the former should be copied to + * the latter, and 4.1.4 (a) stipulates that max_path_length + * should be verified to be larger than zero and decrement it. + * + * Because we're checking the certs in the reverse order, we start + * with verifying that proxy_path_length isn't larger than pcPLC, + * and copy the latter to the former if it is, and finally, + * increment proxy_path_length. + */ + if (x->ex_pcpathlen != -1) { + if (proxy_path_length > x->ex_pcpathlen) { + if (!verify_cb_cert(ctx, x, i, + X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED)) + return 0; + } + proxy_path_length = x->ex_pcpathlen; + } + proxy_path_length++; + must_be_ca = 0; + } else + must_be_ca = 1; + } + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3711-pkey_sm2_decrypt/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2021-3711-pkey_sm2_decrypt/fixed.c new file mode 100644 index 0000000..8d7a237 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3711-pkey_sm2_decrypt/fixed.c @@ -0,0 +1,28 @@ +/* Provenance: openssl/openssl pkey_sm2_decrypt (fixed). + * repo: openssl/openssl + * commit: 59f5e75f3bced8fc0e130d72a3f582cf7b480b46 + * parent: 8c74c9d1ade0fbdab5b815ddb747351b8b839641 + * commit_url: https://github.com/openssl/openssl/commit/59f5e75f3bced8fc0e130d72a3f582cf7b480b46 + * cve: CVE-2021-3711 + * license: OpenSSL License + * function: pkey_sm2_decrypt + * relpath: crypto/sm2/sm2_pmeth.c + */ + +static int pkey_sm2_decrypt(EVP_PKEY_CTX *ctx, + unsigned char *out, size_t *outlen, + const unsigned char *in, size_t inlen) +{ + EC_KEY *ec = ctx->pkey->pkey.ec; + SM2_PKEY_CTX *dctx = ctx->data; + const EVP_MD *md = (dctx->md == NULL) ? EVP_sm3() : dctx->md; + + if (out == NULL) { + if (!sm2_plaintext_size(in, inlen, outlen)) + return -1; + else + return 1; + } + + return sm2_decrypt(ec, md, in, inlen, out, outlen); +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3711-pkey_sm2_decrypt/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2021-3711-pkey_sm2_decrypt/vuln.c new file mode 100644 index 0000000..8c1af9b --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3711-pkey_sm2_decrypt/vuln.c @@ -0,0 +1,28 @@ +/* Provenance: openssl/openssl pkey_sm2_decrypt (vuln). + * repo: openssl/openssl + * commit: 8c74c9d1ade0fbdab5b815ddb747351b8b839641 + * parent: 8c74c9d1ade0fbdab5b815ddb747351b8b839641 + * commit_url: https://github.com/openssl/openssl/commit/59f5e75f3bced8fc0e130d72a3f582cf7b480b46 + * cve: CVE-2021-3711 + * license: OpenSSL License + * function: pkey_sm2_decrypt + * relpath: crypto/sm2/sm2_pmeth.c + */ + +static int pkey_sm2_decrypt(EVP_PKEY_CTX *ctx, + unsigned char *out, size_t *outlen, + const unsigned char *in, size_t inlen) +{ + EC_KEY *ec = ctx->pkey->pkey.ec; + SM2_PKEY_CTX *dctx = ctx->data; + const EVP_MD *md = (dctx->md == NULL) ? EVP_sm3() : dctx->md; + + if (out == NULL) { + if (!sm2_plaintext_size(ec, md, inlen, outlen)) + return -1; + else + return 1; + } + + return sm2_decrypt(ec, md, in, inlen, out, outlen); +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3711-sm2_asym_decrypt/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2021-3711-sm2_asym_decrypt/fixed.c new file mode 100644 index 0000000..6b5c0a2 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3711-sm2_asym_decrypt/fixed.c @@ -0,0 +1,29 @@ +/* Provenance: openssl/openssl sm2_asym_decrypt (fixed). + * repo: openssl/openssl + * commit: 36cf45ef3ba71e44a8be06ee81cb31aa02cb0010 + * parent: 4b8a8bb75229b64d1c7598d845fdc3c7e7d7eee2 + * commit_url: https://github.com/openssl/openssl/commit/36cf45ef3ba71e44a8be06ee81cb31aa02cb0010 + * cve: CVE-2021-3711 + * license: OpenSSL License + * function: sm2_asym_decrypt + * relpath: providers/implementations/asymciphers/sm2_enc.c + */ + +static int sm2_asym_decrypt(void *vpsm2ctx, unsigned char *out, size_t *outlen, + size_t outsize, const unsigned char *in, + size_t inlen) +{ + PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx; + const EVP_MD *md = sm2_get_md(psm2ctx); + + if (md == NULL) + return 0; + + if (out == NULL) { + if (!ossl_sm2_plaintext_size(in, inlen, outlen)) + return 0; + return 1; + } + + return ossl_sm2_decrypt(psm2ctx->key, md, in, inlen, out, outlen); +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3711-sm2_asym_decrypt/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2021-3711-sm2_asym_decrypt/vuln.c new file mode 100644 index 0000000..b182aee --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3711-sm2_asym_decrypt/vuln.c @@ -0,0 +1,29 @@ +/* Provenance: openssl/openssl sm2_asym_decrypt (vuln). + * repo: openssl/openssl + * commit: 4b8a8bb75229b64d1c7598d845fdc3c7e7d7eee2 + * parent: 4b8a8bb75229b64d1c7598d845fdc3c7e7d7eee2 + * commit_url: https://github.com/openssl/openssl/commit/36cf45ef3ba71e44a8be06ee81cb31aa02cb0010 + * cve: CVE-2021-3711 + * license: OpenSSL License + * function: sm2_asym_decrypt + * relpath: providers/implementations/asymciphers/sm2_enc.c + */ + +static int sm2_asym_decrypt(void *vpsm2ctx, unsigned char *out, size_t *outlen, + size_t outsize, const unsigned char *in, + size_t inlen) +{ + PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx; + const EVP_MD *md = sm2_get_md(psm2ctx); + + if (md == NULL) + return 0; + + if (out == NULL) { + if (!ossl_sm2_plaintext_size(psm2ctx->key, md, inlen, outlen)) + return 0; + return 1; + } + + return ossl_sm2_decrypt(psm2ctx->key, md, in, inlen, out, outlen); +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3711/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2021-3711/fixed.c new file mode 100644 index 0000000..5b9e9ae --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3711/fixed.c @@ -0,0 +1,27 @@ +/* Provenance: openssl/openssl sm2_plaintext_size (fixed). + * repo: openssl/openssl + * commit: 59f5e75f3bced8fc0e130d72a3f582cf7b480b46 + * parent: 8c74c9d1ade0fbdab5b815ddb747351b8b839641 + * commit_url: https://github.com/openssl/openssl/commit/59f5e75f3bced8fc0e130d72a3f582cf7b480b46 + * cve: CVE-2021-3711 + * license: OpenSSL License + * function: sm2_plaintext_size + * relpath: crypto/sm2/sm2_crypt.c + */ + +int sm2_plaintext_size(const unsigned char *ct, size_t ct_size, size_t *pt_size) +{ + struct SM2_Ciphertext_st *sm2_ctext = NULL; + + sm2_ctext = d2i_SM2_Ciphertext(NULL, &ct, ct_size); + + if (sm2_ctext == NULL) { + SM2err(SM2_F_SM2_PLAINTEXT_SIZE, SM2_R_INVALID_ENCODING); + return 0; + } + + *pt_size = sm2_ctext->C2->length; + SM2_Ciphertext_free(sm2_ctext); + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3711/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2021-3711/vuln.c new file mode 100644 index 0000000..87d3034 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3711/vuln.c @@ -0,0 +1,36 @@ +/* Provenance: openssl/openssl sm2_plaintext_size (vuln). + * repo: openssl/openssl + * commit: 8c74c9d1ade0fbdab5b815ddb747351b8b839641 + * parent: 8c74c9d1ade0fbdab5b815ddb747351b8b839641 + * commit_url: https://github.com/openssl/openssl/commit/59f5e75f3bced8fc0e130d72a3f582cf7b480b46 + * cve: CVE-2021-3711 + * license: OpenSSL License + * function: sm2_plaintext_size + * relpath: crypto/sm2/sm2_crypt.c + */ + +int sm2_plaintext_size(const EC_KEY *key, const EVP_MD *digest, size_t msg_len, + size_t *pt_size) +{ + const size_t field_size = ec_field_size(EC_KEY_get0_group(key)); + const int md_size = EVP_MD_size(digest); + size_t overhead; + + if (md_size < 0) { + SM2err(SM2_F_SM2_PLAINTEXT_SIZE, SM2_R_INVALID_DIGEST); + return 0; + } + if (field_size == 0) { + SM2err(SM2_F_SM2_PLAINTEXT_SIZE, SM2_R_INVALID_FIELD); + return 0; + } + + overhead = 10 + 2 * field_size + (size_t)md_size; + if (msg_len <= overhead) { + SM2err(SM2_F_SM2_PLAINTEXT_SIZE, SM2_R_INVALID_ENCODING); + return 0; + } + + *pt_size = msg_len - overhead; + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3712-append_ia5/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2021-3712-append_ia5/fixed.c new file mode 100644 index 0000000..61e0d9e --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3712-append_ia5/fixed.c @@ -0,0 +1,45 @@ +/* Provenance: openssl/openssl append_ia5 (fixed). + * repo: openssl/openssl + * commit: 98624776c4d501c8badd6f772ab7048ac9191cb9 + * parent: 1f365708a3318a5f1a395f90c38b584a58d37fb9 + * commit_url: https://github.com/openssl/openssl/commit/98624776c4d501c8badd6f772ab7048ac9191cb9 + * cve: CVE-2021-3712 + * license: OpenSSL License + * function: append_ia5 + * relpath: crypto/x509/v3_utl.c + */ + +static int append_ia5(STACK_OF(OPENSSL_STRING) **sk, + const ASN1_IA5STRING *email) +{ + char *emtmp; + + /* First some sanity checks */ + if (email->type != V_ASN1_IA5STRING) + return 1; + if (email->data == NULL || email->length == 0) + return 1; + if (memchr(email->data, 0, email->length) != NULL) + return 1; + if (*sk == NULL) + *sk = sk_OPENSSL_STRING_new(sk_strcmp); + if (*sk == NULL) + return 0; + + emtmp = OPENSSL_strndup((char *)email->data, email->length); + if (emtmp == NULL) + return 0; + + /* Don't add duplicates */ + if (sk_OPENSSL_STRING_find(*sk, emtmp) != -1) { + OPENSSL_free(emtmp); + return 1; + } + if (!sk_OPENSSL_STRING_push(*sk, emtmp)) { + OPENSSL_free(emtmp); /* free on push failure */ + X509_email_free(*sk); + *sk = NULL; + return 0; + } + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3712-append_ia5/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2021-3712-append_ia5/vuln.c new file mode 100644 index 0000000..9b22783 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3712-append_ia5/vuln.c @@ -0,0 +1,37 @@ +/* Provenance: openssl/openssl append_ia5 (vuln). + * repo: openssl/openssl + * commit: 1f365708a3318a5f1a395f90c38b584a58d37fb9 + * parent: 1f365708a3318a5f1a395f90c38b584a58d37fb9 + * commit_url: https://github.com/openssl/openssl/commit/98624776c4d501c8badd6f772ab7048ac9191cb9 + * cve: CVE-2021-3712 + * license: OpenSSL License + * function: append_ia5 + * relpath: crypto/x509/v3_utl.c + */ + +static int append_ia5(STACK_OF(OPENSSL_STRING) **sk, + const ASN1_IA5STRING *email) +{ + char *emtmp; + + /* First some sanity checks */ + if (email->type != V_ASN1_IA5STRING) + return 1; + if (!email->data || !email->length) + return 1; + if (*sk == NULL) + *sk = sk_OPENSSL_STRING_new(sk_strcmp); + if (*sk == NULL) + return 0; + /* Don't add duplicates */ + if (sk_OPENSSL_STRING_find(*sk, (char *)email->data) != -1) + return 1; + emtmp = OPENSSL_strdup((char *)email->data); + if (emtmp == NULL || !sk_OPENSSL_STRING_push(*sk, emtmp)) { + OPENSSL_free(emtmp); /* free on push failure */ + X509_email_free(*sk); + *sk = NULL; + return 0; + } + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3712-general_name_print/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2021-3712-general_name_print/fixed.c new file mode 100644 index 0000000..5d255ae --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3712-general_name_print/fixed.c @@ -0,0 +1,104 @@ +/* Provenance: openssl/openssl GENERAL_NAME_print (fixed). + * repo: openssl/openssl + * commit: b2b3b9c9936b91315adc0f3254879cb2fd5ca2bd + * parent: 1747d4658b3830951068a6a6c1fa2b45c4731fb3 + * commit_url: https://github.com/openssl/openssl/commit/b2b3b9c9936b91315adc0f3254879cb2fd5ca2bd + * cve: CVE-2021-3712 + * license: OpenSSL License + * function: GENERAL_NAME_print + * relpath: crypto/x509/v3_san.c + */ + +int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen) +{ + char *tmp; + int nid; + + switch (gen->type) { + case GEN_OTHERNAME: + nid = OBJ_obj2nid(gen->d.otherName->type_id); + /* Validate the types are as we expect before we use them */ + if ((nid == NID_SRVName + && gen->d.otherName->value->type != V_ASN1_IA5STRING) + || (nid != NID_SRVName + && gen->d.otherName->value->type != V_ASN1_UTF8STRING)) { + BIO_printf(out, "othername:"); + break; + } + + switch (nid) { + case NID_id_on_SmtpUTF8Mailbox: + BIO_printf(out, "othername:SmtpUTF8Mailbox:%.*s", + gen->d.otherName->value->value.utf8string->length, + gen->d.otherName->value->value.utf8string->data); + break; + case NID_XmppAddr: + BIO_printf(out, "othername:XmppAddr:%.*s", + gen->d.otherName->value->value.utf8string->length, + gen->d.otherName->value->value.utf8string->data); + break; + case NID_SRVName: + BIO_printf(out, "othername:SRVName:%.*s", + gen->d.otherName->value->value.ia5string->length, + gen->d.otherName->value->value.ia5string->data); + break; + case NID_ms_upn: + BIO_printf(out, "othername:UPN:%.*s", + gen->d.otherName->value->value.utf8string->length, + gen->d.otherName->value->value.utf8string->data); + break; + case NID_NAIRealm: + BIO_printf(out, "othername:NAIRealm:%.*s", + gen->d.otherName->value->value.utf8string->length, + gen->d.otherName->value->value.utf8string->data); + break; + default: + BIO_printf(out, "othername:"); + break; + } + break; + + case GEN_X400: + BIO_printf(out, "X400Name:"); + break; + + case GEN_EDIPARTY: + /* Maybe fix this: it is supported now */ + BIO_printf(out, "EdiPartyName:"); + break; + + case GEN_EMAIL: + BIO_printf(out, "email:"); + ASN1_STRING_print(out, gen->d.ia5); + break; + + case GEN_DNS: + BIO_printf(out, "DNS:"); + ASN1_STRING_print(out, gen->d.ia5); + break; + + case GEN_URI: + BIO_printf(out, "URI:"); + ASN1_STRING_print(out, gen->d.ia5); + break; + + case GEN_DIRNAME: + BIO_printf(out, "DirName:"); + X509_NAME_print_ex(out, gen->d.dirn, 0, XN_FLAG_ONELINE); + break; + + case GEN_IPADD: + tmp = ossl_ipaddr_to_asc(gen->d.ip->data, gen->d.ip->length); + if (tmp == NULL) + return 0; + BIO_printf(out, "IP Address:%s", tmp); + OPENSSL_free(tmp); + break; + + case GEN_RID: + BIO_printf(out, "Registered ID:"); + i2a_ASN1_OBJECT(out, gen->d.rid); + break; + } + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3712-general_name_print/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2021-3712-general_name_print/vuln.c new file mode 100644 index 0000000..c615876 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3712-general_name_print/vuln.c @@ -0,0 +1,99 @@ +/* Provenance: openssl/openssl GENERAL_NAME_print (vuln). + * repo: openssl/openssl + * commit: 1747d4658b3830951068a6a6c1fa2b45c4731fb3 + * parent: 1747d4658b3830951068a6a6c1fa2b45c4731fb3 + * commit_url: https://github.com/openssl/openssl/commit/b2b3b9c9936b91315adc0f3254879cb2fd5ca2bd + * cve: CVE-2021-3712 + * license: OpenSSL License + * function: GENERAL_NAME_print + * relpath: crypto/x509/v3_san.c + */ + +int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen) +{ + char *tmp; + int nid; + + switch (gen->type) { + case GEN_OTHERNAME: + nid = OBJ_obj2nid(gen->d.otherName->type_id); + /* Validate the types are as we expect before we use them */ + if ((nid == NID_SRVName + && gen->d.otherName->value->type != V_ASN1_IA5STRING) + || (nid != NID_SRVName + && gen->d.otherName->value->type != V_ASN1_UTF8STRING)) { + BIO_printf(out, "othername:"); + break; + } + + switch (nid) { + case NID_id_on_SmtpUTF8Mailbox: + BIO_printf(out, "othername:SmtpUTF8Mailbox:%s", + gen->d.otherName->value->value.utf8string->data); + break; + case NID_XmppAddr: + BIO_printf(out, "othername:XmppAddr:%s", + gen->d.otherName->value->value.utf8string->data); + break; + case NID_SRVName: + BIO_printf(out, "othername:SRVName:%s", + gen->d.otherName->value->value.ia5string->data); + break; + case NID_ms_upn: + BIO_printf(out, "othername:UPN:%s", + gen->d.otherName->value->value.utf8string->data); + break; + case NID_NAIRealm: + BIO_printf(out, "othername:NAIRealm:%s", + gen->d.otherName->value->value.utf8string->data); + break; + default: + BIO_printf(out, "othername:"); + break; + } + break; + + case GEN_X400: + BIO_printf(out, "X400Name:"); + break; + + case GEN_EDIPARTY: + /* Maybe fix this: it is supported now */ + BIO_printf(out, "EdiPartyName:"); + break; + + case GEN_EMAIL: + BIO_printf(out, "email:"); + ASN1_STRING_print(out, gen->d.ia5); + break; + + case GEN_DNS: + BIO_printf(out, "DNS:"); + ASN1_STRING_print(out, gen->d.ia5); + break; + + case GEN_URI: + BIO_printf(out, "URI:"); + ASN1_STRING_print(out, gen->d.ia5); + break; + + case GEN_DIRNAME: + BIO_printf(out, "DirName:"); + X509_NAME_print_ex(out, gen->d.dirn, 0, XN_FLAG_ONELINE); + break; + + case GEN_IPADD: + tmp = ossl_ipaddr_to_asc(gen->d.ip->data, gen->d.ip->length); + if (tmp == NULL) + return 0; + BIO_printf(out, "IP Address:%s", tmp); + OPENSSL_free(tmp); + break; + + case GEN_RID: + BIO_printf(out, "Registered ID:"); + i2a_ASN1_OBJECT(out, gen->d.rid); + break; + } + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3712-i2r_pci/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2021-3712-i2r_pci/fixed.c new file mode 100644 index 0000000..82f5700 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3712-i2r_pci/fixed.c @@ -0,0 +1,28 @@ +/* Provenance: openssl/openssl i2r_pci (fixed). + * repo: openssl/openssl + * commit: 918430ba80d94ec8f05383b43b1872b1ebb13e1a + * parent: b2b3b9c9936b91315adc0f3254879cb2fd5ca2bd + * commit_url: https://github.com/openssl/openssl/commit/918430ba80d94ec8f05383b43b1872b1ebb13e1a + * cve: CVE-2021-3712 + * license: OpenSSL License + * function: i2r_pci + * relpath: crypto/x509/v3_pci.c + */ + +static int i2r_pci(X509V3_EXT_METHOD *method, PROXY_CERT_INFO_EXTENSION *pci, + BIO *out, int indent) +{ + BIO_printf(out, "%*sPath Length Constraint: ", indent, ""); + if (pci->pcPathLengthConstraint) + i2a_ASN1_INTEGER(out, pci->pcPathLengthConstraint); + else + BIO_printf(out, "infinite"); + BIO_puts(out, "\n"); + BIO_printf(out, "%*sPolicy Language: ", indent, ""); + i2a_ASN1_OBJECT(out, pci->proxyPolicy->policyLanguage); + if (pci->proxyPolicy->policy && pci->proxyPolicy->policy->data) + BIO_printf(out, "\n%*sPolicy Text: %.*s", indent, "", + pci->proxyPolicy->policy->length, + pci->proxyPolicy->policy->data); + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3712-i2r_pci/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2021-3712-i2r_pci/vuln.c new file mode 100644 index 0000000..c9a45b8 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3712-i2r_pci/vuln.c @@ -0,0 +1,27 @@ +/* Provenance: openssl/openssl i2r_pci (vuln). + * repo: openssl/openssl + * commit: b2b3b9c9936b91315adc0f3254879cb2fd5ca2bd + * parent: b2b3b9c9936b91315adc0f3254879cb2fd5ca2bd + * commit_url: https://github.com/openssl/openssl/commit/918430ba80d94ec8f05383b43b1872b1ebb13e1a + * cve: CVE-2021-3712 + * license: OpenSSL License + * function: i2r_pci + * relpath: crypto/x509/v3_pci.c + */ + +static int i2r_pci(X509V3_EXT_METHOD *method, PROXY_CERT_INFO_EXTENSION *pci, + BIO *out, int indent) +{ + BIO_printf(out, "%*sPath Length Constraint: ", indent, ""); + if (pci->pcPathLengthConstraint) + i2a_ASN1_INTEGER(out, pci->pcPathLengthConstraint); + else + BIO_printf(out, "infinite"); + BIO_puts(out, "\n"); + BIO_printf(out, "%*sPolicy Language: ", indent, ""); + i2a_ASN1_OBJECT(out, pci->proxyPolicy->policyLanguage); + if (pci->proxyPolicy->policy && pci->proxyPolicy->policy->data) + BIO_printf(out, "\n%*sPolicy Text: %s", indent, "", + pci->proxyPolicy->policy->data); + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3712-ia5ncasecmp/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2021-3712-ia5ncasecmp/fixed.c new file mode 100644 index 0000000..cb19d51 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3712-ia5ncasecmp/fixed.c @@ -0,0 +1,36 @@ +/* Provenance: openssl/openssl ia5ncasecmp (fixed). + * repo: openssl/openssl + * commit: d2015a783e64613d8e4a142fa05048d1863df944 + * parent: 918430ba80d94ec8f05383b43b1872b1ebb13e1a + * commit_url: https://github.com/openssl/openssl/commit/d2015a783e64613d8e4a142fa05048d1863df944 + * cve: CVE-2021-3712 + * license: OpenSSL License + * function: ia5ncasecmp + * relpath: crypto/x509/v3_ncons.c + */ + +static int ia5ncasecmp(const char *s1, const char *s2, size_t n) +{ + for (; n > 0; n--, s1++, s2++) { + if (*s1 != *s2) { + unsigned char c1 = (unsigned char)*s1, c2 = (unsigned char)*s2; + + /* Convert to lower case */ + if (c1 >= 0x41 /* A */ && c1 <= 0x5A /* Z */) + c1 += 0x20; + if (c2 >= 0x41 /* A */ && c2 <= 0x5A /* Z */) + c2 += 0x20; + + if (c1 == c2) + continue; + + if (c1 < c2) + return -1; + + /* c1 > c2 */ + return 1; + } + } + + return 0; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3712-ia5ncasecmp/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2021-3712-ia5ncasecmp/vuln.c new file mode 100644 index 0000000..37605a5 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3712-ia5ncasecmp/vuln.c @@ -0,0 +1,39 @@ +/* Provenance: openssl/openssl ia5ncasecmp (vuln). + * repo: openssl/openssl + * commit: 918430ba80d94ec8f05383b43b1872b1ebb13e1a + * parent: 918430ba80d94ec8f05383b43b1872b1ebb13e1a + * commit_url: https://github.com/openssl/openssl/commit/d2015a783e64613d8e4a142fa05048d1863df944 + * cve: CVE-2021-3712 + * license: OpenSSL License + * function: ia5ncasecmp + * relpath: crypto/x509/v3_ncons.c + */ + +static int ia5ncasecmp(const char *s1, const char *s2, size_t n) +{ + for (; n > 0; n--, s1++, s2++) { + if (*s1 != *s2) { + unsigned char c1 = (unsigned char)*s1, c2 = (unsigned char)*s2; + + /* Convert to lower case */ + if (c1 >= 0x41 /* A */ && c1 <= 0x5A /* Z */) + c1 += 0x20; + if (c2 >= 0x41 /* A */ && c2 <= 0x5A /* Z */) + c2 += 0x20; + + if (c1 == c2) + continue; + + if (c1 < c2) + return -1; + + /* c1 > c2 */ + return 1; + } else if (*s1 == 0) { + /* If we get here we know that *s2 == 0 too */ + return 0; + } + } + + return 0; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3712-netscape_spki_print/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2021-3712-netscape_spki_print/fixed.c new file mode 100644 index 0000000..3e2f0e0 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3712-netscape_spki_print/fixed.c @@ -0,0 +1,48 @@ +/* Provenance: openssl/openssl NETSCAPE_SPKI_print (fixed). + * repo: openssl/openssl + * commit: 7c038a6bcd98d4bbfd2c2892a87a1138d2f7c5f3 + * parent: 98624776c4d501c8badd6f772ab7048ac9191cb9 + * commit_url: https://github.com/openssl/openssl/commit/7c038a6bcd98d4bbfd2c2892a87a1138d2f7c5f3 + * cve: CVE-2021-3712 + * license: OpenSSL License + * function: NETSCAPE_SPKI_print + * relpath: crypto/asn1/t_spki.c + */ + +int NETSCAPE_SPKI_print(BIO *out, NETSCAPE_SPKI *spki) +{ + EVP_PKEY *pkey; + ASN1_IA5STRING *chal; + ASN1_OBJECT *spkioid; + int i, n; + char *s; + BIO_printf(out, "Netscape SPKI:\n"); + X509_PUBKEY_get0_param(&spkioid, NULL, NULL, NULL, spki->spkac->pubkey); + i = OBJ_obj2nid(spkioid); + BIO_printf(out, " Public Key Algorithm: %s\n", + (i == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(i)); + pkey = X509_PUBKEY_get(spki->spkac->pubkey); + if (pkey == NULL) + BIO_printf(out, " Unable to load public key\n"); + else { + EVP_PKEY_print_public(out, pkey, 4, NULL); + EVP_PKEY_free(pkey); + } + chal = spki->spkac->challenge; + if (chal->length) + BIO_printf(out, " Challenge String: %.*s\n", chal->length, chal->data); + i = OBJ_obj2nid(spki->sig_algor.algorithm); + BIO_printf(out, " Signature Algorithm: %s", + (i == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(i)); + + n = spki->signature->length; + s = (char *)spki->signature->data; + for (i = 0; i < n; i++) { + if ((i % 18) == 0) + BIO_write(out, "\n ", 7); + BIO_printf(out, "%02x%s", (unsigned char)s[i], + ((i + 1) == n) ? "" : ":"); + } + BIO_write(out, "\n", 1); + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3712-netscape_spki_print/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2021-3712-netscape_spki_print/vuln.c new file mode 100644 index 0000000..82feb13 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3712-netscape_spki_print/vuln.c @@ -0,0 +1,48 @@ +/* Provenance: openssl/openssl NETSCAPE_SPKI_print (vuln). + * repo: openssl/openssl + * commit: 98624776c4d501c8badd6f772ab7048ac9191cb9 + * parent: 98624776c4d501c8badd6f772ab7048ac9191cb9 + * commit_url: https://github.com/openssl/openssl/commit/7c038a6bcd98d4bbfd2c2892a87a1138d2f7c5f3 + * cve: CVE-2021-3712 + * license: OpenSSL License + * function: NETSCAPE_SPKI_print + * relpath: crypto/asn1/t_spki.c + */ + +int NETSCAPE_SPKI_print(BIO *out, NETSCAPE_SPKI *spki) +{ + EVP_PKEY *pkey; + ASN1_IA5STRING *chal; + ASN1_OBJECT *spkioid; + int i, n; + char *s; + BIO_printf(out, "Netscape SPKI:\n"); + X509_PUBKEY_get0_param(&spkioid, NULL, NULL, NULL, spki->spkac->pubkey); + i = OBJ_obj2nid(spkioid); + BIO_printf(out, " Public Key Algorithm: %s\n", + (i == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(i)); + pkey = X509_PUBKEY_get(spki->spkac->pubkey); + if (pkey == NULL) + BIO_printf(out, " Unable to load public key\n"); + else { + EVP_PKEY_print_public(out, pkey, 4, NULL); + EVP_PKEY_free(pkey); + } + chal = spki->spkac->challenge; + if (chal->length) + BIO_printf(out, " Challenge String: %s\n", chal->data); + i = OBJ_obj2nid(spki->sig_algor.algorithm); + BIO_printf(out, " Signature Algorithm: %s", + (i == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(i)); + + n = spki->signature->length; + s = (char *)spki->signature->data; + for (i = 0; i < n; i++) { + if ((i % 18) == 0) + BIO_write(out, "\n ", 7); + BIO_printf(out, "%02x%s", (unsigned char)s[i], + ((i + 1) == n) ? "" : ":"); + } + BIO_write(out, "\n", 1); + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3712-ossl_cmp_hdr_push1_freet/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2021-3712-ossl_cmp_hdr_push1_freet/fixed.c new file mode 100644 index 0000000..5e0a4af --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3712-ossl_cmp_hdr_push1_freet/fixed.c @@ -0,0 +1,24 @@ +/* Provenance: openssl/openssl ossl_cmp_hdr_push1_freeText (fixed). + * repo: openssl/openssl + * commit: 95f8c1e142df835d03b5b62521383a462fc5470d + * parent: d2015a783e64613d8e4a142fa05048d1863df944 + * commit_url: https://github.com/openssl/openssl/commit/95f8c1e142df835d03b5b62521383a462fc5470d + * cve: CVE-2021-3712 + * license: OpenSSL License + * function: ossl_cmp_hdr_push1_freeText + * relpath: crypto/cmp/cmp_hdr.c + */ + +int ossl_cmp_hdr_push1_freeText(OSSL_CMP_PKIHEADER *hdr, ASN1_UTF8STRING *text) +{ + if (!ossl_assert(hdr != NULL && text != NULL)) + return 0; + + if (hdr->freeText == NULL + && (hdr->freeText = sk_ASN1_UTF8STRING_new_null()) == NULL) + return 0; + + return + ossl_cmp_sk_ASN1_UTF8STRING_push_str(hdr->freeText, (char *)text->data, + text->length); +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3712-ossl_cmp_hdr_push1_freet/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2021-3712-ossl_cmp_hdr_push1_freet/vuln.c new file mode 100644 index 0000000..dc12ae0 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3712-ossl_cmp_hdr_push1_freet/vuln.c @@ -0,0 +1,23 @@ +/* Provenance: openssl/openssl ossl_cmp_hdr_push1_freeText (vuln). + * repo: openssl/openssl + * commit: d2015a783e64613d8e4a142fa05048d1863df944 + * parent: d2015a783e64613d8e4a142fa05048d1863df944 + * commit_url: https://github.com/openssl/openssl/commit/95f8c1e142df835d03b5b62521383a462fc5470d + * cve: CVE-2021-3712 + * license: OpenSSL License + * function: ossl_cmp_hdr_push1_freeText + * relpath: crypto/cmp/cmp_hdr.c + */ + +int ossl_cmp_hdr_push1_freeText(OSSL_CMP_PKIHEADER *hdr, ASN1_UTF8STRING *text) +{ + if (!ossl_assert(hdr != NULL && text != NULL)) + return 0; + + if (hdr->freeText == NULL + && (hdr->freeText = sk_ASN1_UTF8STRING_new_null()) == NULL) + return 0; + + return + ossl_cmp_sk_ASN1_UTF8STRING_push_str(hdr->freeText, (char *)text->data); +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3712-print_qualifiers/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2021-3712-print_qualifiers/fixed.c new file mode 100644 index 0000000..1af5e7b --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3712-print_qualifiers/fixed.c @@ -0,0 +1,40 @@ +/* Provenance: openssl/openssl print_qualifiers (fixed). + * repo: openssl/openssl + * commit: 1747d4658b3830951068a6a6c1fa2b45c4731fb3 + * parent: ad6ac17489241574136b7d035f01f6175dd9c941 + * commit_url: https://github.com/openssl/openssl/commit/1747d4658b3830951068a6a6c1fa2b45c4731fb3 + * cve: CVE-2021-3712 + * license: OpenSSL License + * function: print_qualifiers + * relpath: crypto/x509/v3_cpols.c + */ + +static void print_qualifiers(BIO *out, STACK_OF(POLICYQUALINFO) *quals, + int indent) +{ + POLICYQUALINFO *qualinfo; + int i; + for (i = 0; i < sk_POLICYQUALINFO_num(quals); i++) { + if (i > 0) + BIO_puts(out, "\n"); + qualinfo = sk_POLICYQUALINFO_value(quals, i); + switch (OBJ_obj2nid(qualinfo->pqualid)) { + case NID_id_qt_cps: + BIO_printf(out, "%*sCPS: %.*s", indent, "", + qualinfo->d.cpsuri->length, + qualinfo->d.cpsuri->data); + break; + + case NID_id_qt_unotice: + BIO_printf(out, "%*sUser Notice:\n", indent, ""); + print_notice(out, qualinfo->d.usernotice, indent + 2); + break; + + default: + BIO_printf(out, "%*sUnknown Qualifier: ", indent + 2, ""); + + i2a_ASN1_OBJECT(out, qualinfo->pqualid); + break; + } + } +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3712-print_qualifiers/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2021-3712-print_qualifiers/vuln.c new file mode 100644 index 0000000..b967533 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3712-print_qualifiers/vuln.c @@ -0,0 +1,39 @@ +/* Provenance: openssl/openssl print_qualifiers (vuln). + * repo: openssl/openssl + * commit: ad6ac17489241574136b7d035f01f6175dd9c941 + * parent: ad6ac17489241574136b7d035f01f6175dd9c941 + * commit_url: https://github.com/openssl/openssl/commit/1747d4658b3830951068a6a6c1fa2b45c4731fb3 + * cve: CVE-2021-3712 + * license: OpenSSL License + * function: print_qualifiers + * relpath: crypto/x509/v3_cpols.c + */ + +static void print_qualifiers(BIO *out, STACK_OF(POLICYQUALINFO) *quals, + int indent) +{ + POLICYQUALINFO *qualinfo; + int i; + for (i = 0; i < sk_POLICYQUALINFO_num(quals); i++) { + if (i > 0) + BIO_puts(out, "\n"); + qualinfo = sk_POLICYQUALINFO_value(quals, i); + switch (OBJ_obj2nid(qualinfo->pqualid)) { + case NID_id_qt_cps: + BIO_printf(out, "%*sCPS: %s", indent, "", + qualinfo->d.cpsuri->data); + break; + + case NID_id_qt_unotice: + BIO_printf(out, "%*sUser Notice:\n", indent, ""); + print_notice(out, qualinfo->d.usernotice, indent + 2); + break; + + default: + BIO_printf(out, "%*sUnknown Qualifier: ", indent + 2, ""); + + i2a_ASN1_OBJECT(out, qualinfo->pqualid); + break; + } + } +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3712/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2021-3712/fixed.c new file mode 100644 index 0000000..61e0d9e --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3712/fixed.c @@ -0,0 +1,45 @@ +/* Provenance: openssl/openssl append_ia5 (fixed). + * repo: openssl/openssl + * commit: 98624776c4d501c8badd6f772ab7048ac9191cb9 + * parent: 1f365708a3318a5f1a395f90c38b584a58d37fb9 + * commit_url: https://github.com/openssl/openssl/commit/98624776c4d501c8badd6f772ab7048ac9191cb9 + * cve: CVE-2021-3712 + * license: OpenSSL License + * function: append_ia5 + * relpath: crypto/x509/v3_utl.c + */ + +static int append_ia5(STACK_OF(OPENSSL_STRING) **sk, + const ASN1_IA5STRING *email) +{ + char *emtmp; + + /* First some sanity checks */ + if (email->type != V_ASN1_IA5STRING) + return 1; + if (email->data == NULL || email->length == 0) + return 1; + if (memchr(email->data, 0, email->length) != NULL) + return 1; + if (*sk == NULL) + *sk = sk_OPENSSL_STRING_new(sk_strcmp); + if (*sk == NULL) + return 0; + + emtmp = OPENSSL_strndup((char *)email->data, email->length); + if (emtmp == NULL) + return 0; + + /* Don't add duplicates */ + if (sk_OPENSSL_STRING_find(*sk, emtmp) != -1) { + OPENSSL_free(emtmp); + return 1; + } + if (!sk_OPENSSL_STRING_push(*sk, emtmp)) { + OPENSSL_free(emtmp); /* free on push failure */ + X509_email_free(*sk); + *sk = NULL; + return 0; + } + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-3712/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2021-3712/vuln.c new file mode 100644 index 0000000..9b22783 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-3712/vuln.c @@ -0,0 +1,37 @@ +/* Provenance: openssl/openssl append_ia5 (vuln). + * repo: openssl/openssl + * commit: 1f365708a3318a5f1a395f90c38b584a58d37fb9 + * parent: 1f365708a3318a5f1a395f90c38b584a58d37fb9 + * commit_url: https://github.com/openssl/openssl/commit/98624776c4d501c8badd6f772ab7048ac9191cb9 + * cve: CVE-2021-3712 + * license: OpenSSL License + * function: append_ia5 + * relpath: crypto/x509/v3_utl.c + */ + +static int append_ia5(STACK_OF(OPENSSL_STRING) **sk, + const ASN1_IA5STRING *email) +{ + char *emtmp; + + /* First some sanity checks */ + if (email->type != V_ASN1_IA5STRING) + return 1; + if (!email->data || !email->length) + return 1; + if (*sk == NULL) + *sk = sk_OPENSSL_STRING_new(sk_strcmp); + if (*sk == NULL) + return 0; + /* Don't add duplicates */ + if (sk_OPENSSL_STRING_find(*sk, (char *)email->data) != -1) + return 1; + emtmp = OPENSSL_strdup((char *)email->data); + if (emtmp == NULL || !sk_OPENSSL_STRING_push(*sk, emtmp)) { + OPENSSL_free(emtmp); /* free on push failure */ + X509_email_free(*sk); + *sk = NULL; + return 0; + } + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-4044-tls_post_process_server_/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2021-4044-tls_post_process_server_/fixed.c new file mode 100644 index 0000000..9b19e2d --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-4044-tls_post_process_server_/fixed.c @@ -0,0 +1,90 @@ +/* Provenance: openssl/openssl tls_post_process_server_certificate (fixed). + * repo: openssl/openssl + * commit: 758754966791c537ea95241438454aa86f91f256 + * parent: 8e78289c4e6f4c9f2fec073b78443736e689854d + * commit_url: https://github.com/openssl/openssl/commit/758754966791c537ea95241438454aa86f91f256 + * cve: CVE-2021-4044 + * license: OpenSSL License + * function: tls_post_process_server_certificate + * relpath: ssl/statem/statem_clnt.c + */ + +WORK_STATE tls_post_process_server_certificate(SSL *s, WORK_STATE wst) +{ + X509 *x; + EVP_PKEY *pkey = NULL; + const SSL_CERT_LOOKUP *clu; + size_t certidx; + int i; + + i = ssl_verify_cert_chain(s, s->session->peer_chain); + if (i == -1) { + s->rwstate = SSL_RETRY_VERIFY; + return WORK_MORE_A; + } + /* + * The documented interface is that SSL_VERIFY_PEER should be set in order + * for client side verification of the server certificate to take place. + * However, historically the code has only checked that *any* flag is set + * to cause server verification to take place. Use of the other flags makes + * no sense in client mode. An attempt to clean up the semantics was + * reverted because at least one application *only* set + * SSL_VERIFY_FAIL_IF_NO_PEER_CERT. Prior to the clean up this still caused + * server verification to take place, after the clean up it silently did + * nothing. SSL_CTX_set_verify()/SSL_set_verify() cannot validate the flags + * sent to them because they are void functions. Therefore, we now use the + * (less clean) historic behaviour of performing validation if any flag is + * set. The *documented* interface remains the same. + */ + if (s->verify_mode != SSL_VERIFY_NONE && i == 0) { + SSLfatal(s, ssl_x509err2alert(s->verify_result), + SSL_R_CERTIFICATE_VERIFY_FAILED); + return WORK_ERROR; + } + ERR_clear_error(); /* but we keep s->verify_result */ + + /* + * Inconsistency alert: cert_chain does include the peer's certificate, + * which we don't include in statem_srvr.c + */ + x = sk_X509_value(s->session->peer_chain, 0); + + pkey = X509_get0_pubkey(x); + + if (pkey == NULL || EVP_PKEY_missing_parameters(pkey)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS); + return WORK_ERROR; + } + + if ((clu = ssl_cert_lookup_by_pkey(pkey, &certidx)) == NULL) { + SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_UNKNOWN_CERTIFICATE_TYPE); + return WORK_ERROR; + } + /* + * Check certificate type is consistent with ciphersuite. For TLS 1.3 + * skip check since TLS 1.3 ciphersuites can be used with any certificate + * type. + */ + if (!SSL_IS_TLS13(s)) { + if ((clu->amask & s->s3.tmp.new_cipher->algorithm_auth) == 0) { + SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_WRONG_CERTIFICATE_TYPE); + return WORK_ERROR; + } + } + + X509_free(s->session->peer); + X509_up_ref(x); + s->session->peer = x; + s->session->verify_result = s->verify_result; + + /* Save the current hash state for when we receive the CertificateVerify */ + if (SSL_IS_TLS13(s) + && !ssl_handshake_hash(s, s->cert_verify_hash, + sizeof(s->cert_verify_hash), + &s->cert_verify_hash_len)) { + /* SSLfatal() already called */; + return WORK_ERROR; + } + return WORK_FINISHED_CONTINUE; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-4044-tls_post_process_server_/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2021-4044-tls_post_process_server_/vuln.c new file mode 100644 index 0000000..60318e2 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-4044-tls_post_process_server_/vuln.c @@ -0,0 +1,90 @@ +/* Provenance: openssl/openssl tls_post_process_server_certificate (vuln). + * repo: openssl/openssl + * commit: 8e78289c4e6f4c9f2fec073b78443736e689854d + * parent: 8e78289c4e6f4c9f2fec073b78443736e689854d + * commit_url: https://github.com/openssl/openssl/commit/758754966791c537ea95241438454aa86f91f256 + * cve: CVE-2021-4044 + * license: OpenSSL License + * function: tls_post_process_server_certificate + * relpath: ssl/statem/statem_clnt.c + */ + +WORK_STATE tls_post_process_server_certificate(SSL *s, WORK_STATE wst) +{ + X509 *x; + EVP_PKEY *pkey = NULL; + const SSL_CERT_LOOKUP *clu; + size_t certidx; + int i; + + i = ssl_verify_cert_chain(s, s->session->peer_chain); + if (i == -1) { + s->rwstate = SSL_RETRY_VERIFY; + return WORK_MORE_A; + } + /* + * The documented interface is that SSL_VERIFY_PEER should be set in order + * for client side verification of the server certificate to take place. + * However, historically the code has only checked that *any* flag is set + * to cause server verification to take place. Use of the other flags makes + * no sense in client mode. An attempt to clean up the semantics was + * reverted because at least one application *only* set + * SSL_VERIFY_FAIL_IF_NO_PEER_CERT. Prior to the clean up this still caused + * server verification to take place, after the clean up it silently did + * nothing. SSL_CTX_set_verify()/SSL_set_verify() cannot validate the flags + * sent to them because they are void functions. Therefore, we now use the + * (less clean) historic behaviour of performing validation if any flag is + * set. The *documented* interface remains the same. + */ + if (s->verify_mode != SSL_VERIFY_NONE && i <= 0) { + SSLfatal(s, ssl_x509err2alert(s->verify_result), + SSL_R_CERTIFICATE_VERIFY_FAILED); + return WORK_ERROR; + } + ERR_clear_error(); /* but we keep s->verify_result */ + + /* + * Inconsistency alert: cert_chain does include the peer's certificate, + * which we don't include in statem_srvr.c + */ + x = sk_X509_value(s->session->peer_chain, 0); + + pkey = X509_get0_pubkey(x); + + if (pkey == NULL || EVP_PKEY_missing_parameters(pkey)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS); + return WORK_ERROR; + } + + if ((clu = ssl_cert_lookup_by_pkey(pkey, &certidx)) == NULL) { + SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_UNKNOWN_CERTIFICATE_TYPE); + return WORK_ERROR; + } + /* + * Check certificate type is consistent with ciphersuite. For TLS 1.3 + * skip check since TLS 1.3 ciphersuites can be used with any certificate + * type. + */ + if (!SSL_IS_TLS13(s)) { + if ((clu->amask & s->s3.tmp.new_cipher->algorithm_auth) == 0) { + SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_WRONG_CERTIFICATE_TYPE); + return WORK_ERROR; + } + } + + X509_free(s->session->peer); + X509_up_ref(x); + s->session->peer = x; + s->session->verify_result = s->verify_result; + + /* Save the current hash state for when we receive the CertificateVerify */ + if (SSL_IS_TLS13(s) + && !ssl_handshake_hash(s, s->cert_verify_hash, + sizeof(s->cert_verify_hash), + &s->cert_verify_hash_len)) { + /* SSLfatal() already called */; + return WORK_ERROR; + } + return WORK_FINISHED_CONTINUE; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-4044/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2021-4044/fixed.c new file mode 100644 index 0000000..78cb379 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-4044/fixed.c @@ -0,0 +1,31 @@ +/* Provenance: openssl/openssl has_san_id (fixed). + * repo: openssl/openssl + * commit: d69ae8a93bfc0f2489c008fcf303a98d77a6df4d + * parent: 758754966791c537ea95241438454aa86f91f256 + * commit_url: https://github.com/openssl/openssl/commit/d69ae8a93bfc0f2489c008fcf303a98d77a6df4d + * cve: CVE-2021-4044 + * license: OpenSSL License + * function: has_san_id + * relpath: crypto/x509/x509_vfy.c + */ + +static int has_san_id(X509 *x, int gtype) +{ + int i; + int ret = 0; + GENERAL_NAMES *gs = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL); + + if (gs == NULL) + return 0; + + for (i = 0; i < sk_GENERAL_NAME_num(gs); i++) { + GENERAL_NAME *g = sk_GENERAL_NAME_value(gs, i); + + if (g->type == gtype) { + ret = 1; + break; + } + } + GENERAL_NAMES_free(gs); + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2021-4044/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2021-4044/vuln.c new file mode 100644 index 0000000..0495909 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2021-4044/vuln.c @@ -0,0 +1,31 @@ +/* Provenance: openssl/openssl has_san_id (vuln). + * repo: openssl/openssl + * commit: 758754966791c537ea95241438454aa86f91f256 + * parent: 758754966791c537ea95241438454aa86f91f256 + * commit_url: https://github.com/openssl/openssl/commit/d69ae8a93bfc0f2489c008fcf303a98d77a6df4d + * cve: CVE-2021-4044 + * license: OpenSSL License + * function: has_san_id + * relpath: crypto/x509/x509_vfy.c + */ + +static int has_san_id(X509 *x, int gtype) +{ + int i; + int ret = 0; + GENERAL_NAMES *gs = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL); + + if (gs == NULL) + return -1; + + for (i = 0; i < sk_GENERAL_NAME_num(gs); i++) { + GENERAL_NAME *g = sk_GENERAL_NAME_value(gs, i); + + if (g->type == gtype) { + ret = 1; + break; + } + } + GENERAL_NAMES_free(gs); + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-0778/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2022-0778/fixed.c new file mode 100644 index 0000000..b4eb067 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-0778/fixed.c @@ -0,0 +1,367 @@ +/* Provenance: openssl/openssl BN_mod_sqrt (fixed). + * repo: openssl/openssl + * commit: 9eafb53614bf65797db25f467946e735e1b43dc9 + * parent: 1832bb0f02e519a48f06a10467c7ce5f7f3feeeb + * commit_url: https://github.com/openssl/openssl/commit/9eafb53614bf65797db25f467946e735e1b43dc9 + * cve: CVE-2022-0778 + * license: Apache-2.0 + * function: BN_mod_sqrt + * relpath: crypto/bn/bn_sqrt.c + */ + +BIGNUM *BN_mod_sqrt(BIGNUM *in, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx) +/* + * Returns 'ret' such that ret^2 == a (mod p), using the Tonelli/Shanks + * algorithm (cf. Henri Cohen, "A Course in Algebraic Computational Number + * Theory", algorithm 1.5.1). 'p' must be prime, otherwise an error or + * an incorrect "result" will be returned. + */ +{ + BIGNUM *ret = in; + int err = 1; + int r; + BIGNUM *A, *b, *q, *t, *x, *y; + int e, i, j; + int used_ctx = 0; + + if (!BN_is_odd(p) || BN_abs_is_word(p, 1)) { + if (BN_abs_is_word(p, 2)) { + if (ret == NULL) + ret = BN_new(); + if (ret == NULL) + goto end; + if (!BN_set_word(ret, BN_is_bit_set(a, 0))) { + if (ret != in) + BN_free(ret); + return NULL; + } + bn_check_top(ret); + return ret; + } + + ERR_raise(ERR_LIB_BN, BN_R_P_IS_NOT_PRIME); + return NULL; + } + + if (BN_is_zero(a) || BN_is_one(a)) { + if (ret == NULL) + ret = BN_new(); + if (ret == NULL) + goto end; + if (!BN_set_word(ret, BN_is_one(a))) { + if (ret != in) + BN_free(ret); + return NULL; + } + bn_check_top(ret); + return ret; + } + + BN_CTX_start(ctx); + used_ctx = 1; + A = BN_CTX_get(ctx); + b = BN_CTX_get(ctx); + q = BN_CTX_get(ctx); + t = BN_CTX_get(ctx); + x = BN_CTX_get(ctx); + y = BN_CTX_get(ctx); + if (y == NULL) + goto end; + + if (ret == NULL) + ret = BN_new(); + if (ret == NULL) + goto end; + + /* A = a mod p */ + if (!BN_nnmod(A, a, p, ctx)) + goto end; + + /* now write |p| - 1 as 2^e*q where q is odd */ + e = 1; + while (!BN_is_bit_set(p, e)) + e++; + /* we'll set q later (if needed) */ + + if (e == 1) { + /*- + * The easy case: (|p|-1)/2 is odd, so 2 has an inverse + * modulo (|p|-1)/2, and square roots can be computed + * directly by modular exponentiation. + * We have + * 2 * (|p|+1)/4 == 1 (mod (|p|-1)/2), + * so we can use exponent (|p|+1)/4, i.e. (|p|-3)/4 + 1. + */ + if (!BN_rshift(q, p, 2)) + goto end; + q->neg = 0; + if (!BN_add_word(q, 1)) + goto end; + if (!BN_mod_exp(ret, A, q, p, ctx)) + goto end; + err = 0; + goto vrfy; + } + + if (e == 2) { + /*- + * |p| == 5 (mod 8) + * + * In this case 2 is always a non-square since + * Legendre(2,p) = (-1)^((p^2-1)/8) for any odd prime. + * So if a really is a square, then 2*a is a non-square. + * Thus for + * b := (2*a)^((|p|-5)/8), + * i := (2*a)*b^2 + * we have + * i^2 = (2*a)^((1 + (|p|-5)/4)*2) + * = (2*a)^((p-1)/2) + * = -1; + * so if we set + * x := a*b*(i-1), + * then + * x^2 = a^2 * b^2 * (i^2 - 2*i + 1) + * = a^2 * b^2 * (-2*i) + * = a*(-i)*(2*a*b^2) + * = a*(-i)*i + * = a. + * + * (This is due to A.O.L. Atkin, + * Subject: Square Roots and Cognate Matters modulo p=8n+5. + * URL: https://listserv.nodak.edu/cgi-bin/wa.exe?A2=ind9211&L=NMBRTHRY&P=4026 + * November 1992.) + */ + + /* t := 2*a */ + if (!BN_mod_lshift1_quick(t, A, p)) + goto end; + + /* b := (2*a)^((|p|-5)/8) */ + if (!BN_rshift(q, p, 3)) + goto end; + q->neg = 0; + if (!BN_mod_exp(b, t, q, p, ctx)) + goto end; + + /* y := b^2 */ + if (!BN_mod_sqr(y, b, p, ctx)) + goto end; + + /* t := (2*a)*b^2 - 1 */ + if (!BN_mod_mul(t, t, y, p, ctx)) + goto end; + if (!BN_sub_word(t, 1)) + goto end; + + /* x = a*b*t */ + if (!BN_mod_mul(x, A, b, p, ctx)) + goto end; + if (!BN_mod_mul(x, x, t, p, ctx)) + goto end; + + if (!BN_copy(ret, x)) + goto end; + err = 0; + goto vrfy; + } + + /* + * e > 2, so we really have to use the Tonelli/Shanks algorithm. First, + * find some y that is not a square. + */ + if (!BN_copy(q, p)) + goto end; /* use 'q' as temp */ + q->neg = 0; + i = 2; + do { + /* + * For efficiency, try small numbers first; if this fails, try random + * numbers. + */ + if (i < 22) { + if (!BN_set_word(y, i)) + goto end; + } else { + if (!BN_priv_rand_ex(y, BN_num_bits(p), 0, 0, 0, ctx)) + goto end; + if (BN_ucmp(y, p) >= 0) { + if (!(p->neg ? BN_add : BN_sub) (y, y, p)) + goto end; + } + /* now 0 <= y < |p| */ + if (BN_is_zero(y)) + if (!BN_set_word(y, i)) + goto end; + } + + r = BN_kronecker(y, q, ctx); /* here 'q' is |p| */ + if (r < -1) + goto end; + if (r == 0) { + /* m divides p */ + ERR_raise(ERR_LIB_BN, BN_R_P_IS_NOT_PRIME); + goto end; + } + } + while (r == 1 && ++i < 82); + + if (r != -1) { + /* + * Many rounds and still no non-square -- this is more likely a bug + * than just bad luck. Even if p is not prime, we should have found + * some y such that r == -1. + */ + ERR_raise(ERR_LIB_BN, BN_R_TOO_MANY_ITERATIONS); + goto end; + } + + /* Here's our actual 'q': */ + if (!BN_rshift(q, q, e)) + goto end; + + /* + * Now that we have some non-square, we can find an element of order 2^e + * by computing its q'th power. + */ + if (!BN_mod_exp(y, y, q, p, ctx)) + goto end; + if (BN_is_one(y)) { + ERR_raise(ERR_LIB_BN, BN_R_P_IS_NOT_PRIME); + goto end; + } + + /*- + * Now we know that (if p is indeed prime) there is an integer + * k, 0 <= k < 2^e, such that + * + * a^q * y^k == 1 (mod p). + * + * As a^q is a square and y is not, k must be even. + * q+1 is even, too, so there is an element + * + * X := a^((q+1)/2) * y^(k/2), + * + * and it satisfies + * + * X^2 = a^q * a * y^k + * = a, + * + * so it is the square root that we are looking for. + */ + + /* t := (q-1)/2 (note that q is odd) */ + if (!BN_rshift1(t, q)) + goto end; + + /* x := a^((q-1)/2) */ + if (BN_is_zero(t)) { /* special case: p = 2^e + 1 */ + if (!BN_nnmod(t, A, p, ctx)) + goto end; + if (BN_is_zero(t)) { + /* special case: a == 0 (mod p) */ + BN_zero(ret); + err = 0; + goto end; + } else if (!BN_one(x)) + goto end; + } else { + if (!BN_mod_exp(x, A, t, p, ctx)) + goto end; + if (BN_is_zero(x)) { + /* special case: a == 0 (mod p) */ + BN_zero(ret); + err = 0; + goto end; + } + } + + /* b := a*x^2 (= a^q) */ + if (!BN_mod_sqr(b, x, p, ctx)) + goto end; + if (!BN_mod_mul(b, b, A, p, ctx)) + goto end; + + /* x := a*x (= a^((q+1)/2)) */ + if (!BN_mod_mul(x, x, A, p, ctx)) + goto end; + + while (1) { + /*- + * Now b is a^q * y^k for some even k (0 <= k < 2^E + * where E refers to the original value of e, which we + * don't keep in a variable), and x is a^((q+1)/2) * y^(k/2). + * + * We have a*b = x^2, + * y^2^(e-1) = -1, + * b^2^(e-1) = 1. + */ + + if (BN_is_one(b)) { + if (!BN_copy(ret, x)) + goto end; + err = 0; + goto vrfy; + } + + /* Find the smallest i, 0 < i < e, such that b^(2^i) = 1. */ + for (i = 1; i < e; i++) { + if (i == 1) { + if (!BN_mod_sqr(t, b, p, ctx)) + goto end; + + } else { + if (!BN_mod_mul(t, t, t, p, ctx)) + goto end; + } + if (BN_is_one(t)) + break; + } + /* If not found, a is not a square or p is not prime. */ + if (i >= e) { + ERR_raise(ERR_LIB_BN, BN_R_NOT_A_SQUARE); + goto end; + } + + /* t := y^2^(e - i - 1) */ + if (!BN_copy(t, y)) + goto end; + for (j = e - i - 1; j > 0; j--) { + if (!BN_mod_sqr(t, t, p, ctx)) + goto end; + } + if (!BN_mod_mul(y, t, t, p, ctx)) + goto end; + if (!BN_mod_mul(x, x, t, p, ctx)) + goto end; + if (!BN_mod_mul(b, b, y, p, ctx)) + goto end; + e = i; + } + + vrfy: + if (!err) { + /* + * verify the result -- the input might have been not a square (test + * added in 0.9.8) + */ + + if (!BN_mod_sqr(x, ret, p, ctx)) + err = 1; + + if (!err && 0 != BN_cmp(x, A)) { + ERR_raise(ERR_LIB_BN, BN_R_NOT_A_SQUARE); + err = 1; + } + } + + end: + if (err) { + if (ret != in) + BN_clear_free(ret); + ret = NULL; + } + if (used_ctx) + BN_CTX_end(ctx); + bn_check_top(ret); + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-0778/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2022-0778/vuln.c new file mode 100644 index 0000000..e676f3a --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-0778/vuln.c @@ -0,0 +1,361 @@ +/* Provenance: openssl/openssl BN_mod_sqrt (vuln). + * repo: openssl/openssl + * commit: 1832bb0f02e519a48f06a10467c7ce5f7f3feeeb + * parent: 1832bb0f02e519a48f06a10467c7ce5f7f3feeeb + * commit_url: https://github.com/openssl/openssl/commit/9eafb53614bf65797db25f467946e735e1b43dc9 + * cve: CVE-2022-0778 + * license: Apache-2.0 + * function: BN_mod_sqrt + * relpath: crypto/bn/bn_sqrt.c + */ + +BIGNUM *BN_mod_sqrt(BIGNUM *in, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx) +/* + * Returns 'ret' such that ret^2 == a (mod p), using the Tonelli/Shanks + * algorithm (cf. Henri Cohen, "A Course in Algebraic Computational Number + * Theory", algorithm 1.5.1). 'p' must be prime! + */ +{ + BIGNUM *ret = in; + int err = 1; + int r; + BIGNUM *A, *b, *q, *t, *x, *y; + int e, i, j; + int used_ctx = 0; + + if (!BN_is_odd(p) || BN_abs_is_word(p, 1)) { + if (BN_abs_is_word(p, 2)) { + if (ret == NULL) + ret = BN_new(); + if (ret == NULL) + goto end; + if (!BN_set_word(ret, BN_is_bit_set(a, 0))) { + if (ret != in) + BN_free(ret); + return NULL; + } + bn_check_top(ret); + return ret; + } + + ERR_raise(ERR_LIB_BN, BN_R_P_IS_NOT_PRIME); + return NULL; + } + + if (BN_is_zero(a) || BN_is_one(a)) { + if (ret == NULL) + ret = BN_new(); + if (ret == NULL) + goto end; + if (!BN_set_word(ret, BN_is_one(a))) { + if (ret != in) + BN_free(ret); + return NULL; + } + bn_check_top(ret); + return ret; + } + + BN_CTX_start(ctx); + used_ctx = 1; + A = BN_CTX_get(ctx); + b = BN_CTX_get(ctx); + q = BN_CTX_get(ctx); + t = BN_CTX_get(ctx); + x = BN_CTX_get(ctx); + y = BN_CTX_get(ctx); + if (y == NULL) + goto end; + + if (ret == NULL) + ret = BN_new(); + if (ret == NULL) + goto end; + + /* A = a mod p */ + if (!BN_nnmod(A, a, p, ctx)) + goto end; + + /* now write |p| - 1 as 2^e*q where q is odd */ + e = 1; + while (!BN_is_bit_set(p, e)) + e++; + /* we'll set q later (if needed) */ + + if (e == 1) { + /*- + * The easy case: (|p|-1)/2 is odd, so 2 has an inverse + * modulo (|p|-1)/2, and square roots can be computed + * directly by modular exponentiation. + * We have + * 2 * (|p|+1)/4 == 1 (mod (|p|-1)/2), + * so we can use exponent (|p|+1)/4, i.e. (|p|-3)/4 + 1. + */ + if (!BN_rshift(q, p, 2)) + goto end; + q->neg = 0; + if (!BN_add_word(q, 1)) + goto end; + if (!BN_mod_exp(ret, A, q, p, ctx)) + goto end; + err = 0; + goto vrfy; + } + + if (e == 2) { + /*- + * |p| == 5 (mod 8) + * + * In this case 2 is always a non-square since + * Legendre(2,p) = (-1)^((p^2-1)/8) for any odd prime. + * So if a really is a square, then 2*a is a non-square. + * Thus for + * b := (2*a)^((|p|-5)/8), + * i := (2*a)*b^2 + * we have + * i^2 = (2*a)^((1 + (|p|-5)/4)*2) + * = (2*a)^((p-1)/2) + * = -1; + * so if we set + * x := a*b*(i-1), + * then + * x^2 = a^2 * b^2 * (i^2 - 2*i + 1) + * = a^2 * b^2 * (-2*i) + * = a*(-i)*(2*a*b^2) + * = a*(-i)*i + * = a. + * + * (This is due to A.O.L. Atkin, + * Subject: Square Roots and Cognate Matters modulo p=8n+5. + * URL: https://listserv.nodak.edu/cgi-bin/wa.exe?A2=ind9211&L=NMBRTHRY&P=4026 + * November 1992.) + */ + + /* t := 2*a */ + if (!BN_mod_lshift1_quick(t, A, p)) + goto end; + + /* b := (2*a)^((|p|-5)/8) */ + if (!BN_rshift(q, p, 3)) + goto end; + q->neg = 0; + if (!BN_mod_exp(b, t, q, p, ctx)) + goto end; + + /* y := b^2 */ + if (!BN_mod_sqr(y, b, p, ctx)) + goto end; + + /* t := (2*a)*b^2 - 1 */ + if (!BN_mod_mul(t, t, y, p, ctx)) + goto end; + if (!BN_sub_word(t, 1)) + goto end; + + /* x = a*b*t */ + if (!BN_mod_mul(x, A, b, p, ctx)) + goto end; + if (!BN_mod_mul(x, x, t, p, ctx)) + goto end; + + if (!BN_copy(ret, x)) + goto end; + err = 0; + goto vrfy; + } + + /* + * e > 2, so we really have to use the Tonelli/Shanks algorithm. First, + * find some y that is not a square. + */ + if (!BN_copy(q, p)) + goto end; /* use 'q' as temp */ + q->neg = 0; + i = 2; + do { + /* + * For efficiency, try small numbers first; if this fails, try random + * numbers. + */ + if (i < 22) { + if (!BN_set_word(y, i)) + goto end; + } else { + if (!BN_priv_rand_ex(y, BN_num_bits(p), 0, 0, 0, ctx)) + goto end; + if (BN_ucmp(y, p) >= 0) { + if (!(p->neg ? BN_add : BN_sub) (y, y, p)) + goto end; + } + /* now 0 <= y < |p| */ + if (BN_is_zero(y)) + if (!BN_set_word(y, i)) + goto end; + } + + r = BN_kronecker(y, q, ctx); /* here 'q' is |p| */ + if (r < -1) + goto end; + if (r == 0) { + /* m divides p */ + ERR_raise(ERR_LIB_BN, BN_R_P_IS_NOT_PRIME); + goto end; + } + } + while (r == 1 && ++i < 82); + + if (r != -1) { + /* + * Many rounds and still no non-square -- this is more likely a bug + * than just bad luck. Even if p is not prime, we should have found + * some y such that r == -1. + */ + ERR_raise(ERR_LIB_BN, BN_R_TOO_MANY_ITERATIONS); + goto end; + } + + /* Here's our actual 'q': */ + if (!BN_rshift(q, q, e)) + goto end; + + /* + * Now that we have some non-square, we can find an element of order 2^e + * by computing its q'th power. + */ + if (!BN_mod_exp(y, y, q, p, ctx)) + goto end; + if (BN_is_one(y)) { + ERR_raise(ERR_LIB_BN, BN_R_P_IS_NOT_PRIME); + goto end; + } + + /*- + * Now we know that (if p is indeed prime) there is an integer + * k, 0 <= k < 2^e, such that + * + * a^q * y^k == 1 (mod p). + * + * As a^q is a square and y is not, k must be even. + * q+1 is even, too, so there is an element + * + * X := a^((q+1)/2) * y^(k/2), + * + * and it satisfies + * + * X^2 = a^q * a * y^k + * = a, + * + * so it is the square root that we are looking for. + */ + + /* t := (q-1)/2 (note that q is odd) */ + if (!BN_rshift1(t, q)) + goto end; + + /* x := a^((q-1)/2) */ + if (BN_is_zero(t)) { /* special case: p = 2^e + 1 */ + if (!BN_nnmod(t, A, p, ctx)) + goto end; + if (BN_is_zero(t)) { + /* special case: a == 0 (mod p) */ + BN_zero(ret); + err = 0; + goto end; + } else if (!BN_one(x)) + goto end; + } else { + if (!BN_mod_exp(x, A, t, p, ctx)) + goto end; + if (BN_is_zero(x)) { + /* special case: a == 0 (mod p) */ + BN_zero(ret); + err = 0; + goto end; + } + } + + /* b := a*x^2 (= a^q) */ + if (!BN_mod_sqr(b, x, p, ctx)) + goto end; + if (!BN_mod_mul(b, b, A, p, ctx)) + goto end; + + /* x := a*x (= a^((q+1)/2)) */ + if (!BN_mod_mul(x, x, A, p, ctx)) + goto end; + + while (1) { + /*- + * Now b is a^q * y^k for some even k (0 <= k < 2^E + * where E refers to the original value of e, which we + * don't keep in a variable), and x is a^((q+1)/2) * y^(k/2). + * + * We have a*b = x^2, + * y^2^(e-1) = -1, + * b^2^(e-1) = 1. + */ + + if (BN_is_one(b)) { + if (!BN_copy(ret, x)) + goto end; + err = 0; + goto vrfy; + } + + /* find smallest i such that b^(2^i) = 1 */ + i = 1; + if (!BN_mod_sqr(t, b, p, ctx)) + goto end; + while (!BN_is_one(t)) { + i++; + if (i == e) { + ERR_raise(ERR_LIB_BN, BN_R_NOT_A_SQUARE); + goto end; + } + if (!BN_mod_mul(t, t, t, p, ctx)) + goto end; + } + + /* t := y^2^(e - i - 1) */ + if (!BN_copy(t, y)) + goto end; + for (j = e - i - 1; j > 0; j--) { + if (!BN_mod_sqr(t, t, p, ctx)) + goto end; + } + if (!BN_mod_mul(y, t, t, p, ctx)) + goto end; + if (!BN_mod_mul(x, x, t, p, ctx)) + goto end; + if (!BN_mod_mul(b, b, y, p, ctx)) + goto end; + e = i; + } + + vrfy: + if (!err) { + /* + * verify the result -- the input might have been not a square (test + * added in 0.9.8) + */ + + if (!BN_mod_sqr(x, ret, p, ctx)) + err = 1; + + if (!err && 0 != BN_cmp(x, A)) { + ERR_raise(ERR_LIB_BN, BN_R_NOT_A_SQUARE); + err = 1; + } + } + + end: + if (err) { + if (ret != in) + BN_clear_free(ret); + ret = NULL; + } + if (used_ctx) + BN_CTX_end(ctx); + bn_check_top(ret); + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-1292/fixed.in b/benchmarks/pairs/vfc/openssl-cve-2022-1292/fixed.in new file mode 100644 index 0000000..5bee1ba --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-1292/fixed.in @@ -0,0 +1,51 @@ +/* Provenance: openssl/openssl link_hash_cert (fixed). + * repo: openssl/openssl + * commit: 1ad73b4d27bd8c1b369a3cd453681d3a4f1bb9b2 + * parent: 7d56a74a96828985db7354a55227a511615f732b + * commit_url: https://github.com/openssl/openssl/commit/1ad73b4d27bd8c1b369a3cd453681d3a4f1bb9b2 + * cve: CVE-2022-1292 + * license: Apache-2.0 + * function: link_hash_cert + * relpath: tools/c_rehash.in + */ + +sub link_hash_cert { + my $fname = $_[0]; + my ($hash, $fprint) = compute_hash($openssl, "x509", $x509hash, + "-fingerprint", "-noout", + "-in", $fname); + chomp $hash; + chomp $fprint; + return if !$hash; + $fprint =~ s/^.*=//; + $fprint =~ tr/://d; + my $suffix = 0; + # Search for an unused hash filename + while(exists $hashlist{"$hash.$suffix"}) { + # Hash matches: if fingerprint matches its a duplicate cert + if ($hashlist{"$hash.$suffix"} eq $fprint) { + print STDERR "WARNING: Skipping duplicate certificate $fname\n"; + return; + } + $suffix++; + } + $hash .= ".$suffix"; + if ($symlink_exists) { + print "link $fname -> $hash\n" if $verbose; + symlink $fname, $hash || warn "Can't symlink, $!"; + } else { + print "copy $fname -> $hash\n" if $verbose; + if (open($in, "<", $fname)) { + if (open($out,">", $hash)) { + print $out $_ while (<$in>); + close $out; + } else { + warn "can't open $hash for write, $!"; + } + close $in; + } else { + warn "can't open $fname for read, $!"; + } + } + $hashlist{$hash} = $fprint; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-1292/vuln.in b/benchmarks/pairs/vfc/openssl-cve-2022-1292/vuln.in new file mode 100644 index 0000000..c98f542 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-1292/vuln.in @@ -0,0 +1,49 @@ +/* Provenance: openssl/openssl link_hash_cert (vuln). + * repo: openssl/openssl + * commit: 7d56a74a96828985db7354a55227a511615f732b + * parent: 7d56a74a96828985db7354a55227a511615f732b + * commit_url: https://github.com/openssl/openssl/commit/1ad73b4d27bd8c1b369a3cd453681d3a4f1bb9b2 + * cve: CVE-2022-1292 + * license: Apache-2.0 + * function: link_hash_cert + * relpath: tools/c_rehash.in + */ + +sub link_hash_cert { + my $fname = $_[0]; + $fname =~ s/\"/\\\"/g; + my ($hash, $fprint) = `"$openssl" x509 $x509hash -fingerprint -noout -in "$fname"`; + chomp $hash; + chomp $fprint; + $fprint =~ s/^.*=//; + $fprint =~ tr/://d; + my $suffix = 0; + # Search for an unused hash filename + while(exists $hashlist{"$hash.$suffix"}) { + # Hash matches: if fingerprint matches its a duplicate cert + if ($hashlist{"$hash.$suffix"} eq $fprint) { + print STDERR "WARNING: Skipping duplicate certificate $fname\n"; + return; + } + $suffix++; + } + $hash .= ".$suffix"; + if ($symlink_exists) { + print "link $fname -> $hash\n" if $verbose; + symlink $fname, $hash || warn "Can't symlink, $!"; + } else { + print "copy $fname -> $hash\n" if $verbose; + if (open($in, "<", $fname)) { + if (open($out,">", $hash)) { + print $out $_ while (<$in>); + close $out; + } else { + warn "can't open $hash for write, $!"; + } + close $in; + } else { + warn "can't open $fname for read, $!"; + } + } + $hashlist{$hash} = $fprint; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-1343/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2022-1343/fixed.c new file mode 100644 index 0000000..36709ff --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-1343/fixed.c @@ -0,0 +1,56 @@ +/* Provenance: openssl/openssl ocsp_verify_signer (fixed). + * repo: openssl/openssl + * commit: 2eda98790c5c2741d76d23cc1e74b0dc4f4b391a + * parent: ae3ece03a61e8822fd7ea58f44812871efba82d1 + * commit_url: https://github.com/openssl/openssl/commit/2eda98790c5c2741d76d23cc1e74b0dc4f4b391a + * cve: CVE-2022-1343 + * license: Apache-2.0 + * function: ocsp_verify_signer + * relpath: crypto/ocsp/ocsp_vfy.c + */ + +static int ocsp_verify_signer(X509 *signer, int response, + X509_STORE *st, unsigned long flags, + STACK_OF(X509) *untrusted, STACK_OF(X509) **chain) +{ + X509_STORE_CTX *ctx = X509_STORE_CTX_new(); + X509_VERIFY_PARAM *vp; + int ret = -1; + + if (ctx == NULL) { + ERR_raise(ERR_LIB_OCSP, ERR_R_MALLOC_FAILURE); + goto end; + } + if (!X509_STORE_CTX_init(ctx, st, signer, untrusted)) { + ERR_raise(ERR_LIB_OCSP, ERR_R_X509_LIB); + goto end; + } + if ((vp = X509_STORE_CTX_get0_param(ctx)) == NULL) + goto end; + if ((flags & OCSP_PARTIAL_CHAIN) != 0) + X509_VERIFY_PARAM_set_flags(vp, X509_V_FLAG_PARTIAL_CHAIN); + if (response + && X509_get_ext_by_NID(signer, NID_id_pkix_OCSP_noCheck, -1) >= 0) + /* + * Locally disable revocation status checking for OCSP responder cert. + * Done here for CRLs; should be done also for OCSP-based checks. + */ + X509_VERIFY_PARAM_clear_flags(vp, X509_V_FLAG_CRL_CHECK); + X509_STORE_CTX_set_purpose(ctx, X509_PURPOSE_OCSP_HELPER); + X509_STORE_CTX_set_trust(ctx, X509_TRUST_OCSP_REQUEST); + + ret = X509_verify_cert(ctx); + if (ret <= 0) { + int err = X509_STORE_CTX_get_error(ctx); + + ERR_raise_data(ERR_LIB_OCSP, OCSP_R_CERTIFICATE_VERIFY_ERROR, + "Verify error: %s", X509_verify_cert_error_string(err)); + goto end; + } + if (chain != NULL) + *chain = X509_STORE_CTX_get1_chain(ctx); + + end: + X509_STORE_CTX_free(ctx); + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-1343/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2022-1343/vuln.c new file mode 100644 index 0000000..5f8f951 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-1343/vuln.c @@ -0,0 +1,55 @@ +/* Provenance: openssl/openssl ocsp_verify_signer (vuln). + * repo: openssl/openssl + * commit: ae3ece03a61e8822fd7ea58f44812871efba82d1 + * parent: ae3ece03a61e8822fd7ea58f44812871efba82d1 + * commit_url: https://github.com/openssl/openssl/commit/2eda98790c5c2741d76d23cc1e74b0dc4f4b391a + * cve: CVE-2022-1343 + * license: Apache-2.0 + * function: ocsp_verify_signer + * relpath: crypto/ocsp/ocsp_vfy.c + */ + +static int ocsp_verify_signer(X509 *signer, int response, + X509_STORE *st, unsigned long flags, + STACK_OF(X509) *untrusted, STACK_OF(X509) **chain) +{ + X509_STORE_CTX *ctx = X509_STORE_CTX_new(); + X509_VERIFY_PARAM *vp; + int ret = -1; + + if (ctx == NULL) { + ERR_raise(ERR_LIB_OCSP, ERR_R_MALLOC_FAILURE); + goto end; + } + if (!X509_STORE_CTX_init(ctx, st, signer, untrusted)) { + ERR_raise(ERR_LIB_OCSP, ERR_R_X509_LIB); + goto end; + } + if ((vp = X509_STORE_CTX_get0_param(ctx)) == NULL) + goto end; + if ((flags & OCSP_PARTIAL_CHAIN) != 0) + X509_VERIFY_PARAM_set_flags(vp, X509_V_FLAG_PARTIAL_CHAIN); + if (response + && X509_get_ext_by_NID(signer, NID_id_pkix_OCSP_noCheck, -1) >= 0) + /* + * Locally disable revocation status checking for OCSP responder cert. + * Done here for CRLs; should be done also for OCSP-based checks. + */ + X509_VERIFY_PARAM_clear_flags(vp, X509_V_FLAG_CRL_CHECK); + X509_STORE_CTX_set_purpose(ctx, X509_PURPOSE_OCSP_HELPER); + X509_STORE_CTX_set_trust(ctx, X509_TRUST_OCSP_REQUEST); + + ret = X509_verify_cert(ctx); + if (ret <= 0) { + ret = X509_STORE_CTX_get_error(ctx); + ERR_raise_data(ERR_LIB_OCSP, OCSP_R_CERTIFICATE_VERIFY_ERROR, + "Verify error: %s", X509_verify_cert_error_string(ret)); + goto end; + } + if (chain != NULL) + *chain = X509_STORE_CTX_get1_chain(ctx); + + end: + X509_STORE_CTX_free(ctx); + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-1434/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2022-1434/fixed.c new file mode 100644 index 0000000..d60f1af --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-1434/fixed.c @@ -0,0 +1,75 @@ +/* Provenance: openssl/openssl rc4_hmac_md5_set_ctx_params (fixed). + * repo: openssl/openssl + * commit: 7d56a74a96828985db7354a55227a511615f732b + * parent: 55c80c222293a972587004c185dc5653ae207a0e + * commit_url: https://github.com/openssl/openssl/commit/7d56a74a96828985db7354a55227a511615f732b + * cve: CVE-2022-1434 + * license: Apache-2.0 + * function: rc4_hmac_md5_set_ctx_params + * relpath: providers/implementations/ciphers/cipher_rc4_hmac_md5.c + */ + +static int rc4_hmac_md5_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_RC4_HMAC_MD5_CTX *ctx = (PROV_RC4_HMAC_MD5_CTX *)vctx; + const OSSL_PARAM *p; + size_t sz; + + if (params == NULL) + return 1; + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL) { + if (!OSSL_PARAM_get_size_t(p, &sz)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + if (ctx->base.keylen != sz) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + } + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_IVLEN); + if (p != NULL) { + if (!OSSL_PARAM_get_size_t(p, &sz)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + if (ctx->base.ivlen != sz) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); + return 0; + } + } + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_OCTET_STRING) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + sz = GET_HW(ctx)->tls_init(&ctx->base, p->data, p->data_size); + if (sz == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DATA); + return 0; + } + ctx->tls_aad_pad_sz = sz; + } + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_MAC_KEY); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_OCTET_STRING) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + GET_HW(ctx)->init_mackey(&ctx->base, p->data, p->data_size); + } + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_TLS_VERSION); + if (p != NULL) { + if (!OSSL_PARAM_get_uint(p, &ctx->base.tlsversion)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + } + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-1434/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2022-1434/vuln.c new file mode 100644 index 0000000..b956b34 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-1434/vuln.c @@ -0,0 +1,75 @@ +/* Provenance: openssl/openssl rc4_hmac_md5_set_ctx_params (vuln). + * repo: openssl/openssl + * commit: 55c80c222293a972587004c185dc5653ae207a0e + * parent: 55c80c222293a972587004c185dc5653ae207a0e + * commit_url: https://github.com/openssl/openssl/commit/7d56a74a96828985db7354a55227a511615f732b + * cve: CVE-2022-1434 + * license: Apache-2.0 + * function: rc4_hmac_md5_set_ctx_params + * relpath: providers/implementations/ciphers/cipher_rc4_hmac_md5.c + */ + +static int rc4_hmac_md5_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_RC4_HMAC_MD5_CTX *ctx = (PROV_RC4_HMAC_MD5_CTX *)vctx; + const OSSL_PARAM *p; + size_t sz; + + if (params == NULL) + return 1; + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL) { + if (!OSSL_PARAM_get_size_t(p, &sz)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + if (ctx->base.keylen != sz) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + } + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_IVLEN); + if (p != NULL) { + if (!OSSL_PARAM_get_size_t(p, &sz)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + if (ctx->base.ivlen != sz) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); + return 0; + } + } + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_OCTET_STRING) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + sz = GET_HW(ctx)->tls_init(&ctx->base, p->data, p->data_size); + if (sz == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DATA); + return 0; + } + ctx->tls_aad_pad_sz = sz; + } + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_OCTET_STRING) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + GET_HW(ctx)->init_mackey(&ctx->base, p->data, p->data_size); + } + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_TLS_VERSION); + if (p != NULL) { + if (!OSSL_PARAM_get_uint(p, &ctx->base.tlsversion)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + } + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-2068-hash_dir/fixed.in b/benchmarks/pairs/vfc/openssl-cve-2022-2068-hash_dir/fixed.in new file mode 100644 index 0000000..986a91b --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-2068-hash_dir/fixed.in @@ -0,0 +1,47 @@ +/* Provenance: openssl/openssl hash_dir (fixed). + * repo: openssl/openssl + * commit: 2c9c35870601b4a44d86ddbf512b38df38285cfa + * parent: abebcec7b1a30fbb1fd5c5cbbe8817690c139163 + * commit_url: https://github.com/openssl/openssl/commit/2c9c35870601b4a44d86ddbf512b38df38285cfa + * cve: CVE-2022-2068 + * license: Apache-2.0 + * function: hash_dir + * relpath: tools/c_rehash.in + */ + +sub hash_dir { + my $dir = shift; + my %hashlist; + + print "Doing $dir\n"; + + if (!chdir $dir) { + print STDERR "WARNING: Cannot chdir to '$dir', $!\n"; + return; + } + + opendir(DIR, ".") || print STDERR "WARNING: Cannot opendir '.', $!\n"; + my @flist = sort readdir(DIR); + closedir DIR; + if ( $removelinks ) { + # Delete any existing symbolic links + foreach (grep {/^[\da-f]+\.r{0,1}\d+$/} @flist) { + if (-l $_) { + print "unlink $_\n" if $verbose; + unlink $_ || warn "Can't unlink $_, $!\n"; + } + } + } + FILE: foreach $fname (grep {/\.(pem)|(crt)|(cer)|(crl)$/} @flist) { + # Check to see if certificates and/or CRLs present. + my ($cert, $crl) = check_file($fname); + if (!$cert && !$crl) { + print STDERR "WARNING: $fname does not contain a certificate or CRL: skipping\n"; + next; + } + link_hash_cert($fname) if ($cert); + link_hash_crl($fname) if ($crl); + } + + chdir $pwd; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-2068-hash_dir/vuln.in b/benchmarks/pairs/vfc/openssl-cve-2022-2068-hash_dir/vuln.in new file mode 100644 index 0000000..496a3c8 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-2068-hash_dir/vuln.in @@ -0,0 +1,38 @@ +/* Provenance: openssl/openssl hash_dir (vuln). + * repo: openssl/openssl + * commit: abebcec7b1a30fbb1fd5c5cbbe8817690c139163 + * parent: abebcec7b1a30fbb1fd5c5cbbe8817690c139163 + * commit_url: https://github.com/openssl/openssl/commit/2c9c35870601b4a44d86ddbf512b38df38285cfa + * cve: CVE-2022-2068 + * license: Apache-2.0 + * function: hash_dir + * relpath: tools/c_rehash.in + */ + +sub hash_dir { + my %hashlist; + print "Doing $_[0]\n"; + chdir $_[0]; + opendir(DIR, "."); + my @flist = sort readdir(DIR); + closedir DIR; + if ( $removelinks ) { + # Delete any existing symbolic links + foreach (grep {/^[\da-f]+\.r{0,1}\d+$/} @flist) { + if (-l $_) { + print "unlink $_" if $verbose; + unlink $_ || warn "Can't unlink $_, $!\n"; + } + } + } + FILE: foreach $fname (grep {/\.(pem)|(crt)|(cer)|(crl)$/} @flist) { + # Check to see if certificates and/or CRLs present. + my ($cert, $crl) = check_file($fname); + if (!$cert && !$crl) { + print STDERR "WARNING: $fname does not contain a certificate or CRL: skipping\n"; + next; + } + link_hash_cert($fname) if ($cert); + link_hash_crl($fname) if ($crl); + } +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-29242/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2022-29242/fixed.c new file mode 100644 index 0000000..387c7ce --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-29242/fixed.c @@ -0,0 +1,107 @@ +/* Provenance: openssl/openssl tls_construct_cke_gost18 (fixed). + * repo: openssl/openssl + * commit: 373de40f3f76c63e4f2684abd86706f3863347ca + * parent: 3be529cd2eb4eb3eaaa7913af619fb9c918d4581 + * commit_url: https://github.com/openssl/openssl/commit/373de40f3f76c63e4f2684abd86706f3863347ca + * cve: CVE-2022-29242 + * license: Apache-2.0 + * function: tls_construct_cke_gost18 + * relpath: ssl/statem/statem_clnt.c + */ + +static int tls_construct_cke_gost18(SSL *s, WPACKET *pkt) +{ +#ifndef OPENSSL_NO_GOST + /* GOST 2018 key exchange message creation */ + unsigned char rnd_dgst[32]; + unsigned char *encdata = NULL; + EVP_PKEY_CTX *pkey_ctx = NULL; + X509 *peer_cert; + unsigned char *pms = NULL; + size_t pmslen = 0; + size_t msglen; + int cipher_nid = ossl_gost18_cke_cipher_nid(s); + + if (cipher_nid == NID_undef) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + + if (ossl_gost_ukm(s, rnd_dgst) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + goto err; + } + + /* Pre-master secret - random bytes */ + pmslen = 32; + pms = OPENSSL_malloc(pmslen); + if (pms == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (RAND_bytes_ex(s->ctx->libctx, pms, pmslen, 0) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + goto err; + } + + /* Get server certificate PKEY and create ctx from it */ + peer_cert = s->session->peer; + if (peer_cert == NULL) { + SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, + SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER); + goto err; + } + + pkey_ctx = EVP_PKEY_CTX_new_from_pkey(s->ctx->libctx, + X509_get0_pubkey(peer_cert), + s->ctx->propq); + if (pkey_ctx == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (EVP_PKEY_encrypt_init(pkey_ctx) <= 0 ) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + goto err; + }; + + /* Reuse EVP_PKEY_CTRL_SET_IV, make choice in engine code */ + if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, EVP_PKEY_OP_ENCRYPT, + EVP_PKEY_CTRL_SET_IV, 32, rnd_dgst) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_LIBRARY_BUG); + goto err; + } + + if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, EVP_PKEY_OP_ENCRYPT, + EVP_PKEY_CTRL_CIPHER, cipher_nid, NULL) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_LIBRARY_BUG); + goto err; + } + + if (EVP_PKEY_encrypt(pkey_ctx, NULL, &msglen, pms, pmslen) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB); + goto err; + } + + if (!WPACKET_allocate_bytes(pkt, msglen, &encdata) + || EVP_PKEY_encrypt(pkey_ctx, encdata, &msglen, pms, pmslen) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB); + goto err; + } + + EVP_PKEY_CTX_free(pkey_ctx); + pkey_ctx = NULL; + s->s3.tmp.pms = pms; + s->s3.tmp.pmslen = pmslen; + + return 1; + err: + EVP_PKEY_CTX_free(pkey_ctx); + OPENSSL_clear_free(pms, pmslen); + return 0; +#else + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; +#endif +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-29242/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2022-29242/vuln.c new file mode 100644 index 0000000..af3c9f6 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-29242/vuln.c @@ -0,0 +1,105 @@ +/* Provenance: openssl/openssl tls_construct_cke_gost18 (vuln). + * repo: openssl/openssl + * commit: 3be529cd2eb4eb3eaaa7913af619fb9c918d4581 + * parent: 3be529cd2eb4eb3eaaa7913af619fb9c918d4581 + * commit_url: https://github.com/openssl/openssl/commit/373de40f3f76c63e4f2684abd86706f3863347ca + * cve: CVE-2022-29242 + * license: Apache-2.0 + * function: tls_construct_cke_gost18 + * relpath: ssl/statem/statem_clnt.c + */ + +static int tls_construct_cke_gost18(SSL *s, WPACKET *pkt) +{ +#ifndef OPENSSL_NO_GOST + /* GOST 2018 key exchange message creation */ + unsigned char rnd_dgst[32], tmp[255]; + EVP_PKEY_CTX *pkey_ctx = NULL; + X509 *peer_cert; + unsigned char *pms = NULL; + size_t pmslen = 0; + size_t msglen; + int cipher_nid = ossl_gost18_cke_cipher_nid(s); + + if (cipher_nid == NID_undef) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + + if (ossl_gost_ukm(s, rnd_dgst) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + goto err; + } + + /* Pre-master secret - random bytes */ + pmslen = 32; + pms = OPENSSL_malloc(pmslen); + if (pms == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (RAND_bytes_ex(s->ctx->libctx, pms, pmslen, 0) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + goto err; + } + + /* Get server certificate PKEY and create ctx from it */ + peer_cert = s->session->peer; + if (peer_cert == NULL) { + SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, + SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER); + goto err; + } + + pkey_ctx = EVP_PKEY_CTX_new_from_pkey(s->ctx->libctx, + X509_get0_pubkey(peer_cert), + s->ctx->propq); + if (pkey_ctx == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (EVP_PKEY_encrypt_init(pkey_ctx) <= 0 ) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + goto err; + }; + + /* Reuse EVP_PKEY_CTRL_SET_IV, make choice in engine code */ + if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, EVP_PKEY_OP_ENCRYPT, + EVP_PKEY_CTRL_SET_IV, 32, rnd_dgst) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_LIBRARY_BUG); + goto err; + } + + if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, EVP_PKEY_OP_ENCRYPT, + EVP_PKEY_CTRL_CIPHER, cipher_nid, NULL) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_LIBRARY_BUG); + goto err; + } + + msglen = 255; + if (EVP_PKEY_encrypt(pkey_ctx, tmp, &msglen, pms, pmslen) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_LIBRARY_BUG); + goto err; + } + + if (!WPACKET_memcpy(pkt, tmp, msglen)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + goto err; + } + + EVP_PKEY_CTX_free(pkey_ctx); + s->s3.tmp.pms = pms; + s->s3.tmp.pmslen = pmslen; + + return 1; + err: + EVP_PKEY_CTX_free(pkey_ctx); + OPENSSL_clear_free(pms, pmslen); + return 0; +#else + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; +#endif +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-3358-evp_cipher_init_internal/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2022-3358-evp_cipher_init_internal/fixed.c new file mode 100644 index 0000000..1d5a426 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-3358-evp_cipher_init_internal/fixed.c @@ -0,0 +1,319 @@ +/* Provenance: openssl/openssl evp_cipher_init_internal (fixed). + * repo: openssl/openssl + * commit: 5485c56679d7c49b96e8fc8ca708b0b7e7c03c4b + * parent: 9f0867da4cbf77ed642717b5e703e09ab2c087a0 + * commit_url: https://github.com/openssl/openssl/commit/5485c56679d7c49b96e8fc8ca708b0b7e7c03c4b + * cve: CVE-2022-3358 + * license: Apache-2.0 + * function: evp_cipher_init_internal + * relpath: crypto/evp/evp_enc.c + */ + +static int evp_cipher_init_internal(EVP_CIPHER_CTX *ctx, + const EVP_CIPHER *cipher, + ENGINE *impl, const unsigned char *key, + const unsigned char *iv, int enc, + const OSSL_PARAM params[]) +{ + int n; +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + ENGINE *tmpimpl = NULL; +#endif + + ctx->iv_len = -1; + + /* + * enc == 1 means we are encrypting. + * enc == 0 means we are decrypting. + * enc == -1 means, use the previously initialised value for encrypt/decrypt + */ + if (enc == -1) { + enc = ctx->encrypt; + } else { + if (enc) + enc = 1; + ctx->encrypt = enc; + } + + if (cipher == NULL && ctx->cipher == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_NO_CIPHER_SET); + return 0; + } + + /* Code below to be removed when legacy support is dropped. */ + +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + /* + * Whether it's nice or not, "Inits" can be used on "Final"'d contexts so + * this context may already have an ENGINE! Try to avoid releasing the + * previous handle, re-querying for an ENGINE, and having a + * reinitialisation, when it may all be unnecessary. + */ + if (ctx->engine && ctx->cipher + && (cipher == NULL || cipher->nid == ctx->cipher->nid)) + goto skip_to_init; + + if (cipher != NULL && impl == NULL) { + /* Ask if an ENGINE is reserved for this job */ + tmpimpl = ENGINE_get_cipher_engine(cipher->nid); + } +#endif + + /* + * If there are engines involved then we should use legacy handling for now. + */ + if (ctx->engine != NULL +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + || tmpimpl != NULL +#endif + || impl != NULL + || (cipher != NULL && cipher->origin == EVP_ORIG_METH) + || (cipher == NULL && ctx->cipher != NULL + && ctx->cipher->origin == EVP_ORIG_METH)) { + if (ctx->cipher == ctx->fetched_cipher) + ctx->cipher = NULL; + EVP_CIPHER_free(ctx->fetched_cipher); + ctx->fetched_cipher = NULL; + goto legacy; + } + /* + * Ensure a context left lying around from last time is cleared + * (legacy code) + */ + if (cipher != NULL && ctx->cipher != NULL) { + OPENSSL_clear_free(ctx->cipher_data, ctx->cipher->ctx_size); + ctx->cipher_data = NULL; + } + + /* Start of non-legacy code below */ + + /* Ensure a context left lying around from last time is cleared */ + if (cipher != NULL && ctx->cipher != NULL) { + unsigned long flags = ctx->flags; + + EVP_CIPHER_CTX_reset(ctx); + /* Restore encrypt and flags */ + ctx->encrypt = enc; + ctx->flags = flags; + } + + if (cipher == NULL) + cipher = ctx->cipher; + + if (cipher->prov == NULL) { +#ifdef FIPS_MODULE + /* We only do explicit fetches inside the FIPS module */ + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; +#else + EVP_CIPHER *provciph = + EVP_CIPHER_fetch(NULL, + cipher->nid == NID_undef ? "NULL" + : OBJ_nid2sn(cipher->nid), + ""); + + if (provciph == NULL) + return 0; + cipher = provciph; + EVP_CIPHER_free(ctx->fetched_cipher); + ctx->fetched_cipher = provciph; +#endif + } + + if (cipher->prov != NULL) { + if (!EVP_CIPHER_up_ref((EVP_CIPHER *)cipher)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + EVP_CIPHER_free(ctx->fetched_cipher); + ctx->fetched_cipher = (EVP_CIPHER *)cipher; + } + ctx->cipher = cipher; + if (ctx->algctx == NULL) { + ctx->algctx = ctx->cipher->newctx(ossl_provider_ctx(cipher->prov)); + if (ctx->algctx == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + } + + if ((ctx->flags & EVP_CIPH_NO_PADDING) != 0) { + /* + * If this ctx was already set up for no padding then we need to tell + * the new cipher about it. + */ + if (!EVP_CIPHER_CTX_set_padding(ctx, 0)) + return 0; + } + + if (enc) { + if (ctx->cipher->einit == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + + return ctx->cipher->einit(ctx->algctx, + key, + key == NULL ? 0 + : EVP_CIPHER_CTX_get_key_length(ctx), + iv, + iv == NULL ? 0 + : EVP_CIPHER_CTX_get_iv_length(ctx), + params); + } + + if (ctx->cipher->dinit == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + + return ctx->cipher->dinit(ctx->algctx, + key, + key == NULL ? 0 + : EVP_CIPHER_CTX_get_key_length(ctx), + iv, + iv == NULL ? 0 + : EVP_CIPHER_CTX_get_iv_length(ctx), + params); + + /* Code below to be removed when legacy support is dropped. */ + legacy: + + if (cipher != NULL) { + /* + * Ensure a context left lying around from last time is cleared (we + * previously attempted to avoid this if the same ENGINE and + * EVP_CIPHER could be used). + */ + if (ctx->cipher) { + unsigned long flags = ctx->flags; + EVP_CIPHER_CTX_reset(ctx); + /* Restore encrypt and flags */ + ctx->encrypt = enc; + ctx->flags = flags; + } +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + if (impl != NULL) { + if (!ENGINE_init(impl)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + } else { + impl = tmpimpl; + } + if (impl != NULL) { + /* There's an ENGINE for this job ... (apparently) */ + const EVP_CIPHER *c = ENGINE_get_cipher(impl, cipher->nid); + + if (c == NULL) { + /* + * One positive side-effect of US's export control history, + * is that we should at least be able to avoid using US + * misspellings of "initialisation"? + */ + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + /* We'll use the ENGINE's private cipher definition */ + cipher = c; + /* + * Store the ENGINE functional reference so we know 'cipher' came + * from an ENGINE and we need to release it when done. + */ + ctx->engine = impl; + } else { + ctx->engine = NULL; + } +#endif + + ctx->cipher = cipher; + if (ctx->cipher->ctx_size) { + ctx->cipher_data = OPENSSL_zalloc(ctx->cipher->ctx_size); + if (ctx->cipher_data == NULL) { + ctx->cipher = NULL; + ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); + return 0; + } + } else { + ctx->cipher_data = NULL; + } + ctx->key_len = cipher->key_len; + /* Preserve wrap enable flag, zero everything else */ + ctx->flags &= EVP_CIPHER_CTX_FLAG_WRAP_ALLOW; + if (ctx->cipher->flags & EVP_CIPH_CTRL_INIT) { + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_INIT, 0, NULL) <= 0) { + ctx->cipher = NULL; + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + } + } +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + skip_to_init: +#endif + if (ctx->cipher == NULL) + return 0; + + /* we assume block size is a power of 2 in *cryptUpdate */ + OPENSSL_assert(ctx->cipher->block_size == 1 + || ctx->cipher->block_size == 8 + || ctx->cipher->block_size == 16); + + if (!(ctx->flags & EVP_CIPHER_CTX_FLAG_WRAP_ALLOW) + && EVP_CIPHER_CTX_get_mode(ctx) == EVP_CIPH_WRAP_MODE) { + ERR_raise(ERR_LIB_EVP, EVP_R_WRAP_MODE_NOT_ALLOWED); + return 0; + } + + if ((EVP_CIPHER_get_flags(EVP_CIPHER_CTX_get0_cipher(ctx)) + & EVP_CIPH_CUSTOM_IV) == 0) { + switch (EVP_CIPHER_CTX_get_mode(ctx)) { + + case EVP_CIPH_STREAM_CIPHER: + case EVP_CIPH_ECB_MODE: + break; + + case EVP_CIPH_CFB_MODE: + case EVP_CIPH_OFB_MODE: + + ctx->num = 0; + /* fall-through */ + + case EVP_CIPH_CBC_MODE: + n = EVP_CIPHER_CTX_get_iv_length(ctx); + if (n < 0 || n > (int)sizeof(ctx->iv)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_IV_LENGTH); + return 0; + } + if (iv != NULL) + memcpy(ctx->oiv, iv, n); + memcpy(ctx->iv, ctx->oiv, n); + break; + + case EVP_CIPH_CTR_MODE: + ctx->num = 0; + /* Don't reuse IV for CTR mode */ + if (iv != NULL) { + n = EVP_CIPHER_CTX_get_iv_length(ctx); + if (n <= 0 || n > (int)sizeof(ctx->iv)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_IV_LENGTH); + return 0; + } + memcpy(ctx->iv, iv, n); + } + break; + + default: + return 0; + } + } + + if (key != NULL || (ctx->cipher->flags & EVP_CIPH_ALWAYS_CALL_INIT)) { + if (!ctx->cipher->init(ctx, key, iv, enc)) + return 0; + } + ctx->buf_len = 0; + ctx->final_used = 0; + ctx->block_mask = ctx->cipher->block_size - 1; + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-3358-evp_cipher_init_internal/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2022-3358-evp_cipher_init_internal/vuln.c new file mode 100644 index 0000000..ff42024 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-3358-evp_cipher_init_internal/vuln.c @@ -0,0 +1,317 @@ +/* Provenance: openssl/openssl evp_cipher_init_internal (vuln). + * repo: openssl/openssl + * commit: 9f0867da4cbf77ed642717b5e703e09ab2c087a0 + * parent: 9f0867da4cbf77ed642717b5e703e09ab2c087a0 + * commit_url: https://github.com/openssl/openssl/commit/5485c56679d7c49b96e8fc8ca708b0b7e7c03c4b + * cve: CVE-2022-3358 + * license: Apache-2.0 + * function: evp_cipher_init_internal + * relpath: crypto/evp/evp_enc.c + */ + +static int evp_cipher_init_internal(EVP_CIPHER_CTX *ctx, + const EVP_CIPHER *cipher, + ENGINE *impl, const unsigned char *key, + const unsigned char *iv, int enc, + const OSSL_PARAM params[]) +{ + int n; +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + ENGINE *tmpimpl = NULL; +#endif + + ctx->iv_len = -1; + + /* + * enc == 1 means we are encrypting. + * enc == 0 means we are decrypting. + * enc == -1 means, use the previously initialised value for encrypt/decrypt + */ + if (enc == -1) { + enc = ctx->encrypt; + } else { + if (enc) + enc = 1; + ctx->encrypt = enc; + } + + if (cipher == NULL && ctx->cipher == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_NO_CIPHER_SET); + return 0; + } + + /* Code below to be removed when legacy support is dropped. */ + +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + /* + * Whether it's nice or not, "Inits" can be used on "Final"'d contexts so + * this context may already have an ENGINE! Try to avoid releasing the + * previous handle, re-querying for an ENGINE, and having a + * reinitialisation, when it may all be unnecessary. + */ + if (ctx->engine && ctx->cipher + && (cipher == NULL || cipher->nid == ctx->cipher->nid)) + goto skip_to_init; + + if (cipher != NULL && impl == NULL) { + /* Ask if an ENGINE is reserved for this job */ + tmpimpl = ENGINE_get_cipher_engine(cipher->nid); + } +#endif + + /* + * If there are engines involved then we should use legacy handling for now. + */ + if (ctx->engine != NULL +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + || tmpimpl != NULL +#endif + || impl != NULL) { + if (ctx->cipher == ctx->fetched_cipher) + ctx->cipher = NULL; + EVP_CIPHER_free(ctx->fetched_cipher); + ctx->fetched_cipher = NULL; + goto legacy; + } + /* + * Ensure a context left lying around from last time is cleared + * (legacy code) + */ + if (cipher != NULL && ctx->cipher != NULL) { + OPENSSL_clear_free(ctx->cipher_data, ctx->cipher->ctx_size); + ctx->cipher_data = NULL; + } + + + /* Start of non-legacy code below */ + + /* Ensure a context left lying around from last time is cleared */ + if (cipher != NULL && ctx->cipher != NULL) { + unsigned long flags = ctx->flags; + + EVP_CIPHER_CTX_reset(ctx); + /* Restore encrypt and flags */ + ctx->encrypt = enc; + ctx->flags = flags; + } + + if (cipher == NULL) + cipher = ctx->cipher; + + if (cipher->prov == NULL) { +#ifdef FIPS_MODULE + /* We only do explicit fetches inside the FIPS module */ + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; +#else + EVP_CIPHER *provciph = + EVP_CIPHER_fetch(NULL, + cipher->nid == NID_undef ? "NULL" + : OBJ_nid2sn(cipher->nid), + ""); + + if (provciph == NULL) + return 0; + cipher = provciph; + EVP_CIPHER_free(ctx->fetched_cipher); + ctx->fetched_cipher = provciph; +#endif + } + + if (cipher->prov != NULL) { + if (!EVP_CIPHER_up_ref((EVP_CIPHER *)cipher)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + EVP_CIPHER_free(ctx->fetched_cipher); + ctx->fetched_cipher = (EVP_CIPHER *)cipher; + } + ctx->cipher = cipher; + if (ctx->algctx == NULL) { + ctx->algctx = ctx->cipher->newctx(ossl_provider_ctx(cipher->prov)); + if (ctx->algctx == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + } + + if ((ctx->flags & EVP_CIPH_NO_PADDING) != 0) { + /* + * If this ctx was already set up for no padding then we need to tell + * the new cipher about it. + */ + if (!EVP_CIPHER_CTX_set_padding(ctx, 0)) + return 0; + } + + if (enc) { + if (ctx->cipher->einit == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + + return ctx->cipher->einit(ctx->algctx, + key, + key == NULL ? 0 + : EVP_CIPHER_CTX_get_key_length(ctx), + iv, + iv == NULL ? 0 + : EVP_CIPHER_CTX_get_iv_length(ctx), + params); + } + + if (ctx->cipher->dinit == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + + return ctx->cipher->dinit(ctx->algctx, + key, + key == NULL ? 0 + : EVP_CIPHER_CTX_get_key_length(ctx), + iv, + iv == NULL ? 0 + : EVP_CIPHER_CTX_get_iv_length(ctx), + params); + + /* Code below to be removed when legacy support is dropped. */ + legacy: + + if (cipher != NULL) { + /* + * Ensure a context left lying around from last time is cleared (we + * previously attempted to avoid this if the same ENGINE and + * EVP_CIPHER could be used). + */ + if (ctx->cipher) { + unsigned long flags = ctx->flags; + EVP_CIPHER_CTX_reset(ctx); + /* Restore encrypt and flags */ + ctx->encrypt = enc; + ctx->flags = flags; + } +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + if (impl != NULL) { + if (!ENGINE_init(impl)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + } else { + impl = tmpimpl; + } + if (impl != NULL) { + /* There's an ENGINE for this job ... (apparently) */ + const EVP_CIPHER *c = ENGINE_get_cipher(impl, cipher->nid); + + if (c == NULL) { + /* + * One positive side-effect of US's export control history, + * is that we should at least be able to avoid using US + * misspellings of "initialisation"? + */ + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + /* We'll use the ENGINE's private cipher definition */ + cipher = c; + /* + * Store the ENGINE functional reference so we know 'cipher' came + * from an ENGINE and we need to release it when done. + */ + ctx->engine = impl; + } else { + ctx->engine = NULL; + } +#endif + + ctx->cipher = cipher; + if (ctx->cipher->ctx_size) { + ctx->cipher_data = OPENSSL_zalloc(ctx->cipher->ctx_size); + if (ctx->cipher_data == NULL) { + ctx->cipher = NULL; + ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); + return 0; + } + } else { + ctx->cipher_data = NULL; + } + ctx->key_len = cipher->key_len; + /* Preserve wrap enable flag, zero everything else */ + ctx->flags &= EVP_CIPHER_CTX_FLAG_WRAP_ALLOW; + if (ctx->cipher->flags & EVP_CIPH_CTRL_INIT) { + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_INIT, 0, NULL) <= 0) { + ctx->cipher = NULL; + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + } + } +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + skip_to_init: +#endif + if (ctx->cipher == NULL) + return 0; + + /* we assume block size is a power of 2 in *cryptUpdate */ + OPENSSL_assert(ctx->cipher->block_size == 1 + || ctx->cipher->block_size == 8 + || ctx->cipher->block_size == 16); + + if (!(ctx->flags & EVP_CIPHER_CTX_FLAG_WRAP_ALLOW) + && EVP_CIPHER_CTX_get_mode(ctx) == EVP_CIPH_WRAP_MODE) { + ERR_raise(ERR_LIB_EVP, EVP_R_WRAP_MODE_NOT_ALLOWED); + return 0; + } + + if ((EVP_CIPHER_get_flags(EVP_CIPHER_CTX_get0_cipher(ctx)) + & EVP_CIPH_CUSTOM_IV) == 0) { + switch (EVP_CIPHER_CTX_get_mode(ctx)) { + + case EVP_CIPH_STREAM_CIPHER: + case EVP_CIPH_ECB_MODE: + break; + + case EVP_CIPH_CFB_MODE: + case EVP_CIPH_OFB_MODE: + + ctx->num = 0; + /* fall-through */ + + case EVP_CIPH_CBC_MODE: + n = EVP_CIPHER_CTX_get_iv_length(ctx); + if (n < 0 || n > (int)sizeof(ctx->iv)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_IV_LENGTH); + return 0; + } + if (iv != NULL) + memcpy(ctx->oiv, iv, n); + memcpy(ctx->iv, ctx->oiv, n); + break; + + case EVP_CIPH_CTR_MODE: + ctx->num = 0; + /* Don't reuse IV for CTR mode */ + if (iv != NULL) { + n = EVP_CIPHER_CTX_get_iv_length(ctx); + if (n <= 0 || n > (int)sizeof(ctx->iv)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_IV_LENGTH); + return 0; + } + memcpy(ctx->iv, iv, n); + } + break; + + default: + return 0; + } + } + + if (key != NULL || (ctx->cipher->flags & EVP_CIPH_ALWAYS_CALL_INIT)) { + if (!ctx->cipher->init(ctx, key, iv, enc)) + return 0; + } + ctx->buf_len = 0; + ctx->final_used = 0; + ctx->block_mask = ctx->cipher->block_size - 1; + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-3358/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2022-3358/fixed.c new file mode 100644 index 0000000..53022f5 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-3358/fixed.c @@ -0,0 +1,224 @@ +/* Provenance: openssl/openssl evp_md_init_internal (fixed). + * repo: openssl/openssl + * commit: 5485c56679d7c49b96e8fc8ca708b0b7e7c03c4b + * parent: 9f0867da4cbf77ed642717b5e703e09ab2c087a0 + * commit_url: https://github.com/openssl/openssl/commit/5485c56679d7c49b96e8fc8ca708b0b7e7c03c4b + * cve: CVE-2022-3358 + * license: Apache-2.0 + * function: evp_md_init_internal + * relpath: crypto/evp/digest.c + */ + +static int evp_md_init_internal(EVP_MD_CTX *ctx, const EVP_MD *type, + const OSSL_PARAM params[], ENGINE *impl) +{ +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + ENGINE *tmpimpl = NULL; +#endif + +#if !defined(FIPS_MODULE) + if (ctx->pctx != NULL + && EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx->pctx) + && ctx->pctx->op.sig.algctx != NULL) { + /* + * Prior to OpenSSL 3.0 calling EVP_DigestInit_ex() on an mdctx + * previously initialised with EVP_DigestSignInit() would retain + * information about the key, and re-initialise for another sign + * operation. So in that case we redirect to EVP_DigestSignInit() + */ + if (ctx->pctx->operation == EVP_PKEY_OP_SIGNCTX) + return EVP_DigestSignInit(ctx, NULL, type, impl, NULL); + if (ctx->pctx->operation == EVP_PKEY_OP_VERIFYCTX) + return EVP_DigestVerifyInit(ctx, NULL, type, impl, NULL); + ERR_raise(ERR_LIB_EVP, EVP_R_UPDATE_ERROR); + return 0; + } +#endif + + EVP_MD_CTX_clear_flags(ctx, EVP_MD_CTX_FLAG_CLEANED); + + if (ctx->algctx != NULL) { + if (!ossl_assert(ctx->digest != NULL)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + if (ctx->digest->freectx != NULL) + ctx->digest->freectx(ctx->algctx); + ctx->algctx = NULL; + } + + if (type != NULL) { + ctx->reqdigest = type; + } else { + if (ctx->digest == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_NO_DIGEST_SET); + return 0; + } + type = ctx->digest; + } + + /* Code below to be removed when legacy support is dropped. */ +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + /* + * Whether it's nice or not, "Inits" can be used on "Final"'d contexts so + * this context may already have an ENGINE! Try to avoid releasing the + * previous handle, re-querying for an ENGINE, and having a + * reinitialisation, when it may all be unnecessary. + */ + if (ctx->engine && ctx->digest && + (type == NULL || (type->type == ctx->digest->type))) + goto skip_to_init; + + if (type != NULL) { + /* + * Ensure an ENGINE left lying around from last time is cleared (the + * previous check attempted to avoid this if the same ENGINE and + * EVP_MD could be used). + */ + ENGINE_finish(ctx->engine); + ctx->engine = NULL; + } + + if (type != NULL && impl == NULL) + tmpimpl = ENGINE_get_digest_engine(type->type); +#endif + + /* + * If there are engines involved or EVP_MD_CTX_FLAG_NO_INIT is set then we + * should use legacy handling for now. + */ + if (ctx->engine != NULL + || impl != NULL +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + || tmpimpl != NULL +#endif + || (ctx->flags & EVP_MD_CTX_FLAG_NO_INIT) != 0 + || (type != NULL && type->origin == EVP_ORIG_METH) + || (type == NULL && ctx->digest != NULL + && ctx->digest->origin == EVP_ORIG_METH)) { + if (ctx->digest == ctx->fetched_digest) + ctx->digest = NULL; + EVP_MD_free(ctx->fetched_digest); + ctx->fetched_digest = NULL; + goto legacy; + } + + cleanup_old_md_data(ctx, 1); + + /* Start of non-legacy code below */ + + if (type->prov == NULL) { +#ifdef FIPS_MODULE + /* We only do explicit fetches inside the FIPS module */ + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; +#else + /* The NULL digest is a special case */ + EVP_MD *provmd = EVP_MD_fetch(NULL, + type->type != NID_undef ? OBJ_nid2sn(type->type) + : "NULL", ""); + + if (provmd == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + type = provmd; + EVP_MD_free(ctx->fetched_digest); + ctx->fetched_digest = provmd; +#endif + } + + if (ctx->algctx != NULL && ctx->digest != NULL && ctx->digest != type) { + if (ctx->digest->freectx != NULL) + ctx->digest->freectx(ctx->algctx); + ctx->algctx = NULL; + } + if (type->prov != NULL && ctx->fetched_digest != type) { + if (!EVP_MD_up_ref((EVP_MD *)type)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + EVP_MD_free(ctx->fetched_digest); + ctx->fetched_digest = (EVP_MD *)type; + } + ctx->digest = type; + if (ctx->algctx == NULL) { + ctx->algctx = ctx->digest->newctx(ossl_provider_ctx(type->prov)); + if (ctx->algctx == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + } + + if (ctx->digest->dinit == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + + return ctx->digest->dinit(ctx->algctx, params); + + /* Code below to be removed when legacy support is dropped. */ + legacy: + +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + if (type) { + if (impl != NULL) { + if (!ENGINE_init(impl)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + } else { + /* Ask if an ENGINE is reserved for this job */ + impl = tmpimpl; + } + if (impl != NULL) { + /* There's an ENGINE for this job ... (apparently) */ + const EVP_MD *d = ENGINE_get_digest(impl, type->type); + + if (d == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + ENGINE_finish(impl); + return 0; + } + /* We'll use the ENGINE's private digest definition */ + type = d; + /* + * Store the ENGINE functional reference so we know 'type' came + * from an ENGINE and we need to release it when done. + */ + ctx->engine = impl; + } else + ctx->engine = NULL; + } +#endif + if (ctx->digest != type) { + cleanup_old_md_data(ctx, 1); + + ctx->digest = type; + if (!(ctx->flags & EVP_MD_CTX_FLAG_NO_INIT) && type->ctx_size) { + ctx->update = type->update; + ctx->md_data = OPENSSL_zalloc(type->ctx_size); + if (ctx->md_data == NULL) { + ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); + return 0; + } + } + } +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + skip_to_init: +#endif +#ifndef FIPS_MODULE + if (ctx->pctx != NULL + && (!EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx->pctx) + || ctx->pctx->op.sig.signature == NULL)) { + int r; + r = EVP_PKEY_CTX_ctrl(ctx->pctx, -1, EVP_PKEY_OP_TYPE_SIG, + EVP_PKEY_CTRL_DIGESTINIT, 0, ctx); + if (r <= 0 && (r != -2)) + return 0; + } +#endif + if (ctx->flags & EVP_MD_CTX_FLAG_NO_INIT) + return 1; + return ctx->digest->init(ctx); +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-3358/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2022-3358/vuln.c new file mode 100644 index 0000000..fd60b88 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-3358/vuln.c @@ -0,0 +1,222 @@ +/* Provenance: openssl/openssl evp_md_init_internal (vuln). + * repo: openssl/openssl + * commit: 9f0867da4cbf77ed642717b5e703e09ab2c087a0 + * parent: 9f0867da4cbf77ed642717b5e703e09ab2c087a0 + * commit_url: https://github.com/openssl/openssl/commit/5485c56679d7c49b96e8fc8ca708b0b7e7c03c4b + * cve: CVE-2022-3358 + * license: Apache-2.0 + * function: evp_md_init_internal + * relpath: crypto/evp/digest.c + */ + +static int evp_md_init_internal(EVP_MD_CTX *ctx, const EVP_MD *type, + const OSSL_PARAM params[], ENGINE *impl) +{ +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + ENGINE *tmpimpl = NULL; +#endif + +#if !defined(FIPS_MODULE) + if (ctx->pctx != NULL + && EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx->pctx) + && ctx->pctx->op.sig.algctx != NULL) { + /* + * Prior to OpenSSL 3.0 calling EVP_DigestInit_ex() on an mdctx + * previously initialised with EVP_DigestSignInit() would retain + * information about the key, and re-initialise for another sign + * operation. So in that case we redirect to EVP_DigestSignInit() + */ + if (ctx->pctx->operation == EVP_PKEY_OP_SIGNCTX) + return EVP_DigestSignInit(ctx, NULL, type, impl, NULL); + if (ctx->pctx->operation == EVP_PKEY_OP_VERIFYCTX) + return EVP_DigestVerifyInit(ctx, NULL, type, impl, NULL); + ERR_raise(ERR_LIB_EVP, EVP_R_UPDATE_ERROR); + return 0; + } +#endif + + EVP_MD_CTX_clear_flags(ctx, EVP_MD_CTX_FLAG_CLEANED); + + if (ctx->algctx != NULL) { + if (!ossl_assert(ctx->digest != NULL)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + if (ctx->digest->freectx != NULL) + ctx->digest->freectx(ctx->algctx); + ctx->algctx = NULL; + } + + if (type != NULL) { + ctx->reqdigest = type; + } else { + if (ctx->digest == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_NO_DIGEST_SET); + return 0; + } + type = ctx->digest; + } + + /* Code below to be removed when legacy support is dropped. */ +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + /* + * Whether it's nice or not, "Inits" can be used on "Final"'d contexts so + * this context may already have an ENGINE! Try to avoid releasing the + * previous handle, re-querying for an ENGINE, and having a + * reinitialisation, when it may all be unnecessary. + */ + if (ctx->engine && ctx->digest && + (type == NULL || (type->type == ctx->digest->type))) + goto skip_to_init; + + if (type != NULL) { + /* + * Ensure an ENGINE left lying around from last time is cleared (the + * previous check attempted to avoid this if the same ENGINE and + * EVP_MD could be used). + */ + ENGINE_finish(ctx->engine); + ctx->engine = NULL; + } + + if (type != NULL && impl == NULL) + tmpimpl = ENGINE_get_digest_engine(type->type); +#endif + + /* + * If there are engines involved or EVP_MD_CTX_FLAG_NO_INIT is set then we + * should use legacy handling for now. + */ + if (ctx->engine != NULL + || impl != NULL +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + || tmpimpl != NULL +#endif + || (ctx->flags & EVP_MD_CTX_FLAG_NO_INIT) != 0 + || type->origin == EVP_ORIG_METH) { + if (ctx->digest == ctx->fetched_digest) + ctx->digest = NULL; + EVP_MD_free(ctx->fetched_digest); + ctx->fetched_digest = NULL; + goto legacy; + } + + cleanup_old_md_data(ctx, 1); + + /* Start of non-legacy code below */ + + if (type->prov == NULL) { +#ifdef FIPS_MODULE + /* We only do explicit fetches inside the FIPS module */ + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; +#else + /* The NULL digest is a special case */ + EVP_MD *provmd = EVP_MD_fetch(NULL, + type->type != NID_undef ? OBJ_nid2sn(type->type) + : "NULL", ""); + + if (provmd == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + type = provmd; + EVP_MD_free(ctx->fetched_digest); + ctx->fetched_digest = provmd; +#endif + } + + if (ctx->algctx != NULL && ctx->digest != NULL && ctx->digest != type) { + if (ctx->digest->freectx != NULL) + ctx->digest->freectx(ctx->algctx); + ctx->algctx = NULL; + } + if (type->prov != NULL && ctx->fetched_digest != type) { + if (!EVP_MD_up_ref((EVP_MD *)type)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + EVP_MD_free(ctx->fetched_digest); + ctx->fetched_digest = (EVP_MD *)type; + } + ctx->digest = type; + if (ctx->algctx == NULL) { + ctx->algctx = ctx->digest->newctx(ossl_provider_ctx(type->prov)); + if (ctx->algctx == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + } + + if (ctx->digest->dinit == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + + return ctx->digest->dinit(ctx->algctx, params); + + /* Code below to be removed when legacy support is dropped. */ + legacy: + +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + if (type) { + if (impl != NULL) { + if (!ENGINE_init(impl)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + } else { + /* Ask if an ENGINE is reserved for this job */ + impl = tmpimpl; + } + if (impl != NULL) { + /* There's an ENGINE for this job ... (apparently) */ + const EVP_MD *d = ENGINE_get_digest(impl, type->type); + + if (d == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + ENGINE_finish(impl); + return 0; + } + /* We'll use the ENGINE's private digest definition */ + type = d; + /* + * Store the ENGINE functional reference so we know 'type' came + * from an ENGINE and we need to release it when done. + */ + ctx->engine = impl; + } else + ctx->engine = NULL; + } +#endif + if (ctx->digest != type) { + cleanup_old_md_data(ctx, 1); + + ctx->digest = type; + if (!(ctx->flags & EVP_MD_CTX_FLAG_NO_INIT) && type->ctx_size) { + ctx->update = type->update; + ctx->md_data = OPENSSL_zalloc(type->ctx_size); + if (ctx->md_data == NULL) { + ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); + return 0; + } + } + } +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + skip_to_init: +#endif +#ifndef FIPS_MODULE + if (ctx->pctx != NULL + && (!EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx->pctx) + || ctx->pctx->op.sig.signature == NULL)) { + int r; + r = EVP_PKEY_CTX_ctrl(ctx->pctx, -1, EVP_PKEY_OP_TYPE_SIG, + EVP_PKEY_CTRL_DIGESTINIT, 0, ctx); + if (r <= 0 && (r != -2)) + return 0; + } +#endif + if (ctx->flags & EVP_MD_CTX_FLAG_NO_INIT) + return 1; + return ctx->digest->init(ctx); +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-3602-ossl_punycode_decode/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2022-3602-ossl_punycode_decode/fixed.c new file mode 100644 index 0000000..db3e0d7 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-3602-ossl_punycode_decode/fixed.c @@ -0,0 +1,90 @@ +/* Provenance: openssl/openssl ossl_punycode_decode (fixed). + * repo: openssl/openssl + * commit: 3b421ebc64c7b52f1b9feb3812bdc7781c784332 + * parent: 89d72311327735ef15c804d2adea84a0fb1bfa0a + * commit_url: https://github.com/openssl/openssl/commit/3b421ebc64c7b52f1b9feb3812bdc7781c784332 + * cve: CVE-2022-3602 + * license: Apache-2.0 + * function: ossl_punycode_decode + * relpath: crypto/punycode.c + */ + +int ossl_punycode_decode(const char *pEncoded, const size_t enc_len, + unsigned int *pDecoded, unsigned int *pout_length) +{ + unsigned int n = initial_n; + unsigned int i = 0; + unsigned int bias = initial_bias; + size_t processed_in = 0, written_out = 0; + unsigned int max_out = *pout_length; + + unsigned int basic_count = 0; + unsigned int loop; + + for (loop = 0; loop < enc_len; loop++) { + if (pEncoded[loop] == delimiter) + basic_count = loop; + } + + if (basic_count > 0) { + if (basic_count > max_out) + return 0; + + for (loop = 0; loop < basic_count; loop++) { + if (is_basic(pEncoded[loop]) == 0) + return 0; + + pDecoded[loop] = pEncoded[loop]; + written_out++; + } + processed_in = basic_count + 1; + } + + for (loop = processed_in; loop < enc_len;) { + unsigned int oldi = i; + unsigned int w = 1; + unsigned int k, t; + int digit; + + for (k = base;; k += base) { + if (loop >= enc_len) + return 0; + + digit = digit_decoded(pEncoded[loop]); + loop++; + + if (digit < 0) + return 0; + if ((unsigned int)digit > (maxint - i) / w) + return 0; + + i = i + digit * w; + t = (k <= bias) ? tmin : (k >= bias + tmax) ? tmax : k - bias; + + if ((unsigned int)digit < t) + break; + + if (w > maxint / (base - t)) + return 0; + w = w * (base - t); + } + + bias = adapt(i - oldi, written_out + 1, (oldi == 0)); + if (i / (written_out + 1) > maxint - n) + return 0; + n = n + i / (written_out + 1); + i %= (written_out + 1); + + if (written_out >= max_out) + return 0; + + memmove(pDecoded + i + 1, pDecoded + i, + (written_out - i) * sizeof *pDecoded); + pDecoded[i] = n; + i++; + written_out++; + } + + *pout_length = written_out; + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-3602-ossl_punycode_decode/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2022-3602-ossl_punycode_decode/vuln.c new file mode 100644 index 0000000..2210955 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-3602-ossl_punycode_decode/vuln.c @@ -0,0 +1,90 @@ +/* Provenance: openssl/openssl ossl_punycode_decode (vuln). + * repo: openssl/openssl + * commit: 89d72311327735ef15c804d2adea84a0fb1bfa0a + * parent: 89d72311327735ef15c804d2adea84a0fb1bfa0a + * commit_url: https://github.com/openssl/openssl/commit/3b421ebc64c7b52f1b9feb3812bdc7781c784332 + * cve: CVE-2022-3602 + * license: Apache-2.0 + * function: ossl_punycode_decode + * relpath: crypto/punycode.c + */ + +int ossl_punycode_decode(const char *pEncoded, const size_t enc_len, + unsigned int *pDecoded, unsigned int *pout_length) +{ + unsigned int n = initial_n; + unsigned int i = 0; + unsigned int bias = initial_bias; + size_t processed_in = 0, written_out = 0; + unsigned int max_out = *pout_length; + + unsigned int basic_count = 0; + unsigned int loop; + + for (loop = 0; loop < enc_len; loop++) { + if (pEncoded[loop] == delimiter) + basic_count = loop; + } + + if (basic_count > 0) { + if (basic_count > max_out) + return 0; + + for (loop = 0; loop < basic_count; loop++) { + if (is_basic(pEncoded[loop]) == 0) + return 0; + + pDecoded[loop] = pEncoded[loop]; + written_out++; + } + processed_in = basic_count + 1; + } + + for (loop = processed_in; loop < enc_len;) { + unsigned int oldi = i; + unsigned int w = 1; + unsigned int k, t; + int digit; + + for (k = base;; k += base) { + if (loop >= enc_len) + return 0; + + digit = digit_decoded(pEncoded[loop]); + loop++; + + if (digit < 0) + return 0; + if ((unsigned int)digit > (maxint - i) / w) + return 0; + + i = i + digit * w; + t = (k <= bias) ? tmin : (k >= bias + tmax) ? tmax : k - bias; + + if ((unsigned int)digit < t) + break; + + if (w > maxint / (base - t)) + return 0; + w = w * (base - t); + } + + bias = adapt(i - oldi, written_out + 1, (oldi == 0)); + if (i / (written_out + 1) > maxint - n) + return 0; + n = n + i / (written_out + 1); + i %= (written_out + 1); + + if (written_out > max_out) + return 0; + + memmove(pDecoded + i + 1, pDecoded + i, + (written_out - i) * sizeof *pDecoded); + pDecoded[i] = n; + i++; + written_out++; + } + + *pout_length = written_out; + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-3602/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2022-3602/fixed.c new file mode 100644 index 0000000..db3e0d7 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-3602/fixed.c @@ -0,0 +1,90 @@ +/* Provenance: openssl/openssl ossl_punycode_decode (fixed). + * repo: openssl/openssl + * commit: 3b421ebc64c7b52f1b9feb3812bdc7781c784332 + * parent: 89d72311327735ef15c804d2adea84a0fb1bfa0a + * commit_url: https://github.com/openssl/openssl/commit/3b421ebc64c7b52f1b9feb3812bdc7781c784332 + * cve: CVE-2022-3602 + * license: Apache-2.0 + * function: ossl_punycode_decode + * relpath: crypto/punycode.c + */ + +int ossl_punycode_decode(const char *pEncoded, const size_t enc_len, + unsigned int *pDecoded, unsigned int *pout_length) +{ + unsigned int n = initial_n; + unsigned int i = 0; + unsigned int bias = initial_bias; + size_t processed_in = 0, written_out = 0; + unsigned int max_out = *pout_length; + + unsigned int basic_count = 0; + unsigned int loop; + + for (loop = 0; loop < enc_len; loop++) { + if (pEncoded[loop] == delimiter) + basic_count = loop; + } + + if (basic_count > 0) { + if (basic_count > max_out) + return 0; + + for (loop = 0; loop < basic_count; loop++) { + if (is_basic(pEncoded[loop]) == 0) + return 0; + + pDecoded[loop] = pEncoded[loop]; + written_out++; + } + processed_in = basic_count + 1; + } + + for (loop = processed_in; loop < enc_len;) { + unsigned int oldi = i; + unsigned int w = 1; + unsigned int k, t; + int digit; + + for (k = base;; k += base) { + if (loop >= enc_len) + return 0; + + digit = digit_decoded(pEncoded[loop]); + loop++; + + if (digit < 0) + return 0; + if ((unsigned int)digit > (maxint - i) / w) + return 0; + + i = i + digit * w; + t = (k <= bias) ? tmin : (k >= bias + tmax) ? tmax : k - bias; + + if ((unsigned int)digit < t) + break; + + if (w > maxint / (base - t)) + return 0; + w = w * (base - t); + } + + bias = adapt(i - oldi, written_out + 1, (oldi == 0)); + if (i / (written_out + 1) > maxint - n) + return 0; + n = n + i / (written_out + 1); + i %= (written_out + 1); + + if (written_out >= max_out) + return 0; + + memmove(pDecoded + i + 1, pDecoded + i, + (written_out - i) * sizeof *pDecoded); + pDecoded[i] = n; + i++; + written_out++; + } + + *pout_length = written_out; + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-3602/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2022-3602/vuln.c new file mode 100644 index 0000000..2210955 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-3602/vuln.c @@ -0,0 +1,90 @@ +/* Provenance: openssl/openssl ossl_punycode_decode (vuln). + * repo: openssl/openssl + * commit: 89d72311327735ef15c804d2adea84a0fb1bfa0a + * parent: 89d72311327735ef15c804d2adea84a0fb1bfa0a + * commit_url: https://github.com/openssl/openssl/commit/3b421ebc64c7b52f1b9feb3812bdc7781c784332 + * cve: CVE-2022-3602 + * license: Apache-2.0 + * function: ossl_punycode_decode + * relpath: crypto/punycode.c + */ + +int ossl_punycode_decode(const char *pEncoded, const size_t enc_len, + unsigned int *pDecoded, unsigned int *pout_length) +{ + unsigned int n = initial_n; + unsigned int i = 0; + unsigned int bias = initial_bias; + size_t processed_in = 0, written_out = 0; + unsigned int max_out = *pout_length; + + unsigned int basic_count = 0; + unsigned int loop; + + for (loop = 0; loop < enc_len; loop++) { + if (pEncoded[loop] == delimiter) + basic_count = loop; + } + + if (basic_count > 0) { + if (basic_count > max_out) + return 0; + + for (loop = 0; loop < basic_count; loop++) { + if (is_basic(pEncoded[loop]) == 0) + return 0; + + pDecoded[loop] = pEncoded[loop]; + written_out++; + } + processed_in = basic_count + 1; + } + + for (loop = processed_in; loop < enc_len;) { + unsigned int oldi = i; + unsigned int w = 1; + unsigned int k, t; + int digit; + + for (k = base;; k += base) { + if (loop >= enc_len) + return 0; + + digit = digit_decoded(pEncoded[loop]); + loop++; + + if (digit < 0) + return 0; + if ((unsigned int)digit > (maxint - i) / w) + return 0; + + i = i + digit * w; + t = (k <= bias) ? tmin : (k >= bias + tmax) ? tmax : k - bias; + + if ((unsigned int)digit < t) + break; + + if (w > maxint / (base - t)) + return 0; + w = w * (base - t); + } + + bias = adapt(i - oldi, written_out + 1, (oldi == 0)); + if (i / (written_out + 1) > maxint - n) + return 0; + n = n + i / (written_out + 1); + i %= (written_out + 1); + + if (written_out > max_out) + return 0; + + memmove(pDecoded + i + 1, pDecoded + i, + (written_out - i) * sizeof *pDecoded); + pDecoded[i] = n; + i++; + written_out++; + } + + *pout_length = written_out; + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-37454/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2022-37454/fixed.c new file mode 100644 index 0000000..cda12b7 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-37454/fixed.c @@ -0,0 +1,78 @@ +/* Provenance: openssl/openssl HKDF_Expand (fixed). + * repo: openssl/openssl + * commit: d12cde7fc5561d463badcd8a73079cf92864c31e + * parent: 5d6f13d90d5c4212737002bcd54871cf236a1220 + * commit_url: https://github.com/openssl/openssl/commit/d12cde7fc5561d463badcd8a73079cf92864c31e + * cve: CVE-2022-37454 + * license: Apache-2.0 + * function: HKDF_Expand + * relpath: providers/implementations/kdfs/hkdf.c + */ + +static int HKDF_Expand(const EVP_MD *evp_md, + const unsigned char *prk, size_t prk_len, + const unsigned char *info, size_t info_len, + unsigned char *okm, size_t okm_len) +{ + HMAC_CTX *hmac; + int ret = 0, sz; + unsigned int i; + unsigned char prev[EVP_MAX_MD_SIZE]; + size_t done_len = 0, dig_len, n; + + sz = EVP_MD_get_size(evp_md); + if (sz <= 0) + return 0; + dig_len = (size_t)sz; + + /* calc: N = ceil(L/HashLen) */ + n = okm_len / dig_len; + if (okm_len % dig_len) + n++; + + if (n > 255 || okm == NULL) + return 0; + + if ((hmac = HMAC_CTX_new()) == NULL) + return 0; + + if (!HMAC_Init_ex(hmac, prk, prk_len, evp_md, NULL)) + goto err; + + for (i = 1; i <= n; i++) { + size_t copy_len; + const unsigned char ctr = i; + + /* calc: T(i) = HMAC-Hash(PRK, T(i - 1) | info | i) */ + if (i > 1) { + if (!HMAC_Init_ex(hmac, NULL, 0, NULL, NULL)) + goto err; + + if (!HMAC_Update(hmac, prev, dig_len)) + goto err; + } + + if (!HMAC_Update(hmac, info, info_len)) + goto err; + + if (!HMAC_Update(hmac, &ctr, 1)) + goto err; + + if (!HMAC_Final(hmac, prev, NULL)) + goto err; + + copy_len = (dig_len > okm_len - done_len) ? + okm_len - done_len : + dig_len; + + memcpy(okm + done_len, prev, copy_len); + + done_len += copy_len; + } + ret = 1; + + err: + OPENSSL_cleanse(prev, sizeof(prev)); + HMAC_CTX_free(hmac); + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-37454/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2022-37454/vuln.c new file mode 100644 index 0000000..1ea3800 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-37454/vuln.c @@ -0,0 +1,78 @@ +/* Provenance: openssl/openssl HKDF_Expand (vuln). + * repo: openssl/openssl + * commit: 5d6f13d90d5c4212737002bcd54871cf236a1220 + * parent: 5d6f13d90d5c4212737002bcd54871cf236a1220 + * commit_url: https://github.com/openssl/openssl/commit/d12cde7fc5561d463badcd8a73079cf92864c31e + * cve: CVE-2022-37454 + * license: Apache-2.0 + * function: HKDF_Expand + * relpath: providers/implementations/kdfs/hkdf.c + */ + +static int HKDF_Expand(const EVP_MD *evp_md, + const unsigned char *prk, size_t prk_len, + const unsigned char *info, size_t info_len, + unsigned char *okm, size_t okm_len) +{ + HMAC_CTX *hmac; + int ret = 0, sz; + unsigned int i; + unsigned char prev[EVP_MAX_MD_SIZE]; + size_t done_len = 0, dig_len, n; + + sz = EVP_MD_get_size(evp_md); + if (sz <= 0) + return 0; + dig_len = (size_t)sz; + + /* calc: N = ceil(L/HashLen) */ + n = okm_len / dig_len; + if (okm_len % dig_len) + n++; + + if (n > 255 || okm == NULL) + return 0; + + if ((hmac = HMAC_CTX_new()) == NULL) + return 0; + + if (!HMAC_Init_ex(hmac, prk, prk_len, evp_md, NULL)) + goto err; + + for (i = 1; i <= n; i++) { + size_t copy_len; + const unsigned char ctr = i; + + /* calc: T(i) = HMAC-Hash(PRK, T(i - 1) | info | i) */ + if (i > 1) { + if (!HMAC_Init_ex(hmac, NULL, 0, NULL, NULL)) + goto err; + + if (!HMAC_Update(hmac, prev, dig_len)) + goto err; + } + + if (!HMAC_Update(hmac, info, info_len)) + goto err; + + if (!HMAC_Update(hmac, &ctr, 1)) + goto err; + + if (!HMAC_Final(hmac, prev, NULL)) + goto err; + + copy_len = (done_len + dig_len > okm_len) ? + okm_len - done_len : + dig_len; + + memcpy(okm + done_len, prev, copy_len); + + done_len += copy_len; + } + ret = 1; + + err: + OPENSSL_cleanse(prev, sizeof(prev)); + HMAC_CTX_free(hmac); + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-3786-ossl_punycode_decode/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2022-3786-ossl_punycode_decode/fixed.c new file mode 100644 index 0000000..047f893 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-3786-ossl_punycode_decode/fixed.c @@ -0,0 +1,89 @@ +/* Provenance: openssl/openssl ossl_punycode_decode (fixed). + * repo: openssl/openssl + * commit: 680e65b94c916af259bfdc2e25f1ab6e0c7a97d6 + * parent: 3b421ebc64c7b52f1b9feb3812bdc7781c784332 + * commit_url: https://github.com/openssl/openssl/commit/680e65b94c916af259bfdc2e25f1ab6e0c7a97d6 + * cve: CVE-2022-3786 + * license: Apache-2.0 + * function: ossl_punycode_decode + * relpath: crypto/punycode.c + */ + +int ossl_punycode_decode(const char *pEncoded, const size_t enc_len, + unsigned int *pDecoded, unsigned int *pout_length) +{ + unsigned int n = initial_n; + unsigned int i = 0; + unsigned int bias = initial_bias; + size_t processed_in = 0, written_out = 0; + unsigned int max_out = *pout_length; + unsigned int basic_count = 0; + unsigned int loop; + + for (loop = 0; loop < enc_len; loop++) { + if (pEncoded[loop] == delimiter) + basic_count = loop; + } + + if (basic_count > 0) { + if (basic_count > max_out) + return 0; + + for (loop = 0; loop < basic_count; loop++) { + if (is_basic(pEncoded[loop]) == 0) + return 0; + + pDecoded[loop] = pEncoded[loop]; + written_out++; + } + processed_in = basic_count + 1; + } + + for (loop = processed_in; loop < enc_len;) { + unsigned int oldi = i; + unsigned int w = 1; + unsigned int k, t; + int digit; + + for (k = base;; k += base) { + if (loop >= enc_len) + return 0; + + digit = digit_decoded(pEncoded[loop]); + loop++; + + if (digit < 0) + return 0; + if ((unsigned int)digit > (maxint - i) / w) + return 0; + + i = i + digit * w; + t = (k <= bias) ? tmin : (k >= bias + tmax) ? tmax : k - bias; + + if ((unsigned int)digit < t) + break; + + if (w > maxint / (base - t)) + return 0; + w = w * (base - t); + } + + bias = adapt(i - oldi, written_out + 1, (oldi == 0)); + if (i / (written_out + 1) > maxint - n) + return 0; + n = n + i / (written_out + 1); + i %= (written_out + 1); + + if (written_out >= max_out) + return 0; + + memmove(pDecoded + i + 1, pDecoded + i, + (written_out - i) * sizeof(*pDecoded)); + pDecoded[i] = n; + i++; + written_out++; + } + + *pout_length = written_out; + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-3786-ossl_punycode_decode/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2022-3786-ossl_punycode_decode/vuln.c new file mode 100644 index 0000000..a0d4b1b --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-3786-ossl_punycode_decode/vuln.c @@ -0,0 +1,90 @@ +/* Provenance: openssl/openssl ossl_punycode_decode (vuln). + * repo: openssl/openssl + * commit: 3b421ebc64c7b52f1b9feb3812bdc7781c784332 + * parent: 3b421ebc64c7b52f1b9feb3812bdc7781c784332 + * commit_url: https://github.com/openssl/openssl/commit/680e65b94c916af259bfdc2e25f1ab6e0c7a97d6 + * cve: CVE-2022-3786 + * license: Apache-2.0 + * function: ossl_punycode_decode + * relpath: crypto/punycode.c + */ + +int ossl_punycode_decode(const char *pEncoded, const size_t enc_len, + unsigned int *pDecoded, unsigned int *pout_length) +{ + unsigned int n = initial_n; + unsigned int i = 0; + unsigned int bias = initial_bias; + size_t processed_in = 0, written_out = 0; + unsigned int max_out = *pout_length; + + unsigned int basic_count = 0; + unsigned int loop; + + for (loop = 0; loop < enc_len; loop++) { + if (pEncoded[loop] == delimiter) + basic_count = loop; + } + + if (basic_count > 0) { + if (basic_count > max_out) + return 0; + + for (loop = 0; loop < basic_count; loop++) { + if (is_basic(pEncoded[loop]) == 0) + return 0; + + pDecoded[loop] = pEncoded[loop]; + written_out++; + } + processed_in = basic_count + 1; + } + + for (loop = processed_in; loop < enc_len;) { + unsigned int oldi = i; + unsigned int w = 1; + unsigned int k, t; + int digit; + + for (k = base;; k += base) { + if (loop >= enc_len) + return 0; + + digit = digit_decoded(pEncoded[loop]); + loop++; + + if (digit < 0) + return 0; + if ((unsigned int)digit > (maxint - i) / w) + return 0; + + i = i + digit * w; + t = (k <= bias) ? tmin : (k >= bias + tmax) ? tmax : k - bias; + + if ((unsigned int)digit < t) + break; + + if (w > maxint / (base - t)) + return 0; + w = w * (base - t); + } + + bias = adapt(i - oldi, written_out + 1, (oldi == 0)); + if (i / (written_out + 1) > maxint - n) + return 0; + n = n + i / (written_out + 1); + i %= (written_out + 1); + + if (written_out >= max_out) + return 0; + + memmove(pDecoded + i + 1, pDecoded + i, + (written_out - i) * sizeof *pDecoded); + pDecoded[i] = n; + i++; + written_out++; + } + + *pout_length = written_out; + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-3786/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2022-3786/fixed.c new file mode 100644 index 0000000..047f893 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-3786/fixed.c @@ -0,0 +1,89 @@ +/* Provenance: openssl/openssl ossl_punycode_decode (fixed). + * repo: openssl/openssl + * commit: 680e65b94c916af259bfdc2e25f1ab6e0c7a97d6 + * parent: 3b421ebc64c7b52f1b9feb3812bdc7781c784332 + * commit_url: https://github.com/openssl/openssl/commit/680e65b94c916af259bfdc2e25f1ab6e0c7a97d6 + * cve: CVE-2022-3786 + * license: Apache-2.0 + * function: ossl_punycode_decode + * relpath: crypto/punycode.c + */ + +int ossl_punycode_decode(const char *pEncoded, const size_t enc_len, + unsigned int *pDecoded, unsigned int *pout_length) +{ + unsigned int n = initial_n; + unsigned int i = 0; + unsigned int bias = initial_bias; + size_t processed_in = 0, written_out = 0; + unsigned int max_out = *pout_length; + unsigned int basic_count = 0; + unsigned int loop; + + for (loop = 0; loop < enc_len; loop++) { + if (pEncoded[loop] == delimiter) + basic_count = loop; + } + + if (basic_count > 0) { + if (basic_count > max_out) + return 0; + + for (loop = 0; loop < basic_count; loop++) { + if (is_basic(pEncoded[loop]) == 0) + return 0; + + pDecoded[loop] = pEncoded[loop]; + written_out++; + } + processed_in = basic_count + 1; + } + + for (loop = processed_in; loop < enc_len;) { + unsigned int oldi = i; + unsigned int w = 1; + unsigned int k, t; + int digit; + + for (k = base;; k += base) { + if (loop >= enc_len) + return 0; + + digit = digit_decoded(pEncoded[loop]); + loop++; + + if (digit < 0) + return 0; + if ((unsigned int)digit > (maxint - i) / w) + return 0; + + i = i + digit * w; + t = (k <= bias) ? tmin : (k >= bias + tmax) ? tmax : k - bias; + + if ((unsigned int)digit < t) + break; + + if (w > maxint / (base - t)) + return 0; + w = w * (base - t); + } + + bias = adapt(i - oldi, written_out + 1, (oldi == 0)); + if (i / (written_out + 1) > maxint - n) + return 0; + n = n + i / (written_out + 1); + i %= (written_out + 1); + + if (written_out >= max_out) + return 0; + + memmove(pDecoded + i + 1, pDecoded + i, + (written_out - i) * sizeof(*pDecoded)); + pDecoded[i] = n; + i++; + written_out++; + } + + *pout_length = written_out; + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-3786/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2022-3786/vuln.c new file mode 100644 index 0000000..a0d4b1b --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-3786/vuln.c @@ -0,0 +1,90 @@ +/* Provenance: openssl/openssl ossl_punycode_decode (vuln). + * repo: openssl/openssl + * commit: 3b421ebc64c7b52f1b9feb3812bdc7781c784332 + * parent: 3b421ebc64c7b52f1b9feb3812bdc7781c784332 + * commit_url: https://github.com/openssl/openssl/commit/680e65b94c916af259bfdc2e25f1ab6e0c7a97d6 + * cve: CVE-2022-3786 + * license: Apache-2.0 + * function: ossl_punycode_decode + * relpath: crypto/punycode.c + */ + +int ossl_punycode_decode(const char *pEncoded, const size_t enc_len, + unsigned int *pDecoded, unsigned int *pout_length) +{ + unsigned int n = initial_n; + unsigned int i = 0; + unsigned int bias = initial_bias; + size_t processed_in = 0, written_out = 0; + unsigned int max_out = *pout_length; + + unsigned int basic_count = 0; + unsigned int loop; + + for (loop = 0; loop < enc_len; loop++) { + if (pEncoded[loop] == delimiter) + basic_count = loop; + } + + if (basic_count > 0) { + if (basic_count > max_out) + return 0; + + for (loop = 0; loop < basic_count; loop++) { + if (is_basic(pEncoded[loop]) == 0) + return 0; + + pDecoded[loop] = pEncoded[loop]; + written_out++; + } + processed_in = basic_count + 1; + } + + for (loop = processed_in; loop < enc_len;) { + unsigned int oldi = i; + unsigned int w = 1; + unsigned int k, t; + int digit; + + for (k = base;; k += base) { + if (loop >= enc_len) + return 0; + + digit = digit_decoded(pEncoded[loop]); + loop++; + + if (digit < 0) + return 0; + if ((unsigned int)digit > (maxint - i) / w) + return 0; + + i = i + digit * w; + t = (k <= bias) ? tmin : (k >= bias + tmax) ? tmax : k - bias; + + if ((unsigned int)digit < t) + break; + + if (w > maxint / (base - t)) + return 0; + w = w * (base - t); + } + + bias = adapt(i - oldi, written_out + 1, (oldi == 0)); + if (i / (written_out + 1) > maxint - n) + return 0; + n = n + i / (written_out + 1); + i %= (written_out + 1); + + if (written_out >= max_out) + return 0; + + memmove(pDecoded + i + 1, pDecoded + i, + (written_out - i) * sizeof *pDecoded); + pDecoded[i] = n; + i++; + written_out++; + } + + *pout_length = written_out; + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-3996/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2022-3996/fixed.c new file mode 100644 index 0000000..6dbaa74 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-3996/fixed.c @@ -0,0 +1,69 @@ +/* Provenance: openssl/openssl ossl_policy_cache_set_mapping (fixed). + * repo: openssl/openssl + * commit: 7725e7bfe6f2ce8146b6552b44e0d226be7638e7 + * parent: 9a5c884999a55595e376083b3a165515c8123049 + * commit_url: https://github.com/openssl/openssl/commit/7725e7bfe6f2ce8146b6552b44e0d226be7638e7 + * cve: CVE-2022-3996 + * license: Apache-2.0 + * function: ossl_policy_cache_set_mapping + * relpath: crypto/x509/pcy_map.c + */ + +int ossl_policy_cache_set_mapping(X509 *x, POLICY_MAPPINGS *maps) +{ + POLICY_MAPPING *map; + X509_POLICY_DATA *data; + X509_POLICY_CACHE *cache = x->policy_cache; + int i; + int ret = 0; + if (sk_POLICY_MAPPING_num(maps) == 0) { + ret = -1; + goto bad_mapping; + } + for (i = 0; i < sk_POLICY_MAPPING_num(maps); i++) { + map = sk_POLICY_MAPPING_value(maps, i); + /* Reject if map to or from anyPolicy */ + if ((OBJ_obj2nid(map->subjectDomainPolicy) == NID_any_policy) + || (OBJ_obj2nid(map->issuerDomainPolicy) == NID_any_policy)) { + ret = -1; + goto bad_mapping; + } + + /* Attempt to find matching policy data */ + data = ossl_policy_cache_find_data(cache, map->issuerDomainPolicy); + /* If we don't have anyPolicy can't map */ + if (data == NULL && !cache->anyPolicy) + continue; + + /* Create a NODE from anyPolicy */ + if (data == NULL) { + data = ossl_policy_data_new(NULL, map->issuerDomainPolicy, + cache->anyPolicy->flags + & POLICY_DATA_FLAG_CRITICAL); + if (data == NULL) + goto bad_mapping; + data->qualifier_set = cache->anyPolicy->qualifier_set; + /* + * map->issuerDomainPolicy = NULL; + */ + data->flags |= POLICY_DATA_FLAG_MAPPED_ANY; + data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS; + if (!sk_X509_POLICY_DATA_push(cache->data, data)) { + ossl_policy_data_free(data); + goto bad_mapping; + } + } else + data->flags |= POLICY_DATA_FLAG_MAPPED; + if (!sk_ASN1_OBJECT_push(data->expected_policy_set, + map->subjectDomainPolicy)) + goto bad_mapping; + map->subjectDomainPolicy = NULL; + + } + + ret = 1; + bad_mapping: + sk_POLICY_MAPPING_pop_free(maps, POLICY_MAPPING_free); + return ret; + +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-3996/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2022-3996/vuln.c new file mode 100644 index 0000000..7ff304b --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-3996/vuln.c @@ -0,0 +1,73 @@ +/* Provenance: openssl/openssl ossl_policy_cache_set_mapping (vuln). + * repo: openssl/openssl + * commit: 9a5c884999a55595e376083b3a165515c8123049 + * parent: 9a5c884999a55595e376083b3a165515c8123049 + * commit_url: https://github.com/openssl/openssl/commit/7725e7bfe6f2ce8146b6552b44e0d226be7638e7 + * cve: CVE-2022-3996 + * license: Apache-2.0 + * function: ossl_policy_cache_set_mapping + * relpath: crypto/x509/pcy_map.c + */ + +int ossl_policy_cache_set_mapping(X509 *x, POLICY_MAPPINGS *maps) +{ + POLICY_MAPPING *map; + X509_POLICY_DATA *data; + X509_POLICY_CACHE *cache = x->policy_cache; + int i; + int ret = 0; + if (sk_POLICY_MAPPING_num(maps) == 0) { + ret = -1; + goto bad_mapping; + } + for (i = 0; i < sk_POLICY_MAPPING_num(maps); i++) { + map = sk_POLICY_MAPPING_value(maps, i); + /* Reject if map to or from anyPolicy */ + if ((OBJ_obj2nid(map->subjectDomainPolicy) == NID_any_policy) + || (OBJ_obj2nid(map->issuerDomainPolicy) == NID_any_policy)) { + ret = -1; + goto bad_mapping; + } + + /* Attempt to find matching policy data */ + data = ossl_policy_cache_find_data(cache, map->issuerDomainPolicy); + /* If we don't have anyPolicy can't map */ + if (data == NULL && !cache->anyPolicy) + continue; + + /* Create a NODE from anyPolicy */ + if (data == NULL) { + data = ossl_policy_data_new(NULL, map->issuerDomainPolicy, + cache->anyPolicy->flags + & POLICY_DATA_FLAG_CRITICAL); + if (data == NULL) + goto bad_mapping; + data->qualifier_set = cache->anyPolicy->qualifier_set; + /* + * map->issuerDomainPolicy = NULL; + */ + data->flags |= POLICY_DATA_FLAG_MAPPED_ANY; + data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS; + if (!sk_X509_POLICY_DATA_push(cache->data, data)) { + ossl_policy_data_free(data); + goto bad_mapping; + } + } else + data->flags |= POLICY_DATA_FLAG_MAPPED; + if (!sk_ASN1_OBJECT_push(data->expected_policy_set, + map->subjectDomainPolicy)) + goto bad_mapping; + map->subjectDomainPolicy = NULL; + + } + + ret = 1; + bad_mapping: + if (ret == -1 && CRYPTO_THREAD_write_lock(x->lock)) { + x->ex_flags |= EXFLAG_INVALID_POLICY; + CRYPTO_THREAD_unlock(x->lock); + } + sk_POLICY_MAPPING_pop_free(maps, POLICY_MAPPING_free); + return ret; + +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-4304-bn_blinding_invert_ex/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2022-4304-bn_blinding_invert_ex/fixed.c new file mode 100644 index 0000000..e172a08 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-4304-bn_blinding_invert_ex/fixed.c @@ -0,0 +1,47 @@ +/* Provenance: openssl/openssl BN_BLINDING_invert_ex (fixed). + * repo: openssl/openssl + * commit: a00d757d9ca212994625d1a02c81cc5edd27e13b + * parent: 908eaceb62624f5b5c505b286d904bd3a4e8a64a + * commit_url: https://github.com/openssl/openssl/commit/a00d757d9ca212994625d1a02c81cc5edd27e13b + * cve: CVE-2022-4304 + * license: Apache-2.0 + * function: BN_BLINDING_invert_ex + * relpath: crypto/bn/bn_blind.c + */ + +int BN_BLINDING_invert_ex(BIGNUM *n, const BIGNUM *r, BN_BLINDING *b, + BN_CTX *ctx) +{ + int ret; + + bn_check_top(n); + + if (r == NULL && (r = b->Ai) == NULL) { + ERR_raise(ERR_LIB_BN, BN_R_NOT_INITIALIZED); + return 0; + } + + if (b->m_ctx != NULL) { + /* ensure that BN_mod_mul_montgomery takes pre-defined path */ + if (n->dmax >= r->top) { + size_t i, rtop = r->top, ntop = n->top; + BN_ULONG mask; + + for (i = 0; i < rtop; i++) { + mask = (BN_ULONG)0 - ((i - ntop) >> (8 * sizeof(i) - 1)); + n->d[i] &= mask; + } + mask = (BN_ULONG)0 - ((rtop - ntop) >> (8 * sizeof(ntop) - 1)); + /* always true, if (rtop >= ntop) n->top = r->top; */ + n->top = (int)(rtop & ~mask) | (ntop & mask); + n->flags |= (BN_FLG_FIXED_TOP & ~mask); + } + ret = bn_mul_mont_fixed_top(n, n, r, b->m_ctx, ctx); + bn_correct_top_consttime(n); + } else { + ret = BN_mod_mul(n, n, r, b->mod, ctx); + } + + bn_check_top(n); + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-4304-bn_blinding_invert_ex/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2022-4304-bn_blinding_invert_ex/vuln.c new file mode 100644 index 0000000..6aea60d --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-4304-bn_blinding_invert_ex/vuln.c @@ -0,0 +1,46 @@ +/* Provenance: openssl/openssl BN_BLINDING_invert_ex (vuln). + * repo: openssl/openssl + * commit: 908eaceb62624f5b5c505b286d904bd3a4e8a64a + * parent: 908eaceb62624f5b5c505b286d904bd3a4e8a64a + * commit_url: https://github.com/openssl/openssl/commit/a00d757d9ca212994625d1a02c81cc5edd27e13b + * cve: CVE-2022-4304 + * license: Apache-2.0 + * function: BN_BLINDING_invert_ex + * relpath: crypto/bn/bn_blind.c + */ + +int BN_BLINDING_invert_ex(BIGNUM *n, const BIGNUM *r, BN_BLINDING *b, + BN_CTX *ctx) +{ + int ret; + + bn_check_top(n); + + if (r == NULL && (r = b->Ai) == NULL) { + ERR_raise(ERR_LIB_BN, BN_R_NOT_INITIALIZED); + return 0; + } + + if (b->m_ctx != NULL) { + /* ensure that BN_mod_mul_montgomery takes pre-defined path */ + if (n->dmax >= r->top) { + size_t i, rtop = r->top, ntop = n->top; + BN_ULONG mask; + + for (i = 0; i < rtop; i++) { + mask = (BN_ULONG)0 - ((i - ntop) >> (8 * sizeof(i) - 1)); + n->d[i] &= mask; + } + mask = (BN_ULONG)0 - ((rtop - ntop) >> (8 * sizeof(ntop) - 1)); + /* always true, if (rtop >= ntop) n->top = r->top; */ + n->top = (int)(rtop & ~mask) | (ntop & mask); + n->flags |= (BN_FLG_FIXED_TOP & ~mask); + } + ret = BN_mod_mul_montgomery(n, n, r, b->m_ctx, ctx); + } else { + ret = BN_mod_mul(n, n, r, b->mod, ctx); + } + + bn_check_top(n); + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-4304-rsa_blinding_invert/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2022-4304-rsa_blinding_invert/fixed.c new file mode 100644 index 0000000..ac1c281 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-4304-rsa_blinding_invert/fixed.c @@ -0,0 +1,25 @@ +/* Provenance: openssl/openssl rsa_blinding_invert (fixed). + * repo: openssl/openssl + * commit: a00d757d9ca212994625d1a02c81cc5edd27e13b + * parent: 908eaceb62624f5b5c505b286d904bd3a4e8a64a + * commit_url: https://github.com/openssl/openssl/commit/a00d757d9ca212994625d1a02c81cc5edd27e13b + * cve: CVE-2022-4304 + * license: Apache-2.0 + * function: rsa_blinding_invert + * relpath: crypto/rsa/rsa_ossl.c + */ + +static int rsa_blinding_invert(BN_BLINDING *b, BIGNUM *f, BIGNUM *unblind, + BN_CTX *ctx) +{ + /* + * For local blinding, unblind is set to NULL, and BN_BLINDING_invert_ex + * will use the unblinding factor stored in BN_BLINDING. If BN_BLINDING + * is shared between threads, unblind must be non-null: + * BN_BLINDING_invert_ex will then use the local unblinding factor, and + * will only read the modulus from BN_BLINDING. In both cases it's safe + * to access the blinding without a lock. + */ + BN_set_flags(f, BN_FLG_CONSTTIME); + return BN_BLINDING_invert_ex(f, unblind, b, ctx); +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-4304-rsa_blinding_invert/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2022-4304-rsa_blinding_invert/vuln.c new file mode 100644 index 0000000..fd1b148 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-4304-rsa_blinding_invert/vuln.c @@ -0,0 +1,24 @@ +/* Provenance: openssl/openssl rsa_blinding_invert (vuln). + * repo: openssl/openssl + * commit: 908eaceb62624f5b5c505b286d904bd3a4e8a64a + * parent: 908eaceb62624f5b5c505b286d904bd3a4e8a64a + * commit_url: https://github.com/openssl/openssl/commit/a00d757d9ca212994625d1a02c81cc5edd27e13b + * cve: CVE-2022-4304 + * license: Apache-2.0 + * function: rsa_blinding_invert + * relpath: crypto/rsa/rsa_ossl.c + */ + +static int rsa_blinding_invert(BN_BLINDING *b, BIGNUM *f, BIGNUM *unblind, + BN_CTX *ctx) +{ + /* + * For local blinding, unblind is set to NULL, and BN_BLINDING_invert_ex + * will use the unblinding factor stored in BN_BLINDING. If BN_BLINDING + * is shared between threads, unblind must be non-null: + * BN_BLINDING_invert_ex will then use the local unblinding factor, and + * will only read the modulus from BN_BLINDING. In both cases it's safe + * to access the blinding without a lock. + */ + return BN_BLINDING_invert_ex(f, unblind, b, ctx); +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-4304-rsa_ossl_private_decrypt/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2022-4304-rsa_ossl_private_decrypt/fixed.c new file mode 100644 index 0000000..7dc5046 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-4304-rsa_ossl_private_decrypt/fixed.c @@ -0,0 +1,155 @@ +/* Provenance: openssl/openssl rsa_ossl_private_decrypt (fixed). + * repo: openssl/openssl + * commit: 8022a4799fe884b3bf8d538e2b4c4ec323663118 + * parent: e2d0a3b5f559e23f11e4d4687b2889b483afb22a + * commit_url: https://github.com/openssl/openssl/commit/8022a4799fe884b3bf8d538e2b4c4ec323663118 + * cve: CVE-2022-4304 + * license: Apache-2.0 + * function: rsa_ossl_private_decrypt + * relpath: crypto/rsa/rsa_ossl.c + */ + +static int rsa_ossl_private_decrypt(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding) +{ + BIGNUM *f, *ret; + int j, num = 0, r = -1; + unsigned char *buf = NULL; + BN_CTX *ctx = NULL; + int local_blinding = 0; + /* + * Used only if the blinding structure is shared. A non-NULL unblind + * instructs rsa_blinding_convert() and rsa_blinding_invert() to store + * the unblinding factor outside the blinding structure. + */ + BIGNUM *unblind = NULL; + BN_BLINDING *blinding = NULL; + + if ((ctx = BN_CTX_new_ex(rsa->libctx)) == NULL) + goto err; + BN_CTX_start(ctx); + f = BN_CTX_get(ctx); + ret = BN_CTX_get(ctx); + num = BN_num_bytes(rsa->n); + buf = OPENSSL_malloc(num); + if (ret == NULL || buf == NULL) { + ERR_raise(ERR_LIB_RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* + * This check was for equality but PGP does evil things and chops off the + * top '0' bytes + */ + if (flen > num) { + ERR_raise(ERR_LIB_RSA, RSA_R_DATA_GREATER_THAN_MOD_LEN); + goto err; + } + + /* make data into a big number */ + if (BN_bin2bn(from, (int)flen, f) == NULL) + goto err; + + if (BN_ucmp(f, rsa->n) >= 0) { + ERR_raise(ERR_LIB_RSA, RSA_R_DATA_TOO_LARGE_FOR_MODULUS); + goto err; + } + + if (!(rsa->flags & RSA_FLAG_NO_BLINDING)) { + blinding = rsa_get_blinding(rsa, &local_blinding, ctx); + if (blinding == NULL) { + ERR_raise(ERR_LIB_RSA, ERR_R_INTERNAL_ERROR); + goto err; + } + } + + if (blinding != NULL) { + if (!local_blinding && ((unblind = BN_CTX_get(ctx)) == NULL)) { + ERR_raise(ERR_LIB_RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + if (!rsa_blinding_convert(blinding, f, unblind, ctx)) + goto err; + } + + /* do the decrypt */ + if ((rsa->flags & RSA_FLAG_EXT_PKEY) || + (rsa->version == RSA_ASN1_VERSION_MULTI) || + ((rsa->p != NULL) && + (rsa->q != NULL) && + (rsa->dmp1 != NULL) && (rsa->dmq1 != NULL) && (rsa->iqmp != NULL))) { + if (!rsa->meth->rsa_mod_exp(ret, f, rsa, ctx)) + goto err; + } else { + BIGNUM *d = BN_new(); + if (d == NULL) { + ERR_raise(ERR_LIB_RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + if (rsa->d == NULL) { + ERR_raise(ERR_LIB_RSA, RSA_R_MISSING_PRIVATE_KEY); + BN_free(d); + goto err; + } + BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME); + + if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) + if (!BN_MONT_CTX_set_locked(&rsa->_method_mod_n, rsa->lock, + rsa->n, ctx)) { + BN_free(d); + goto err; + } + if (!rsa->meth->bn_mod_exp(ret, f, d, rsa->n, ctx, + rsa->_method_mod_n)) { + BN_free(d); + goto err; + } + /* We MUST free d before any further use of rsa->d */ + BN_free(d); + } + + if (blinding) { + /* + * ossl_bn_rsa_do_unblind() combines blinding inversion and + * 0-padded BN BE serialization + */ + j = ossl_bn_rsa_do_unblind(ret, blinding, unblind, rsa->n, ctx, + buf, num); + if (j == 0) + goto err; + } else { + j = BN_bn2binpad(ret, buf, num); + if (j < 0) + goto err; + } + + switch (padding) { + case RSA_PKCS1_PADDING: + r = RSA_padding_check_PKCS1_type_2(to, num, buf, j, num); + break; + case RSA_PKCS1_OAEP_PADDING: + r = RSA_padding_check_PKCS1_OAEP(to, num, buf, j, num, NULL, 0); + break; + case RSA_NO_PADDING: + memcpy(to, buf, (r = j)); + break; + default: + ERR_raise(ERR_LIB_RSA, RSA_R_UNKNOWN_PADDING_TYPE); + goto err; + } +#ifndef FIPS_MODULE + /* + * This trick doesn't work in the FIPS provider because libcrypto manages + * the error stack. Instead we opt not to put an error on the stack at all + * in case of padding failure in the FIPS provider. + */ + ERR_raise(ERR_LIB_RSA, RSA_R_PADDING_CHECK_FAILED); + err_clear_last_constant_time(1 & ~constant_time_msb(r)); +#endif + + err: + BN_CTX_end(ctx); + BN_CTX_free(ctx); + OPENSSL_clear_free(buf, num); + return r; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-4304-rsa_ossl_private_decrypt/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2022-4304-rsa_ossl_private_decrypt/vuln.c new file mode 100644 index 0000000..282bf06 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-4304-rsa_ossl_private_decrypt/vuln.c @@ -0,0 +1,148 @@ +/* Provenance: openssl/openssl rsa_ossl_private_decrypt (vuln). + * repo: openssl/openssl + * commit: e2d0a3b5f559e23f11e4d4687b2889b483afb22a + * parent: e2d0a3b5f559e23f11e4d4687b2889b483afb22a + * commit_url: https://github.com/openssl/openssl/commit/8022a4799fe884b3bf8d538e2b4c4ec323663118 + * cve: CVE-2022-4304 + * license: Apache-2.0 + * function: rsa_ossl_private_decrypt + * relpath: crypto/rsa/rsa_ossl.c + */ + +static int rsa_ossl_private_decrypt(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding) +{ + BIGNUM *f, *ret; + int j, num = 0, r = -1; + unsigned char *buf = NULL; + BN_CTX *ctx = NULL; + int local_blinding = 0; + /* + * Used only if the blinding structure is shared. A non-NULL unblind + * instructs rsa_blinding_convert() and rsa_blinding_invert() to store + * the unblinding factor outside the blinding structure. + */ + BIGNUM *unblind = NULL; + BN_BLINDING *blinding = NULL; + + if ((ctx = BN_CTX_new_ex(rsa->libctx)) == NULL) + goto err; + BN_CTX_start(ctx); + f = BN_CTX_get(ctx); + ret = BN_CTX_get(ctx); + num = BN_num_bytes(rsa->n); + buf = OPENSSL_malloc(num); + if (ret == NULL || buf == NULL) { + ERR_raise(ERR_LIB_RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* + * This check was for equality but PGP does evil things and chops off the + * top '0' bytes + */ + if (flen > num) { + ERR_raise(ERR_LIB_RSA, RSA_R_DATA_GREATER_THAN_MOD_LEN); + goto err; + } + + /* make data into a big number */ + if (BN_bin2bn(from, (int)flen, f) == NULL) + goto err; + + if (BN_ucmp(f, rsa->n) >= 0) { + ERR_raise(ERR_LIB_RSA, RSA_R_DATA_TOO_LARGE_FOR_MODULUS); + goto err; + } + + if (!(rsa->flags & RSA_FLAG_NO_BLINDING)) { + blinding = rsa_get_blinding(rsa, &local_blinding, ctx); + if (blinding == NULL) { + ERR_raise(ERR_LIB_RSA, ERR_R_INTERNAL_ERROR); + goto err; + } + } + + if (blinding != NULL) { + if (!local_blinding && ((unblind = BN_CTX_get(ctx)) == NULL)) { + ERR_raise(ERR_LIB_RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + if (!rsa_blinding_convert(blinding, f, unblind, ctx)) + goto err; + } + + /* do the decrypt */ + if ((rsa->flags & RSA_FLAG_EXT_PKEY) || + (rsa->version == RSA_ASN1_VERSION_MULTI) || + ((rsa->p != NULL) && + (rsa->q != NULL) && + (rsa->dmp1 != NULL) && (rsa->dmq1 != NULL) && (rsa->iqmp != NULL))) { + if (!rsa->meth->rsa_mod_exp(ret, f, rsa, ctx)) + goto err; + } else { + BIGNUM *d = BN_new(); + if (d == NULL) { + ERR_raise(ERR_LIB_RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + if (rsa->d == NULL) { + ERR_raise(ERR_LIB_RSA, RSA_R_MISSING_PRIVATE_KEY); + BN_free(d); + goto err; + } + BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME); + + if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) + if (!BN_MONT_CTX_set_locked(&rsa->_method_mod_n, rsa->lock, + rsa->n, ctx)) { + BN_free(d); + goto err; + } + if (!rsa->meth->bn_mod_exp(ret, f, d, rsa->n, ctx, + rsa->_method_mod_n)) { + BN_free(d); + goto err; + } + /* We MUST free d before any further use of rsa->d */ + BN_free(d); + } + + if (blinding) + if (!rsa_blinding_invert(blinding, ret, unblind, ctx)) + goto err; + + j = BN_bn2binpad(ret, buf, num); + if (j < 0) + goto err; + + switch (padding) { + case RSA_PKCS1_PADDING: + r = RSA_padding_check_PKCS1_type_2(to, num, buf, j, num); + break; + case RSA_PKCS1_OAEP_PADDING: + r = RSA_padding_check_PKCS1_OAEP(to, num, buf, j, num, NULL, 0); + break; + case RSA_NO_PADDING: + memcpy(to, buf, (r = j)); + break; + default: + ERR_raise(ERR_LIB_RSA, RSA_R_UNKNOWN_PADDING_TYPE); + goto err; + } +#ifndef FIPS_MODULE + /* + * This trick doesn't work in the FIPS provider because libcrypto manages + * the error stack. Instead we opt not to put an error on the stack at all + * in case of padding failure in the FIPS provider. + */ + ERR_raise(ERR_LIB_RSA, RSA_R_PADDING_CHECK_FAILED); + err_clear_last_constant_time(1 & ~constant_time_msb(r)); +#endif + + err: + BN_CTX_end(ctx); + BN_CTX_free(ctx); + OPENSSL_clear_free(buf, num); + return r; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-4304/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2022-4304/fixed.c new file mode 100644 index 0000000..a4ff65f --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-4304/fixed.c @@ -0,0 +1,72 @@ +/* Provenance: openssl/openssl bn_sub_words (fixed). + * repo: openssl/openssl + * commit: a00d757d9ca212994625d1a02c81cc5edd27e13b + * parent: 908eaceb62624f5b5c505b286d904bd3a4e8a64a + * commit_url: https://github.com/openssl/openssl/commit/a00d757d9ca212994625d1a02c81cc5edd27e13b + * cve: CVE-2022-4304 + * license: Apache-2.0 + * function: bn_sub_words + * relpath: crypto/bn/bn_asm.c + */ + +BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, + int n) +{ + BN_ULONG t1, t2; + int c = 0; + + assert(n >= 0); + if (n <= 0) + return (BN_ULONG)0; + +#ifndef OPENSSL_SMALL_FOOTPRINT + while (n & ~3) { + t1 = a[0]; + t2 = (t1 - c) & BN_MASK2; + c = (t2 > t1); + t1 = b[0]; + t1 = (t2 - t1) & BN_MASK2; + r[0] = t1; + c += (t1 > t2); + t1 = a[1]; + t2 = (t1 - c) & BN_MASK2; + c = (t2 > t1); + t1 = b[1]; + t1 = (t2 - t1) & BN_MASK2; + r[1] = t1; + c += (t1 > t2); + t1 = a[2]; + t2 = (t1 - c) & BN_MASK2; + c = (t2 > t1); + t1 = b[2]; + t1 = (t2 - t1) & BN_MASK2; + r[2] = t1; + c += (t1 > t2); + t1 = a[3]; + t2 = (t1 - c) & BN_MASK2; + c = (t2 > t1); + t1 = b[3]; + t1 = (t2 - t1) & BN_MASK2; + r[3] = t1; + c += (t1 > t2); + a += 4; + b += 4; + r += 4; + n -= 4; + } +#endif + while (n) { + t1 = a[0]; + t2 = (t1 - c) & BN_MASK2; + c = (t2 > t1); + t1 = b[0]; + t1 = (t2 - t1) & BN_MASK2; + r[0] = t1; + c += (t1 > t2); + a++; + b++; + r++; + n--; + } + return c; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2022-4304/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2022-4304/vuln.c new file mode 100644 index 0000000..03abf4d --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2022-4304/vuln.c @@ -0,0 +1,62 @@ +/* Provenance: openssl/openssl bn_sub_words (vuln). + * repo: openssl/openssl + * commit: 908eaceb62624f5b5c505b286d904bd3a4e8a64a + * parent: 908eaceb62624f5b5c505b286d904bd3a4e8a64a + * commit_url: https://github.com/openssl/openssl/commit/a00d757d9ca212994625d1a02c81cc5edd27e13b + * cve: CVE-2022-4304 + * license: Apache-2.0 + * function: bn_sub_words + * relpath: crypto/bn/bn_asm.c + */ + +BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, + int n) +{ + BN_ULONG t1, t2; + int c = 0; + + assert(n >= 0); + if (n <= 0) + return (BN_ULONG)0; + +#ifndef OPENSSL_SMALL_FOOTPRINT + while (n & ~3) { + t1 = a[0]; + t2 = b[0]; + r[0] = (t1 - t2 - c) & BN_MASK2; + if (t1 != t2) + c = (t1 < t2); + t1 = a[1]; + t2 = b[1]; + r[1] = (t1 - t2 - c) & BN_MASK2; + if (t1 != t2) + c = (t1 < t2); + t1 = a[2]; + t2 = b[2]; + r[2] = (t1 - t2 - c) & BN_MASK2; + if (t1 != t2) + c = (t1 < t2); + t1 = a[3]; + t2 = b[3]; + r[3] = (t1 - t2 - c) & BN_MASK2; + if (t1 != t2) + c = (t1 < t2); + a += 4; + b += 4; + r += 4; + n -= 4; + } +#endif + while (n) { + t1 = a[0]; + t2 = b[0]; + r[0] = (t1 - t2 - c) & BN_MASK2; + if (t1 != t2) + c = (t1 < t2); + a++; + b++; + r++; + n--; + } + return c; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2023-0216/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2023-0216/fixed.c new file mode 100644 index 0000000..6f28b91 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2023-0216/fixed.c @@ -0,0 +1,21 @@ +/* Provenance: openssl/openssl STACK_OF (fixed). + * repo: openssl/openssl + * commit: 80253dbdc92bec584f4a9866b43f8674156d838a + * parent: 625faca931957719c76fb16094cf5b6e0debe23f + * commit_url: https://github.com/openssl/openssl/commit/80253dbdc92bec584f4a9866b43f8674156d838a + * cve: CVE-2023-0216 + * license: Apache-2.0 + * function: STACK_OF + * relpath: crypto/pkcs7/pk7_lib.c + */ + +static STACK_OF(X509) *pkcs7_get_signer_certs(const PKCS7 *p7) +{ + if (p7->d.ptr == NULL) + return NULL; + if (PKCS7_type_is_signed(p7)) + return p7->d.sign->cert; + if (PKCS7_type_is_signedAndEnveloped(p7)) + return p7->d.signed_and_enveloped->cert; + return NULL; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2023-0216/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2023-0216/vuln.c new file mode 100644 index 0000000..760ea46 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2023-0216/vuln.c @@ -0,0 +1,19 @@ +/* Provenance: openssl/openssl STACK_OF (vuln). + * repo: openssl/openssl + * commit: 625faca931957719c76fb16094cf5b6e0debe23f + * parent: 625faca931957719c76fb16094cf5b6e0debe23f + * commit_url: https://github.com/openssl/openssl/commit/80253dbdc92bec584f4a9866b43f8674156d838a + * cve: CVE-2023-0216 + * license: Apache-2.0 + * function: STACK_OF + * relpath: crypto/pkcs7/pk7_lib.c + */ + +static STACK_OF(X509) *pkcs7_get_signer_certs(const PKCS7 *p7) +{ + if (PKCS7_type_is_signed(p7)) + return p7->d.sign->cert; + if (PKCS7_type_is_signedAndEnveloped(p7)) + return p7->d.signed_and_enveloped->cert; + return NULL; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2023-0217/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2023-0217/fixed.c new file mode 100644 index 0000000..15a3730 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2023-0217/fixed.c @@ -0,0 +1,54 @@ +/* Provenance: openssl/openssl ossl_ffc_validate_public_key_partial (fixed). + * repo: openssl/openssl + * commit: bcec03c33cc00a7b5eb89ebeeee59e604570a86a + * parent: 3436f9c24ab90c1661e4798e7944f028d5d251ce + * commit_url: https://github.com/openssl/openssl/commit/bcec03c33cc00a7b5eb89ebeeee59e604570a86a + * cve: CVE-2023-0217 + * license: Apache-2.0 + * function: ossl_ffc_validate_public_key_partial + * relpath: crypto/ffc/ffc_key_validate.c + */ + +int ossl_ffc_validate_public_key_partial(const FFC_PARAMS *params, + const BIGNUM *pub_key, int *ret) +{ + int ok = 0; + BIGNUM *tmp = NULL; + BN_CTX *ctx = NULL; + + *ret = 0; + if (params == NULL || pub_key == NULL || params->p == NULL) { + *ret = FFC_ERROR_PASSED_NULL_PARAM; + return 0; + } + + ctx = BN_CTX_new_ex(NULL); + if (ctx == NULL) + goto err; + + BN_CTX_start(ctx); + tmp = BN_CTX_get(ctx); + /* Step(1): Verify pub_key >= 2 */ + if (tmp == NULL + || !BN_set_word(tmp, 1)) + goto err; + if (BN_cmp(pub_key, tmp) <= 0) { + *ret |= FFC_ERROR_PUBKEY_TOO_SMALL; + goto err; + } + /* Step(1): Verify pub_key <= p-2 */ + if (BN_copy(tmp, params->p) == NULL + || !BN_sub_word(tmp, 1)) + goto err; + if (BN_cmp(pub_key, tmp) >= 0) { + *ret |= FFC_ERROR_PUBKEY_TOO_LARGE; + goto err; + } + ok = 1; + err: + if (ctx != NULL) { + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + return ok; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2023-0217/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2023-0217/vuln.c new file mode 100644 index 0000000..cd34797 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2023-0217/vuln.c @@ -0,0 +1,49 @@ +/* Provenance: openssl/openssl ossl_ffc_validate_public_key_partial (vuln). + * repo: openssl/openssl + * commit: 3436f9c24ab90c1661e4798e7944f028d5d251ce + * parent: 3436f9c24ab90c1661e4798e7944f028d5d251ce + * commit_url: https://github.com/openssl/openssl/commit/bcec03c33cc00a7b5eb89ebeeee59e604570a86a + * cve: CVE-2023-0217 + * license: Apache-2.0 + * function: ossl_ffc_validate_public_key_partial + * relpath: crypto/ffc/ffc_key_validate.c + */ + +int ossl_ffc_validate_public_key_partial(const FFC_PARAMS *params, + const BIGNUM *pub_key, int *ret) +{ + int ok = 0; + BIGNUM *tmp = NULL; + BN_CTX *ctx = NULL; + + *ret = 0; + ctx = BN_CTX_new_ex(NULL); + if (ctx == NULL) + goto err; + + BN_CTX_start(ctx); + tmp = BN_CTX_get(ctx); + /* Step(1): Verify pub_key >= 2 */ + if (tmp == NULL + || !BN_set_word(tmp, 1)) + goto err; + if (BN_cmp(pub_key, tmp) <= 0) { + *ret |= FFC_ERROR_PUBKEY_TOO_SMALL; + goto err; + } + /* Step(1): Verify pub_key <= p-2 */ + if (BN_copy(tmp, params->p) == NULL + || !BN_sub_word(tmp, 1)) + goto err; + if (BN_cmp(pub_key, tmp) >= 0) { + *ret |= FFC_ERROR_PUBKEY_TOO_LARGE; + goto err; + } + ok = 1; + err: + if (ctx != NULL) { + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + return ok; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2023-0286-general_name_cmp/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2023-0286-general_name_cmp/fixed.c new file mode 100644 index 0000000..50128cc --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2023-0286-general_name_cmp/fixed.c @@ -0,0 +1,50 @@ +/* Provenance: openssl/openssl GENERAL_NAME_cmp (fixed). + * repo: openssl/openssl + * commit: 7880536fe17c2b5450e279155bedd51771d28c9f + * parent: adf77d6657e836fc87391fad53d857927a764297 + * commit_url: https://github.com/openssl/openssl/commit/7880536fe17c2b5450e279155bedd51771d28c9f + * cve: CVE-2023-0286 + * license: Apache-2.0 + * function: GENERAL_NAME_cmp + * relpath: crypto/x509/v3_genn.c + */ + +int GENERAL_NAME_cmp(GENERAL_NAME *a, GENERAL_NAME *b) +{ + int result = -1; + + if (!a || !b || a->type != b->type) + return -1; + switch (a->type) { + case GEN_X400: + result = ASN1_STRING_cmp(a->d.x400Address, b->d.x400Address); + break; + + case GEN_EDIPARTY: + result = edipartyname_cmp(a->d.ediPartyName, b->d.ediPartyName); + break; + + case GEN_OTHERNAME: + result = OTHERNAME_cmp(a->d.otherName, b->d.otherName); + break; + + case GEN_EMAIL: + case GEN_DNS: + case GEN_URI: + result = ASN1_STRING_cmp(a->d.ia5, b->d.ia5); + break; + + case GEN_DIRNAME: + result = X509_NAME_cmp(a->d.dirn, b->d.dirn); + break; + + case GEN_IPADD: + result = ASN1_OCTET_STRING_cmp(a->d.ip, b->d.ip); + break; + + case GEN_RID: + result = OBJ_cmp(a->d.rid, b->d.rid); + break; + } + return result; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2023-0286-general_name_cmp/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2023-0286-general_name_cmp/vuln.c new file mode 100644 index 0000000..e5e8925 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2023-0286-general_name_cmp/vuln.c @@ -0,0 +1,50 @@ +/* Provenance: openssl/openssl GENERAL_NAME_cmp (vuln). + * repo: openssl/openssl + * commit: adf77d6657e836fc87391fad53d857927a764297 + * parent: adf77d6657e836fc87391fad53d857927a764297 + * commit_url: https://github.com/openssl/openssl/commit/7880536fe17c2b5450e279155bedd51771d28c9f + * cve: CVE-2023-0286 + * license: Apache-2.0 + * function: GENERAL_NAME_cmp + * relpath: crypto/x509/v3_genn.c + */ + +int GENERAL_NAME_cmp(GENERAL_NAME *a, GENERAL_NAME *b) +{ + int result = -1; + + if (!a || !b || a->type != b->type) + return -1; + switch (a->type) { + case GEN_X400: + result = ASN1_TYPE_cmp(a->d.x400Address, b->d.x400Address); + break; + + case GEN_EDIPARTY: + result = edipartyname_cmp(a->d.ediPartyName, b->d.ediPartyName); + break; + + case GEN_OTHERNAME: + result = OTHERNAME_cmp(a->d.otherName, b->d.otherName); + break; + + case GEN_EMAIL: + case GEN_DNS: + case GEN_URI: + result = ASN1_STRING_cmp(a->d.ia5, b->d.ia5); + break; + + case GEN_DIRNAME: + result = X509_NAME_cmp(a->d.dirn, b->d.dirn); + break; + + case GEN_IPADD: + result = ASN1_OCTET_STRING_cmp(a->d.ip, b->d.ip); + break; + + case GEN_RID: + result = OBJ_cmp(a->d.rid, b->d.rid); + break; + } + return result; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2023-0286/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2023-0286/fixed.c new file mode 100644 index 0000000..50128cc --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2023-0286/fixed.c @@ -0,0 +1,50 @@ +/* Provenance: openssl/openssl GENERAL_NAME_cmp (fixed). + * repo: openssl/openssl + * commit: 7880536fe17c2b5450e279155bedd51771d28c9f + * parent: adf77d6657e836fc87391fad53d857927a764297 + * commit_url: https://github.com/openssl/openssl/commit/7880536fe17c2b5450e279155bedd51771d28c9f + * cve: CVE-2023-0286 + * license: Apache-2.0 + * function: GENERAL_NAME_cmp + * relpath: crypto/x509/v3_genn.c + */ + +int GENERAL_NAME_cmp(GENERAL_NAME *a, GENERAL_NAME *b) +{ + int result = -1; + + if (!a || !b || a->type != b->type) + return -1; + switch (a->type) { + case GEN_X400: + result = ASN1_STRING_cmp(a->d.x400Address, b->d.x400Address); + break; + + case GEN_EDIPARTY: + result = edipartyname_cmp(a->d.ediPartyName, b->d.ediPartyName); + break; + + case GEN_OTHERNAME: + result = OTHERNAME_cmp(a->d.otherName, b->d.otherName); + break; + + case GEN_EMAIL: + case GEN_DNS: + case GEN_URI: + result = ASN1_STRING_cmp(a->d.ia5, b->d.ia5); + break; + + case GEN_DIRNAME: + result = X509_NAME_cmp(a->d.dirn, b->d.dirn); + break; + + case GEN_IPADD: + result = ASN1_OCTET_STRING_cmp(a->d.ip, b->d.ip); + break; + + case GEN_RID: + result = OBJ_cmp(a->d.rid, b->d.rid); + break; + } + return result; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2023-0286/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2023-0286/vuln.c new file mode 100644 index 0000000..e5e8925 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2023-0286/vuln.c @@ -0,0 +1,50 @@ +/* Provenance: openssl/openssl GENERAL_NAME_cmp (vuln). + * repo: openssl/openssl + * commit: adf77d6657e836fc87391fad53d857927a764297 + * parent: adf77d6657e836fc87391fad53d857927a764297 + * commit_url: https://github.com/openssl/openssl/commit/7880536fe17c2b5450e279155bedd51771d28c9f + * cve: CVE-2023-0286 + * license: Apache-2.0 + * function: GENERAL_NAME_cmp + * relpath: crypto/x509/v3_genn.c + */ + +int GENERAL_NAME_cmp(GENERAL_NAME *a, GENERAL_NAME *b) +{ + int result = -1; + + if (!a || !b || a->type != b->type) + return -1; + switch (a->type) { + case GEN_X400: + result = ASN1_TYPE_cmp(a->d.x400Address, b->d.x400Address); + break; + + case GEN_EDIPARTY: + result = edipartyname_cmp(a->d.ediPartyName, b->d.ediPartyName); + break; + + case GEN_OTHERNAME: + result = OTHERNAME_cmp(a->d.otherName, b->d.otherName); + break; + + case GEN_EMAIL: + case GEN_DNS: + case GEN_URI: + result = ASN1_STRING_cmp(a->d.ia5, b->d.ia5); + break; + + case GEN_DIRNAME: + result = X509_NAME_cmp(a->d.dirn, b->d.dirn); + break; + + case GEN_IPADD: + result = ASN1_OCTET_STRING_cmp(a->d.ip, b->d.ip); + break; + + case GEN_RID: + result = OBJ_cmp(a->d.rid, b->d.rid); + break; + } + return result; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2023-0401/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2023-0401/fixed.c new file mode 100644 index 0000000..b64b9e6 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2023-0401/fixed.c @@ -0,0 +1,61 @@ +/* Provenance: openssl/openssl pkcs7_bio_add_digest (fixed). + * repo: openssl/openssl + * commit: 6eebe6c0238178356114a96a7858f36b24172847 + * parent: 7880536fe17c2b5450e279155bedd51771d28c9f + * commit_url: https://github.com/openssl/openssl/commit/6eebe6c0238178356114a96a7858f36b24172847 + * cve: CVE-2023-0401 + * license: Apache-2.0 + * function: pkcs7_bio_add_digest + * relpath: crypto/pkcs7/pk7_doit.c + */ + +static int pkcs7_bio_add_digest(BIO **pbio, X509_ALGOR *alg, + const PKCS7_CTX *ctx) +{ + BIO *btmp; + char name[OSSL_MAX_NAME_SIZE]; + EVP_MD *fetched = NULL; + const EVP_MD *md; + + if ((btmp = BIO_new(BIO_f_md())) == NULL) { + ERR_raise(ERR_LIB_PKCS7, ERR_R_BIO_LIB); + goto err; + } + + OBJ_obj2txt(name, sizeof(name), alg->algorithm, 0); + + (void)ERR_set_mark(); + fetched = EVP_MD_fetch(ossl_pkcs7_ctx_get0_libctx(ctx), name, + ossl_pkcs7_ctx_get0_propq(ctx)); + if (fetched != NULL) + md = fetched; + else + md = EVP_get_digestbyname(name); + + if (md == NULL) { + (void)ERR_clear_last_mark(); + ERR_raise(ERR_LIB_PKCS7, PKCS7_R_UNKNOWN_DIGEST_TYPE); + goto err; + } + (void)ERR_pop_to_mark(); + + if (BIO_set_md(btmp, md) <= 0) { + ERR_raise(ERR_LIB_PKCS7, ERR_R_BIO_LIB); + EVP_MD_free(fetched); + goto err; + } + EVP_MD_free(fetched); + if (*pbio == NULL) + *pbio = btmp; + else if (!BIO_push(*pbio, btmp)) { + ERR_raise(ERR_LIB_PKCS7, ERR_R_BIO_LIB); + goto err; + } + btmp = NULL; + + return 1; + + err: + BIO_free(btmp); + return 0; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2023-0401/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2023-0401/vuln.c new file mode 100644 index 0000000..937754b --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2023-0401/vuln.c @@ -0,0 +1,57 @@ +/* Provenance: openssl/openssl pkcs7_bio_add_digest (vuln). + * repo: openssl/openssl + * commit: 7880536fe17c2b5450e279155bedd51771d28c9f + * parent: 7880536fe17c2b5450e279155bedd51771d28c9f + * commit_url: https://github.com/openssl/openssl/commit/6eebe6c0238178356114a96a7858f36b24172847 + * cve: CVE-2023-0401 + * license: Apache-2.0 + * function: pkcs7_bio_add_digest + * relpath: crypto/pkcs7/pk7_doit.c + */ + +static int pkcs7_bio_add_digest(BIO **pbio, X509_ALGOR *alg, + const PKCS7_CTX *ctx) +{ + BIO *btmp; + char name[OSSL_MAX_NAME_SIZE]; + EVP_MD *fetched = NULL; + const EVP_MD *md; + + if ((btmp = BIO_new(BIO_f_md())) == NULL) { + ERR_raise(ERR_LIB_PKCS7, ERR_R_BIO_LIB); + goto err; + } + + OBJ_obj2txt(name, sizeof(name), alg->algorithm, 0); + + (void)ERR_set_mark(); + fetched = EVP_MD_fetch(ossl_pkcs7_ctx_get0_libctx(ctx), name, + ossl_pkcs7_ctx_get0_propq(ctx)); + if (fetched != NULL) + md = fetched; + else + md = EVP_get_digestbyname(name); + + if (md == NULL) { + (void)ERR_clear_last_mark(); + ERR_raise(ERR_LIB_PKCS7, PKCS7_R_UNKNOWN_DIGEST_TYPE); + goto err; + } + (void)ERR_pop_to_mark(); + + BIO_set_md(btmp, md); + EVP_MD_free(fetched); + if (*pbio == NULL) + *pbio = btmp; + else if (!BIO_push(*pbio, btmp)) { + ERR_raise(ERR_LIB_PKCS7, ERR_R_BIO_LIB); + goto err; + } + btmp = NULL; + + return 1; + + err: + BIO_free(btmp); + return 0; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2023-0464-tree_init/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2023-0464-tree_init/fixed.c new file mode 100644 index 0000000..886feea --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2023-0464-tree_init/fixed.c @@ -0,0 +1,167 @@ +/* Provenance: openssl/openssl tree_init (fixed). + * repo: openssl/openssl + * commit: 959c59c7a0164117e7f8366466a32bb1f8d77ff1 + * parent: c309c4dce742c3eeb393a0f03f9c567d0e368ccc + * commit_url: https://github.com/openssl/openssl/commit/959c59c7a0164117e7f8366466a32bb1f8d77ff1 + * cve: CVE-2023-0464 + * license: Apache-2.0 + * function: tree_init + * relpath: crypto/x509/pcy_tree.c + */ + +static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs, + unsigned int flags) +{ + X509_POLICY_TREE *tree; + X509_POLICY_LEVEL *level; + const X509_POLICY_CACHE *cache; + X509_POLICY_DATA *data = NULL; + int ret = X509_PCY_TREE_VALID; + int n = sk_X509_num(certs) - 1; /* RFC5280 paths omit the TA */ + int explicit_policy = (flags & X509_V_FLAG_EXPLICIT_POLICY) ? 0 : n+1; + int any_skip = (flags & X509_V_FLAG_INHIBIT_ANY) ? 0 : n+1; + int map_skip = (flags & X509_V_FLAG_INHIBIT_MAP) ? 0 : n+1; + int i; + + *ptree = NULL; + + /* Can't do anything with just a trust anchor */ + if (n == 0) + return X509_PCY_TREE_EMPTY; + + /* + * First setup the policy cache in all n non-TA certificates, this will be + * used in X509_verify_cert() which will invoke the verify callback for all + * certificates with invalid policy extensions. + */ + for (i = n - 1; i >= 0; i--) { + X509 *x = sk_X509_value(certs, i); + + /* Call for side-effect of computing hash and caching extensions */ + X509_check_purpose(x, -1, 0); + + /* If cache is NULL, likely ENOMEM: return immediately */ + if (ossl_policy_cache_set(x) == NULL) + return X509_PCY_TREE_INTERNAL; + } + + /* + * At this point check for invalid policies and required explicit policy. + * Note that the explicit_policy counter is a count-down to zero, with the + * requirement kicking in if and once it does that. The counter is + * decremented for every non-self-issued certificate in the path, but may + * be further reduced by policy constraints in a non-leaf certificate. + * + * The ultimate policy set is the intersection of all the policies along + * the path, if we hit a certificate with an empty policy set, and explicit + * policy is required we're done. + */ + for (i = n - 1; + i >= 0 && (explicit_policy > 0 || (ret & X509_PCY_TREE_EMPTY) == 0); + i--) { + X509 *x = sk_X509_value(certs, i); + uint32_t ex_flags = X509_get_extension_flags(x); + + /* All the policies are already cached, we can return early */ + if (ex_flags & EXFLAG_INVALID_POLICY) + return X509_PCY_TREE_INVALID; + + /* Access the cache which we now know exists */ + cache = ossl_policy_cache_set(x); + + if ((ret & X509_PCY_TREE_VALID) && cache->data == NULL) + ret = X509_PCY_TREE_EMPTY; + if (explicit_policy > 0) { + if (!(ex_flags & EXFLAG_SI)) + explicit_policy--; + if ((cache->explicit_skip >= 0) + && (cache->explicit_skip < explicit_policy)) + explicit_policy = cache->explicit_skip; + } + } + + if (explicit_policy == 0) + ret |= X509_PCY_TREE_EXPLICIT; + if ((ret & X509_PCY_TREE_VALID) == 0) + return ret; + + /* If we get this far initialize the tree */ + if ((tree = OPENSSL_zalloc(sizeof(*tree))) == NULL) { + ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE); + return X509_PCY_TREE_INTERNAL; + } + + /* Limit the growth of the tree to mitigate CVE-2023-0464 */ + tree->node_maximum = OPENSSL_POLICY_TREE_NODES_MAX; + + /* + * http://tools.ietf.org/html/rfc5280#section-6.1.2, figure 3. + * + * The top level is implicitly for the trust anchor with valid expected + * policies of anyPolicy. (RFC 5280 has the TA at depth 0 and the leaf at + * depth n, we have the leaf at depth 0 and the TA at depth n). + */ + if ((tree->levels = OPENSSL_zalloc(sizeof(*tree->levels)*(n+1))) == NULL) { + OPENSSL_free(tree); + ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE); + return X509_PCY_TREE_INTERNAL; + } + tree->nlevel = n+1; + level = tree->levels; + if ((data = ossl_policy_data_new(NULL, + OBJ_nid2obj(NID_any_policy), 0)) == NULL) + goto bad_tree; + if (ossl_policy_level_add_node(level, data, NULL, tree, 1) == NULL) { + ossl_policy_data_free(data); + goto bad_tree; + } + + /* + * In this pass initialize all the tree levels and whether anyPolicy and + * policy mapping are inhibited at each level. + */ + for (i = n - 1; i >= 0; i--) { + X509 *x = sk_X509_value(certs, i); + uint32_t ex_flags = X509_get_extension_flags(x); + + /* Access the cache which we now know exists */ + cache = ossl_policy_cache_set(x); + + X509_up_ref(x); + (++level)->cert = x; + + if (!cache->anyPolicy) + level->flags |= X509_V_FLAG_INHIBIT_ANY; + + /* Determine inhibit any and inhibit map flags */ + if (any_skip == 0) { + /* + * Any matching allowed only if certificate is self issued and not + * the last in the chain. + */ + if (!(ex_flags & EXFLAG_SI) || (i == 0)) + level->flags |= X509_V_FLAG_INHIBIT_ANY; + } else { + if (!(ex_flags & EXFLAG_SI)) + any_skip--; + if ((cache->any_skip >= 0) && (cache->any_skip < any_skip)) + any_skip = cache->any_skip; + } + + if (map_skip == 0) + level->flags |= X509_V_FLAG_INHIBIT_MAP; + else { + if (!(ex_flags & EXFLAG_SI)) + map_skip--; + if ((cache->map_skip >= 0) && (cache->map_skip < map_skip)) + map_skip = cache->map_skip; + } + } + + *ptree = tree; + return ret; + + bad_tree: + X509_policy_tree_free(tree); + return X509_PCY_TREE_INTERNAL; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2023-0464-tree_init/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2023-0464-tree_init/vuln.c new file mode 100644 index 0000000..77eb084 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2023-0464-tree_init/vuln.c @@ -0,0 +1,164 @@ +/* Provenance: openssl/openssl tree_init (vuln). + * repo: openssl/openssl + * commit: c309c4dce742c3eeb393a0f03f9c567d0e368ccc + * parent: c309c4dce742c3eeb393a0f03f9c567d0e368ccc + * commit_url: https://github.com/openssl/openssl/commit/959c59c7a0164117e7f8366466a32bb1f8d77ff1 + * cve: CVE-2023-0464 + * license: Apache-2.0 + * function: tree_init + * relpath: crypto/x509/pcy_tree.c + */ + +static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs, + unsigned int flags) +{ + X509_POLICY_TREE *tree; + X509_POLICY_LEVEL *level; + const X509_POLICY_CACHE *cache; + X509_POLICY_DATA *data = NULL; + int ret = X509_PCY_TREE_VALID; + int n = sk_X509_num(certs) - 1; /* RFC5280 paths omit the TA */ + int explicit_policy = (flags & X509_V_FLAG_EXPLICIT_POLICY) ? 0 : n+1; + int any_skip = (flags & X509_V_FLAG_INHIBIT_ANY) ? 0 : n+1; + int map_skip = (flags & X509_V_FLAG_INHIBIT_MAP) ? 0 : n+1; + int i; + + *ptree = NULL; + + /* Can't do anything with just a trust anchor */ + if (n == 0) + return X509_PCY_TREE_EMPTY; + + /* + * First setup the policy cache in all n non-TA certificates, this will be + * used in X509_verify_cert() which will invoke the verify callback for all + * certificates with invalid policy extensions. + */ + for (i = n - 1; i >= 0; i--) { + X509 *x = sk_X509_value(certs, i); + + /* Call for side-effect of computing hash and caching extensions */ + X509_check_purpose(x, -1, 0); + + /* If cache is NULL, likely ENOMEM: return immediately */ + if (ossl_policy_cache_set(x) == NULL) + return X509_PCY_TREE_INTERNAL; + } + + /* + * At this point check for invalid policies and required explicit policy. + * Note that the explicit_policy counter is a count-down to zero, with the + * requirement kicking in if and once it does that. The counter is + * decremented for every non-self-issued certificate in the path, but may + * be further reduced by policy constraints in a non-leaf certificate. + * + * The ultimate policy set is the intersection of all the policies along + * the path, if we hit a certificate with an empty policy set, and explicit + * policy is required we're done. + */ + for (i = n - 1; + i >= 0 && (explicit_policy > 0 || (ret & X509_PCY_TREE_EMPTY) == 0); + i--) { + X509 *x = sk_X509_value(certs, i); + uint32_t ex_flags = X509_get_extension_flags(x); + + /* All the policies are already cached, we can return early */ + if (ex_flags & EXFLAG_INVALID_POLICY) + return X509_PCY_TREE_INVALID; + + /* Access the cache which we now know exists */ + cache = ossl_policy_cache_set(x); + + if ((ret & X509_PCY_TREE_VALID) && cache->data == NULL) + ret = X509_PCY_TREE_EMPTY; + if (explicit_policy > 0) { + if (!(ex_flags & EXFLAG_SI)) + explicit_policy--; + if ((cache->explicit_skip >= 0) + && (cache->explicit_skip < explicit_policy)) + explicit_policy = cache->explicit_skip; + } + } + + if (explicit_policy == 0) + ret |= X509_PCY_TREE_EXPLICIT; + if ((ret & X509_PCY_TREE_VALID) == 0) + return ret; + + /* If we get this far initialize the tree */ + if ((tree = OPENSSL_zalloc(sizeof(*tree))) == NULL) { + ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE); + return X509_PCY_TREE_INTERNAL; + } + + /* + * http://tools.ietf.org/html/rfc5280#section-6.1.2, figure 3. + * + * The top level is implicitly for the trust anchor with valid expected + * policies of anyPolicy. (RFC 5280 has the TA at depth 0 and the leaf at + * depth n, we have the leaf at depth 0 and the TA at depth n). + */ + if ((tree->levels = OPENSSL_zalloc(sizeof(*tree->levels)*(n+1))) == NULL) { + OPENSSL_free(tree); + ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE); + return X509_PCY_TREE_INTERNAL; + } + tree->nlevel = n+1; + level = tree->levels; + if ((data = ossl_policy_data_new(NULL, + OBJ_nid2obj(NID_any_policy), 0)) == NULL) + goto bad_tree; + if (ossl_policy_level_add_node(level, data, NULL, tree) == NULL) { + ossl_policy_data_free(data); + goto bad_tree; + } + + /* + * In this pass initialize all the tree levels and whether anyPolicy and + * policy mapping are inhibited at each level. + */ + for (i = n - 1; i >= 0; i--) { + X509 *x = sk_X509_value(certs, i); + uint32_t ex_flags = X509_get_extension_flags(x); + + /* Access the cache which we now know exists */ + cache = ossl_policy_cache_set(x); + + X509_up_ref(x); + (++level)->cert = x; + + if (!cache->anyPolicy) + level->flags |= X509_V_FLAG_INHIBIT_ANY; + + /* Determine inhibit any and inhibit map flags */ + if (any_skip == 0) { + /* + * Any matching allowed only if certificate is self issued and not + * the last in the chain. + */ + if (!(ex_flags & EXFLAG_SI) || (i == 0)) + level->flags |= X509_V_FLAG_INHIBIT_ANY; + } else { + if (!(ex_flags & EXFLAG_SI)) + any_skip--; + if ((cache->any_skip >= 0) && (cache->any_skip < any_skip)) + any_skip = cache->any_skip; + } + + if (map_skip == 0) + level->flags |= X509_V_FLAG_INHIBIT_MAP; + else { + if (!(ex_flags & EXFLAG_SI)) + map_skip--; + if ((cache->map_skip >= 0) && (cache->map_skip < map_skip)) + map_skip = cache->map_skip; + } + } + + *ptree = tree; + return ret; + + bad_tree: + X509_policy_tree_free(tree); + return X509_PCY_TREE_INTERNAL; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2023-0464/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2023-0464/fixed.c new file mode 100644 index 0000000..acd0504 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2023-0464/fixed.c @@ -0,0 +1,166 @@ +/* Provenance: openssl/openssl tree_init (fixed). + * repo: openssl/openssl + * commit: 879f7080d7e141f415c79eaa3a8ac4a3dad0348b + * parent: 969327390220aee7515a4054d5189186402d6687 + * commit_url: https://github.com/openssl/openssl/commit/879f7080d7e141f415c79eaa3a8ac4a3dad0348b + * cve: CVE-2023-0464 + * license: Apache-2.0 + * function: tree_init + * relpath: crypto/x509v3/pcy_tree.c + */ + +static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs, + unsigned int flags) +{ + X509_POLICY_TREE *tree; + X509_POLICY_LEVEL *level; + const X509_POLICY_CACHE *cache; + X509_POLICY_DATA *data = NULL; + int ret = X509_PCY_TREE_VALID; + int n = sk_X509_num(certs) - 1; /* RFC5280 paths omit the TA */ + int explicit_policy = (flags & X509_V_FLAG_EXPLICIT_POLICY) ? 0 : n+1; + int any_skip = (flags & X509_V_FLAG_INHIBIT_ANY) ? 0 : n+1; + int map_skip = (flags & X509_V_FLAG_INHIBIT_MAP) ? 0 : n+1; + int i; + + *ptree = NULL; + + /* Can't do anything with just a trust anchor */ + if (n == 0) + return X509_PCY_TREE_EMPTY; + + /* + * First setup the policy cache in all n non-TA certificates, this will be + * used in X509_verify_cert() which will invoke the verify callback for all + * certificates with invalid policy extensions. + */ + for (i = n - 1; i >= 0; i--) { + X509 *x = sk_X509_value(certs, i); + + /* Call for side-effect of computing hash and caching extensions */ + X509_check_purpose(x, -1, 0); + + /* If cache is NULL, likely ENOMEM: return immediately */ + if (policy_cache_set(x) == NULL) + return X509_PCY_TREE_INTERNAL; + } + + /* + * At this point check for invalid policies and required explicit policy. + * Note that the explicit_policy counter is a count-down to zero, with the + * requirement kicking in if and once it does that. The counter is + * decremented for every non-self-issued certificate in the path, but may + * be further reduced by policy constraints in a non-leaf certificate. + * + * The ultimate policy set is the intersection of all the policies along + * the path, if we hit a certificate with an empty policy set, and explicit + * policy is required we're done. + */ + for (i = n - 1; + i >= 0 && (explicit_policy > 0 || (ret & X509_PCY_TREE_EMPTY) == 0); + i--) { + X509 *x = sk_X509_value(certs, i); + uint32_t ex_flags = X509_get_extension_flags(x); + + /* All the policies are already cached, we can return early */ + if (ex_flags & EXFLAG_INVALID_POLICY) + return X509_PCY_TREE_INVALID; + + /* Access the cache which we now know exists */ + cache = policy_cache_set(x); + + if ((ret & X509_PCY_TREE_VALID) && cache->data == NULL) + ret = X509_PCY_TREE_EMPTY; + if (explicit_policy > 0) { + if (!(ex_flags & EXFLAG_SI)) + explicit_policy--; + if ((cache->explicit_skip >= 0) + && (cache->explicit_skip < explicit_policy)) + explicit_policy = cache->explicit_skip; + } + } + + if (explicit_policy == 0) + ret |= X509_PCY_TREE_EXPLICIT; + if ((ret & X509_PCY_TREE_VALID) == 0) + return ret; + + /* If we get this far initialize the tree */ + if ((tree = OPENSSL_zalloc(sizeof(*tree))) == NULL) { + X509V3err(X509V3_F_TREE_INIT, ERR_R_MALLOC_FAILURE); + return X509_PCY_TREE_INTERNAL; + } + + /* Limit the growth of the tree to mitigate CVE-2023-0464 */ + tree->node_maximum = OPENSSL_POLICY_TREE_NODES_MAX; + + /* + * http://tools.ietf.org/html/rfc5280#section-6.1.2, figure 3. + * + * The top level is implicitly for the trust anchor with valid expected + * policies of anyPolicy. (RFC 5280 has the TA at depth 0 and the leaf at + * depth n, we have the leaf at depth 0 and the TA at depth n). + */ + if ((tree->levels = OPENSSL_zalloc(sizeof(*tree->levels)*(n+1))) == NULL) { + OPENSSL_free(tree); + X509V3err(X509V3_F_TREE_INIT, ERR_R_MALLOC_FAILURE); + return X509_PCY_TREE_INTERNAL; + } + tree->nlevel = n+1; + level = tree->levels; + if ((data = policy_data_new(NULL, OBJ_nid2obj(NID_any_policy), 0)) == NULL) + goto bad_tree; + if (level_add_node(level, data, NULL, tree, 1) == NULL) { + policy_data_free(data); + goto bad_tree; + } + + /* + * In this pass initialize all the tree levels and whether anyPolicy and + * policy mapping are inhibited at each level. + */ + for (i = n - 1; i >= 0; i--) { + X509 *x = sk_X509_value(certs, i); + uint32_t ex_flags = X509_get_extension_flags(x); + + /* Access the cache which we now know exists */ + cache = policy_cache_set(x); + + X509_up_ref(x); + (++level)->cert = x; + + if (!cache->anyPolicy) + level->flags |= X509_V_FLAG_INHIBIT_ANY; + + /* Determine inhibit any and inhibit map flags */ + if (any_skip == 0) { + /* + * Any matching allowed only if certificate is self issued and not + * the last in the chain. + */ + if (!(ex_flags & EXFLAG_SI) || (i == 0)) + level->flags |= X509_V_FLAG_INHIBIT_ANY; + } else { + if (!(ex_flags & EXFLAG_SI)) + any_skip--; + if ((cache->any_skip >= 0) && (cache->any_skip < any_skip)) + any_skip = cache->any_skip; + } + + if (map_skip == 0) + level->flags |= X509_V_FLAG_INHIBIT_MAP; + else { + if (!(ex_flags & EXFLAG_SI)) + map_skip--; + if ((cache->map_skip >= 0) && (cache->map_skip < map_skip)) + map_skip = cache->map_skip; + } + } + + *ptree = tree; + return ret; + + bad_tree: + X509_policy_tree_free(tree); + return X509_PCY_TREE_INTERNAL; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2023-0464/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2023-0464/vuln.c new file mode 100644 index 0000000..b6a6513 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2023-0464/vuln.c @@ -0,0 +1,163 @@ +/* Provenance: openssl/openssl tree_init (vuln). + * repo: openssl/openssl + * commit: 969327390220aee7515a4054d5189186402d6687 + * parent: 969327390220aee7515a4054d5189186402d6687 + * commit_url: https://github.com/openssl/openssl/commit/879f7080d7e141f415c79eaa3a8ac4a3dad0348b + * cve: CVE-2023-0464 + * license: Apache-2.0 + * function: tree_init + * relpath: crypto/x509v3/pcy_tree.c + */ + +static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs, + unsigned int flags) +{ + X509_POLICY_TREE *tree; + X509_POLICY_LEVEL *level; + const X509_POLICY_CACHE *cache; + X509_POLICY_DATA *data = NULL; + int ret = X509_PCY_TREE_VALID; + int n = sk_X509_num(certs) - 1; /* RFC5280 paths omit the TA */ + int explicit_policy = (flags & X509_V_FLAG_EXPLICIT_POLICY) ? 0 : n+1; + int any_skip = (flags & X509_V_FLAG_INHIBIT_ANY) ? 0 : n+1; + int map_skip = (flags & X509_V_FLAG_INHIBIT_MAP) ? 0 : n+1; + int i; + + *ptree = NULL; + + /* Can't do anything with just a trust anchor */ + if (n == 0) + return X509_PCY_TREE_EMPTY; + + /* + * First setup the policy cache in all n non-TA certificates, this will be + * used in X509_verify_cert() which will invoke the verify callback for all + * certificates with invalid policy extensions. + */ + for (i = n - 1; i >= 0; i--) { + X509 *x = sk_X509_value(certs, i); + + /* Call for side-effect of computing hash and caching extensions */ + X509_check_purpose(x, -1, 0); + + /* If cache is NULL, likely ENOMEM: return immediately */ + if (policy_cache_set(x) == NULL) + return X509_PCY_TREE_INTERNAL; + } + + /* + * At this point check for invalid policies and required explicit policy. + * Note that the explicit_policy counter is a count-down to zero, with the + * requirement kicking in if and once it does that. The counter is + * decremented for every non-self-issued certificate in the path, but may + * be further reduced by policy constraints in a non-leaf certificate. + * + * The ultimate policy set is the intersection of all the policies along + * the path, if we hit a certificate with an empty policy set, and explicit + * policy is required we're done. + */ + for (i = n - 1; + i >= 0 && (explicit_policy > 0 || (ret & X509_PCY_TREE_EMPTY) == 0); + i--) { + X509 *x = sk_X509_value(certs, i); + uint32_t ex_flags = X509_get_extension_flags(x); + + /* All the policies are already cached, we can return early */ + if (ex_flags & EXFLAG_INVALID_POLICY) + return X509_PCY_TREE_INVALID; + + /* Access the cache which we now know exists */ + cache = policy_cache_set(x); + + if ((ret & X509_PCY_TREE_VALID) && cache->data == NULL) + ret = X509_PCY_TREE_EMPTY; + if (explicit_policy > 0) { + if (!(ex_flags & EXFLAG_SI)) + explicit_policy--; + if ((cache->explicit_skip >= 0) + && (cache->explicit_skip < explicit_policy)) + explicit_policy = cache->explicit_skip; + } + } + + if (explicit_policy == 0) + ret |= X509_PCY_TREE_EXPLICIT; + if ((ret & X509_PCY_TREE_VALID) == 0) + return ret; + + /* If we get this far initialize the tree */ + if ((tree = OPENSSL_zalloc(sizeof(*tree))) == NULL) { + X509V3err(X509V3_F_TREE_INIT, ERR_R_MALLOC_FAILURE); + return X509_PCY_TREE_INTERNAL; + } + + /* + * http://tools.ietf.org/html/rfc5280#section-6.1.2, figure 3. + * + * The top level is implicitly for the trust anchor with valid expected + * policies of anyPolicy. (RFC 5280 has the TA at depth 0 and the leaf at + * depth n, we have the leaf at depth 0 and the TA at depth n). + */ + if ((tree->levels = OPENSSL_zalloc(sizeof(*tree->levels)*(n+1))) == NULL) { + OPENSSL_free(tree); + X509V3err(X509V3_F_TREE_INIT, ERR_R_MALLOC_FAILURE); + return X509_PCY_TREE_INTERNAL; + } + tree->nlevel = n+1; + level = tree->levels; + if ((data = policy_data_new(NULL, OBJ_nid2obj(NID_any_policy), 0)) == NULL) + goto bad_tree; + if (level_add_node(level, data, NULL, tree) == NULL) { + policy_data_free(data); + goto bad_tree; + } + + /* + * In this pass initialize all the tree levels and whether anyPolicy and + * policy mapping are inhibited at each level. + */ + for (i = n - 1; i >= 0; i--) { + X509 *x = sk_X509_value(certs, i); + uint32_t ex_flags = X509_get_extension_flags(x); + + /* Access the cache which we now know exists */ + cache = policy_cache_set(x); + + X509_up_ref(x); + (++level)->cert = x; + + if (!cache->anyPolicy) + level->flags |= X509_V_FLAG_INHIBIT_ANY; + + /* Determine inhibit any and inhibit map flags */ + if (any_skip == 0) { + /* + * Any matching allowed only if certificate is self issued and not + * the last in the chain. + */ + if (!(ex_flags & EXFLAG_SI) || (i == 0)) + level->flags |= X509_V_FLAG_INHIBIT_ANY; + } else { + if (!(ex_flags & EXFLAG_SI)) + any_skip--; + if ((cache->any_skip >= 0) && (cache->any_skip < any_skip)) + any_skip = cache->any_skip; + } + + if (map_skip == 0) + level->flags |= X509_V_FLAG_INHIBIT_MAP; + else { + if (!(ex_flags & EXFLAG_SI)) + map_skip--; + if ((cache->map_skip >= 0) && (cache->map_skip < map_skip)) + map_skip = cache->map_skip; + } + } + + *ptree = tree; + return ret; + + bad_tree: + X509_policy_tree_free(tree); + return X509_PCY_TREE_INTERNAL; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2023-0465/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2023-0465/fixed.c new file mode 100644 index 0000000..23db491 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2023-0465/fixed.c @@ -0,0 +1,90 @@ +/* Provenance: openssl/openssl check_policy (fixed). + * repo: openssl/openssl + * commit: b013765abfa80036dc779dd0e50602c57bb3bf95 + * parent: f675d164e5d9648c3537a0f5efe1cc2fd232b4a9 + * commit_url: https://github.com/openssl/openssl/commit/b013765abfa80036dc779dd0e50602c57bb3bf95 + * cve: CVE-2023-0465 + * license: Apache-2.0 + * function: check_policy + * relpath: crypto/x509/x509_vfy.c + */ + +static int check_policy(X509_STORE_CTX *ctx) +{ + int ret; + + if (ctx->parent) + return 1; + /* + * With DANE, the trust anchor might be a bare public key, not a + * certificate! In that case our chain does not have the trust anchor + * certificate as a top-most element. This comports well with RFC5280 + * chain verification, since there too, the trust anchor is not part of the + * chain to be verified. In particular, X509_policy_check() does not look + * at the TA cert, but assumes that it is present as the top-most chain + * element. We therefore temporarily push a NULL cert onto the chain if it + * was verified via a bare public key, and pop it off right after the + * X509_policy_check() call. + */ + if (ctx->bare_ta_signed && !sk_X509_push(ctx->chain, NULL)) { + X509err(X509_F_CHECK_POLICY, ERR_R_MALLOC_FAILURE); + ctx->error = X509_V_ERR_OUT_OF_MEM; + return 0; + } + ret = X509_policy_check(&ctx->tree, &ctx->explicit_policy, ctx->chain, + ctx->param->policies, ctx->param->flags); + if (ctx->bare_ta_signed) + sk_X509_pop(ctx->chain); + + if (ret == X509_PCY_TREE_INTERNAL) { + X509err(X509_F_CHECK_POLICY, ERR_R_MALLOC_FAILURE); + ctx->error = X509_V_ERR_OUT_OF_MEM; + return 0; + } + /* Invalid or inconsistent extensions */ + if (ret == X509_PCY_TREE_INVALID) { + int i, cbcalled = 0; + + /* Locate certificates with bad extensions and notify callback. */ + for (i = 0; i < sk_X509_num(ctx->chain); i++) { + X509 *x = sk_X509_value(ctx->chain, i); + + if (!(x->ex_flags & EXFLAG_INVALID_POLICY)) + continue; + cbcalled = 1; + if (!verify_cb_cert(ctx, x, i, + X509_V_ERR_INVALID_POLICY_EXTENSION)) + return 0; + } + if (!cbcalled) { + /* Should not be able to get here */ + X509err(X509_F_CHECK_POLICY, ERR_R_INTERNAL_ERROR); + return 0; + } + /* The callback ignored the error so we return success */ + return 1; + } + if (ret == X509_PCY_TREE_FAILURE) { + ctx->current_cert = NULL; + ctx->error = X509_V_ERR_NO_EXPLICIT_POLICY; + return ctx->verify_cb(0, ctx); + } + if (ret != X509_PCY_TREE_VALID) { + X509err(X509_F_CHECK_POLICY, ERR_R_INTERNAL_ERROR); + return 0; + } + + if (ctx->param->flags & X509_V_FLAG_NOTIFY_POLICY) { + ctx->current_cert = NULL; + /* + * Verification errors need to be "sticky", a callback may have allowed + * an SSL handshake to continue despite an error, and we must then + * remain in an error state. Therefore, we MUST NOT clear earlier + * verification errors by setting the error to X509_V_OK. + */ + if (!ctx->verify_cb(2, ctx)) + return 0; + } + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2023-0465/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2023-0465/vuln.c new file mode 100644 index 0000000..dae635f --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2023-0465/vuln.c @@ -0,0 +1,83 @@ +/* Provenance: openssl/openssl check_policy (vuln). + * repo: openssl/openssl + * commit: f675d164e5d9648c3537a0f5efe1cc2fd232b4a9 + * parent: f675d164e5d9648c3537a0f5efe1cc2fd232b4a9 + * commit_url: https://github.com/openssl/openssl/commit/b013765abfa80036dc779dd0e50602c57bb3bf95 + * cve: CVE-2023-0465 + * license: Apache-2.0 + * function: check_policy + * relpath: crypto/x509/x509_vfy.c + */ + +static int check_policy(X509_STORE_CTX *ctx) +{ + int ret; + + if (ctx->parent) + return 1; + /* + * With DANE, the trust anchor might be a bare public key, not a + * certificate! In that case our chain does not have the trust anchor + * certificate as a top-most element. This comports well with RFC5280 + * chain verification, since there too, the trust anchor is not part of the + * chain to be verified. In particular, X509_policy_check() does not look + * at the TA cert, but assumes that it is present as the top-most chain + * element. We therefore temporarily push a NULL cert onto the chain if it + * was verified via a bare public key, and pop it off right after the + * X509_policy_check() call. + */ + if (ctx->bare_ta_signed && !sk_X509_push(ctx->chain, NULL)) { + X509err(X509_F_CHECK_POLICY, ERR_R_MALLOC_FAILURE); + ctx->error = X509_V_ERR_OUT_OF_MEM; + return 0; + } + ret = X509_policy_check(&ctx->tree, &ctx->explicit_policy, ctx->chain, + ctx->param->policies, ctx->param->flags); + if (ctx->bare_ta_signed) + sk_X509_pop(ctx->chain); + + if (ret == X509_PCY_TREE_INTERNAL) { + X509err(X509_F_CHECK_POLICY, ERR_R_MALLOC_FAILURE); + ctx->error = X509_V_ERR_OUT_OF_MEM; + return 0; + } + /* Invalid or inconsistent extensions */ + if (ret == X509_PCY_TREE_INVALID) { + int i; + + /* Locate certificates with bad extensions and notify callback. */ + for (i = 1; i < sk_X509_num(ctx->chain); i++) { + X509 *x = sk_X509_value(ctx->chain, i); + + if (!(x->ex_flags & EXFLAG_INVALID_POLICY)) + continue; + if (!verify_cb_cert(ctx, x, i, + X509_V_ERR_INVALID_POLICY_EXTENSION)) + return 0; + } + return 1; + } + if (ret == X509_PCY_TREE_FAILURE) { + ctx->current_cert = NULL; + ctx->error = X509_V_ERR_NO_EXPLICIT_POLICY; + return ctx->verify_cb(0, ctx); + } + if (ret != X509_PCY_TREE_VALID) { + X509err(X509_F_CHECK_POLICY, ERR_R_INTERNAL_ERROR); + return 0; + } + + if (ctx->param->flags & X509_V_FLAG_NOTIFY_POLICY) { + ctx->current_cert = NULL; + /* + * Verification errors need to be "sticky", a callback may have allowed + * an SSL handshake to continue despite an error, and we must then + * remain in an error state. Therefore, we MUST NOT clear earlier + * verification errors by setting the error to X509_V_OK. + */ + if (!ctx->verify_cb(2, ctx)) + return 0; + } + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2023-2650/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2023-2650/fixed.c new file mode 100644 index 0000000..5d175fb --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2023-2650/fixed.c @@ -0,0 +1,166 @@ +/* Provenance: openssl/openssl OBJ_obj2txt (fixed). + * repo: openssl/openssl + * commit: d63b3e7959e79f98d60760a739f7876dc5adc838 + * parent: 3ca28c9e81fae36b0b44dc39beecd2b5a7561975 + * commit_url: https://github.com/openssl/openssl/commit/d63b3e7959e79f98d60760a739f7876dc5adc838 + * cve: CVE-2023-2650 + * license: Apache-2.0 + * function: OBJ_obj2txt + * relpath: crypto/objects/obj_dat.c + */ + +int OBJ_obj2txt(char *buf, int buf_len, const ASN1_OBJECT *a, int no_name) +{ + int i, n = 0, len, nid, first, use_bn; + BIGNUM *bl; + unsigned long l; + const unsigned char *p; + char tbuf[DECIMAL_SIZE(i) + DECIMAL_SIZE(l) + 2]; + const char *s; + + /* Ensure that, at every state, |buf| is NUL-terminated. */ + if (buf != NULL && buf_len > 0) + buf[0] = '\0'; + + if (a == NULL || a->data == NULL) + return 0; + + if (!no_name && (nid = OBJ_obj2nid(a)) != NID_undef) { + s = OBJ_nid2ln(nid); + if (s == NULL) + s = OBJ_nid2sn(nid); + if (s != NULL) { + if (buf != NULL) + OPENSSL_strlcpy(buf, s, buf_len); + return (int)strlen(s); + } + } + + len = a->length; + p = a->data; + + first = 1; + bl = NULL; + + /* + * RFC 2578 (STD 58) says this about OBJECT IDENTIFIERs: + * + * > 3.5. OBJECT IDENTIFIER values + * > + * > An OBJECT IDENTIFIER value is an ordered list of non-negative + * > numbers. For the SMIv2, each number in the list is referred to as a + * > sub-identifier, there are at most 128 sub-identifiers in a value, + * > and each sub-identifier has a maximum value of 2^32-1 (4294967295 + * > decimal). + * + * So a legitimate OID according to this RFC is at most (32 * 128 / 7), + * i.e. 586 bytes long. + * + * Ref: https://datatracker.ietf.org/doc/html/rfc2578#section-3.5 + */ + if (len > 586) + goto err; + + while (len > 0) { + l = 0; + use_bn = 0; + for (;;) { + unsigned char c = *p++; + + len--; + if (len == 0 && (c & 0x80) != 0) + goto err; + if (use_bn) { + if (!BN_add_word(bl, c & 0x7f)) + goto err; + } else { + l |= c & 0x7f; + } + if ((c & 0x80) == 0) + break; + if (!use_bn && l > (ULONG_MAX >> 7L)) { + if (bl == NULL && (bl = BN_new()) == NULL) + goto err; + if (!BN_set_word(bl, l)) + goto err; + use_bn = 1; + } + if (use_bn) { + if (!BN_lshift(bl, bl, 7)) + goto err; + } else { + l <<= 7L; + } + } + + if (first) { + first = 0; + if (l >= 80) { + i = 2; + if (use_bn) { + if (!BN_sub_word(bl, 80)) + goto err; + } else { + l -= 80; + } + } else { + i = (int)(l / 40); + l -= (long)(i * 40); + } + if (buf != NULL && buf_len > 1) { + *buf++ = i + '0'; + *buf = '\0'; + buf_len--; + } + n++; + } + + if (use_bn) { + char *bndec; + bndec = BN_bn2dec(bl); + if (!bndec) + goto err; + i = strlen(bndec); + if (buf != NULL) { + if (buf_len > 1) { + *buf++ = '.'; + *buf = '\0'; + buf_len--; + } + OPENSSL_strlcpy(buf, bndec, buf_len); + if (i > buf_len) { + buf += buf_len; + buf_len = 0; + } else { + buf += i; + buf_len -= i; + } + } + n++; + n += i; + OPENSSL_free(bndec); + } else { + BIO_snprintf(tbuf, sizeof(tbuf), ".%lu", l); + i = strlen(tbuf); + if (buf && buf_len > 0) { + OPENSSL_strlcpy(buf, tbuf, buf_len); + if (i > buf_len) { + buf += buf_len; + buf_len = 0; + } else { + buf += i; + buf_len -= i; + } + } + n += i; + l = 0; + } + } + + BN_free(bl); + return n; + + err: + BN_free(bl); + return -1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2023-2650/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2023-2650/vuln.c new file mode 100644 index 0000000..d9fe767 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2023-2650/vuln.c @@ -0,0 +1,147 @@ +/* Provenance: openssl/openssl OBJ_obj2txt (vuln). + * repo: openssl/openssl + * commit: 3ca28c9e81fae36b0b44dc39beecd2b5a7561975 + * parent: 3ca28c9e81fae36b0b44dc39beecd2b5a7561975 + * commit_url: https://github.com/openssl/openssl/commit/d63b3e7959e79f98d60760a739f7876dc5adc838 + * cve: CVE-2023-2650 + * license: Apache-2.0 + * function: OBJ_obj2txt + * relpath: crypto/objects/obj_dat.c + */ + +int OBJ_obj2txt(char *buf, int buf_len, const ASN1_OBJECT *a, int no_name) +{ + int i, n = 0, len, nid, first, use_bn; + BIGNUM *bl; + unsigned long l; + const unsigned char *p; + char tbuf[DECIMAL_SIZE(i) + DECIMAL_SIZE(l) + 2]; + const char *s; + + /* Ensure that, at every state, |buf| is NUL-terminated. */ + if (buf != NULL && buf_len > 0) + buf[0] = '\0'; + + if (a == NULL || a->data == NULL) + return 0; + + if (!no_name && (nid = OBJ_obj2nid(a)) != NID_undef) { + s = OBJ_nid2ln(nid); + if (s == NULL) + s = OBJ_nid2sn(nid); + if (s != NULL) { + if (buf != NULL) + OPENSSL_strlcpy(buf, s, buf_len); + return (int)strlen(s); + } + } + + len = a->length; + p = a->data; + + first = 1; + bl = NULL; + + while (len > 0) { + l = 0; + use_bn = 0; + for (;;) { + unsigned char c = *p++; + + len--; + if (len == 0 && (c & 0x80) != 0) + goto err; + if (use_bn) { + if (!BN_add_word(bl, c & 0x7f)) + goto err; + } else { + l |= c & 0x7f; + } + if ((c & 0x80) == 0) + break; + if (!use_bn && l > (ULONG_MAX >> 7L)) { + if (bl == NULL && (bl = BN_new()) == NULL) + goto err; + if (!BN_set_word(bl, l)) + goto err; + use_bn = 1; + } + if (use_bn) { + if (!BN_lshift(bl, bl, 7)) + goto err; + } else { + l <<= 7L; + } + } + + if (first) { + first = 0; + if (l >= 80) { + i = 2; + if (use_bn) { + if (!BN_sub_word(bl, 80)) + goto err; + } else { + l -= 80; + } + } else { + i = (int)(l / 40); + l -= (long)(i * 40); + } + if (buf != NULL && buf_len > 1) { + *buf++ = i + '0'; + *buf = '\0'; + buf_len--; + } + n++; + } + + if (use_bn) { + char *bndec; + bndec = BN_bn2dec(bl); + if (!bndec) + goto err; + i = strlen(bndec); + if (buf != NULL) { + if (buf_len > 1) { + *buf++ = '.'; + *buf = '\0'; + buf_len--; + } + OPENSSL_strlcpy(buf, bndec, buf_len); + if (i > buf_len) { + buf += buf_len; + buf_len = 0; + } else { + buf += i; + buf_len -= i; + } + } + n++; + n += i; + OPENSSL_free(bndec); + } else { + BIO_snprintf(tbuf, sizeof(tbuf), ".%lu", l); + i = strlen(tbuf); + if (buf && buf_len > 0) { + OPENSSL_strlcpy(buf, tbuf, buf_len); + if (i > buf_len) { + buf += buf_len; + buf_len = 0; + } else { + buf += i; + buf_len -= i; + } + } + n += i; + l = 0; + } + } + + BN_free(bl); + return n; + + err: + BN_free(bl); + return -1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2023-2975/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2023-2975/fixed.c new file mode 100644 index 0000000..c066979 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2023-2975/fixed.c @@ -0,0 +1,40 @@ +/* Provenance: openssl/openssl siv_cipher (fixed). + * repo: openssl/openssl + * commit: 00e2f5eea29994d19293ec4e8c8775ba73678598 + * parent: 175fa8469fc78f6cf35dfb87d26899e60e9ff1d4 + * commit_url: https://github.com/openssl/openssl/commit/00e2f5eea29994d19293ec4e8c8775ba73678598 + * cve: CVE-2023-2975 + * license: Apache-2.0 + * function: siv_cipher + * relpath: providers/implementations/ciphers/cipher_aes_siv.c + */ + +static int siv_cipher(void *vctx, unsigned char *out, size_t *outl, + size_t outsize, const unsigned char *in, size_t inl) +{ + PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx; + + if (!ossl_prov_is_running()) + return 0; + + /* Ignore just empty encryption/decryption call and not AAD. */ + if (out != NULL) { + if (inl == 0) { + if (outl != NULL) + *outl = 0; + return 1; + } + + if (outsize < inl) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + } + + if (ctx->hw->cipher(ctx, out, in, inl) <= 0) + return 0; + + if (outl != NULL) + *outl = inl; + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2023-2975/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2023-2975/vuln.c new file mode 100644 index 0000000..309bc41 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2023-2975/vuln.c @@ -0,0 +1,36 @@ +/* Provenance: openssl/openssl siv_cipher (vuln). + * repo: openssl/openssl + * commit: 175fa8469fc78f6cf35dfb87d26899e60e9ff1d4 + * parent: 175fa8469fc78f6cf35dfb87d26899e60e9ff1d4 + * commit_url: https://github.com/openssl/openssl/commit/00e2f5eea29994d19293ec4e8c8775ba73678598 + * cve: CVE-2023-2975 + * license: Apache-2.0 + * function: siv_cipher + * relpath: providers/implementations/ciphers/cipher_aes_siv.c + */ + +static int siv_cipher(void *vctx, unsigned char *out, size_t *outl, + size_t outsize, const unsigned char *in, size_t inl) +{ + PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx; + + if (!ossl_prov_is_running()) + return 0; + + if (inl == 0) { + *outl = 0; + return 1; + } + + if (outsize < inl) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + if (ctx->hw->cipher(ctx, out, in, inl) <= 0) + return 0; + + if (outl != NULL) + *outl = inl; + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2023-3446/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2023-3446/fixed.c new file mode 100644 index 0000000..9867500 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2023-3446/fixed.c @@ -0,0 +1,81 @@ +/* Provenance: openssl/openssl DH_check (fixed). + * repo: openssl/openssl + * commit: 8780a896543a654e757db1b9396383f9d8095528 + * parent: fe824ce0c5d51e7e7cf36c31db6c49c1c0c04a25 + * commit_url: https://github.com/openssl/openssl/commit/8780a896543a654e757db1b9396383f9d8095528 + * cve: CVE-2023-3446 + * license: Apache-2.0 + * function: DH_check + * relpath: crypto/dh/dh_check.c + */ + +int DH_check(const DH *dh, int *ret) +{ + int ok = 0, r; + BN_CTX *ctx = NULL; + BIGNUM *t1 = NULL, *t2 = NULL; + + /* Don't do any checks at all with an excessively large modulus */ + if (BN_num_bits(dh->p) > OPENSSL_DH_CHECK_MAX_MODULUS_BITS) { + DHerr(DH_F_DH_CHECK, DH_R_MODULUS_TOO_LARGE); + return 0; + } + + if (!DH_check_params(dh, ret)) + return 0; + + ctx = BN_CTX_new(); + if (ctx == NULL) + goto err; + BN_CTX_start(ctx); + t1 = BN_CTX_get(ctx); + t2 = BN_CTX_get(ctx); + if (t2 == NULL) + goto err; + + if (dh->q) { + if (BN_cmp(dh->g, BN_value_one()) <= 0) + *ret |= DH_NOT_SUITABLE_GENERATOR; + else if (BN_cmp(dh->g, dh->p) >= 0) + *ret |= DH_NOT_SUITABLE_GENERATOR; + else { + /* Check g^q == 1 mod p */ + if (!BN_mod_exp(t1, dh->g, dh->q, dh->p, ctx)) + goto err; + if (!BN_is_one(t1)) + *ret |= DH_NOT_SUITABLE_GENERATOR; + } + r = BN_is_prime_ex(dh->q, DH_NUMBER_ITERATIONS_FOR_PRIME, ctx, NULL); + if (r < 0) + goto err; + if (!r) + *ret |= DH_CHECK_Q_NOT_PRIME; + /* Check p == 1 mod q i.e. q divides p - 1 */ + if (!BN_div(t1, t2, dh->p, dh->q, ctx)) + goto err; + if (!BN_is_one(t2)) + *ret |= DH_CHECK_INVALID_Q_VALUE; + if (dh->j && BN_cmp(dh->j, t1)) + *ret |= DH_CHECK_INVALID_J_VALUE; + } + + r = BN_is_prime_ex(dh->p, DH_NUMBER_ITERATIONS_FOR_PRIME, ctx, NULL); + if (r < 0) + goto err; + if (!r) + *ret |= DH_CHECK_P_NOT_PRIME; + else if (!dh->q) { + if (!BN_rshift1(t1, dh->p)) + goto err; + r = BN_is_prime_ex(t1, DH_NUMBER_ITERATIONS_FOR_PRIME, ctx, NULL); + if (r < 0) + goto err; + if (!r) + *ret |= DH_CHECK_P_NOT_SAFE_PRIME; + } + ok = 1; + err: + BN_CTX_end(ctx); + BN_CTX_free(ctx); + return ok; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2023-3446/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2023-3446/vuln.c new file mode 100644 index 0000000..0809d55 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2023-3446/vuln.c @@ -0,0 +1,75 @@ +/* Provenance: openssl/openssl DH_check (vuln). + * repo: openssl/openssl + * commit: fe824ce0c5d51e7e7cf36c31db6c49c1c0c04a25 + * parent: fe824ce0c5d51e7e7cf36c31db6c49c1c0c04a25 + * commit_url: https://github.com/openssl/openssl/commit/8780a896543a654e757db1b9396383f9d8095528 + * cve: CVE-2023-3446 + * license: Apache-2.0 + * function: DH_check + * relpath: crypto/dh/dh_check.c + */ + +int DH_check(const DH *dh, int *ret) +{ + int ok = 0, r; + BN_CTX *ctx = NULL; + BIGNUM *t1 = NULL, *t2 = NULL; + + if (!DH_check_params(dh, ret)) + return 0; + + ctx = BN_CTX_new(); + if (ctx == NULL) + goto err; + BN_CTX_start(ctx); + t1 = BN_CTX_get(ctx); + t2 = BN_CTX_get(ctx); + if (t2 == NULL) + goto err; + + if (dh->q) { + if (BN_cmp(dh->g, BN_value_one()) <= 0) + *ret |= DH_NOT_SUITABLE_GENERATOR; + else if (BN_cmp(dh->g, dh->p) >= 0) + *ret |= DH_NOT_SUITABLE_GENERATOR; + else { + /* Check g^q == 1 mod p */ + if (!BN_mod_exp(t1, dh->g, dh->q, dh->p, ctx)) + goto err; + if (!BN_is_one(t1)) + *ret |= DH_NOT_SUITABLE_GENERATOR; + } + r = BN_is_prime_ex(dh->q, DH_NUMBER_ITERATIONS_FOR_PRIME, ctx, NULL); + if (r < 0) + goto err; + if (!r) + *ret |= DH_CHECK_Q_NOT_PRIME; + /* Check p == 1 mod q i.e. q divides p - 1 */ + if (!BN_div(t1, t2, dh->p, dh->q, ctx)) + goto err; + if (!BN_is_one(t2)) + *ret |= DH_CHECK_INVALID_Q_VALUE; + if (dh->j && BN_cmp(dh->j, t1)) + *ret |= DH_CHECK_INVALID_J_VALUE; + } + + r = BN_is_prime_ex(dh->p, DH_NUMBER_ITERATIONS_FOR_PRIME, ctx, NULL); + if (r < 0) + goto err; + if (!r) + *ret |= DH_CHECK_P_NOT_PRIME; + else if (!dh->q) { + if (!BN_rshift1(t1, dh->p)) + goto err; + r = BN_is_prime_ex(t1, DH_NUMBER_ITERATIONS_FOR_PRIME, ctx, NULL); + if (r < 0) + goto err; + if (!r) + *ret |= DH_CHECK_P_NOT_SAFE_PRIME; + } + ok = 1; + err: + BN_CTX_end(ctx); + BN_CTX_free(ctx); + return ok; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2023-3817-dh_check/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2023-3817-dh_check/fixed.c new file mode 100644 index 0000000..23c0e42 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2023-3817-dh_check/fixed.c @@ -0,0 +1,99 @@ +/* Provenance: openssl/openssl DH_check (fixed). + * repo: openssl/openssl + * commit: 9002fd07327a91f35ba6c1307e71fa6fd4409b7f + * parent: e648db50d9a63f71cab5cb78424c2932d019a744 + * commit_url: https://github.com/openssl/openssl/commit/9002fd07327a91f35ba6c1307e71fa6fd4409b7f + * cve: CVE-2023-3817 + * license: Apache-2.0 + * function: DH_check + * relpath: crypto/dh/dh_check.c + */ + +int DH_check(const DH *dh, int *ret) +{ +#ifdef FIPS_MODULE + return DH_check_params(dh, ret); +#else + int ok = 0, r, q_good = 0; + BN_CTX *ctx = NULL; + BIGNUM *t1 = NULL, *t2 = NULL; + int nid = DH_get_nid((DH *)dh); + + *ret = 0; + if (nid != NID_undef) + return 1; + + /* Don't do any checks at all with an excessively large modulus */ + if (BN_num_bits(dh->params.p) > OPENSSL_DH_CHECK_MAX_MODULUS_BITS) { + ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE); + *ret = DH_MODULUS_TOO_LARGE | DH_CHECK_P_NOT_PRIME; + return 0; + } + + if (!DH_check_params(dh, ret)) + return 0; + + ctx = BN_CTX_new_ex(dh->libctx); + if (ctx == NULL) + goto err; + BN_CTX_start(ctx); + t1 = BN_CTX_get(ctx); + t2 = BN_CTX_get(ctx); + if (t2 == NULL) + goto err; + + if (dh->params.q != NULL) { + if (BN_ucmp(dh->params.p, dh->params.q) > 0) + q_good = 1; + else + *ret |= DH_CHECK_INVALID_Q_VALUE; + } + + if (q_good) { + if (BN_cmp(dh->params.g, BN_value_one()) <= 0) + *ret |= DH_NOT_SUITABLE_GENERATOR; + else if (BN_cmp(dh->params.g, dh->params.p) >= 0) + *ret |= DH_NOT_SUITABLE_GENERATOR; + else { + /* Check g^q == 1 mod p */ + if (!BN_mod_exp(t1, dh->params.g, dh->params.q, dh->params.p, ctx)) + goto err; + if (!BN_is_one(t1)) + *ret |= DH_NOT_SUITABLE_GENERATOR; + } + r = BN_check_prime(dh->params.q, ctx, NULL); + if (r < 0) + goto err; + if (!r) + *ret |= DH_CHECK_Q_NOT_PRIME; + /* Check p == 1 mod q i.e. q divides p - 1 */ + if (!BN_div(t1, t2, dh->params.p, dh->params.q, ctx)) + goto err; + if (!BN_is_one(t2)) + *ret |= DH_CHECK_INVALID_Q_VALUE; + if (dh->params.j != NULL + && BN_cmp(dh->params.j, t1)) + *ret |= DH_CHECK_INVALID_J_VALUE; + } + + r = BN_check_prime(dh->params.p, ctx, NULL); + if (r < 0) + goto err; + if (!r) + *ret |= DH_CHECK_P_NOT_PRIME; + else if (dh->params.q == NULL) { + if (!BN_rshift1(t1, dh->params.p)) + goto err; + r = BN_check_prime(t1, ctx, NULL); + if (r < 0) + goto err; + if (!r) + *ret |= DH_CHECK_P_NOT_SAFE_PRIME; + } + ok = 1; + err: + BN_CTX_end(ctx); + BN_CTX_free(ctx); + return ok; +#endif /* FIPS_MODULE */ +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2023-3817-dh_check/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2023-3817-dh_check/vuln.c new file mode 100644 index 0000000..4e12537 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2023-3817-dh_check/vuln.c @@ -0,0 +1,92 @@ +/* Provenance: openssl/openssl DH_check (vuln). + * repo: openssl/openssl + * commit: e648db50d9a63f71cab5cb78424c2932d019a744 + * parent: e648db50d9a63f71cab5cb78424c2932d019a744 + * commit_url: https://github.com/openssl/openssl/commit/9002fd07327a91f35ba6c1307e71fa6fd4409b7f + * cve: CVE-2023-3817 + * license: Apache-2.0 + * function: DH_check + * relpath: crypto/dh/dh_check.c + */ + +int DH_check(const DH *dh, int *ret) +{ +#ifdef FIPS_MODULE + return DH_check_params(dh, ret); +#else + int ok = 0, r; + BN_CTX *ctx = NULL; + BIGNUM *t1 = NULL, *t2 = NULL; + int nid = DH_get_nid((DH *)dh); + + *ret = 0; + if (nid != NID_undef) + return 1; + + /* Don't do any checks at all with an excessively large modulus */ + if (BN_num_bits(dh->params.p) > OPENSSL_DH_CHECK_MAX_MODULUS_BITS) { + ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE); + *ret = DH_MODULUS_TOO_LARGE | DH_CHECK_P_NOT_PRIME; + return 0; + } + + if (!DH_check_params(dh, ret)) + return 0; + + ctx = BN_CTX_new_ex(dh->libctx); + if (ctx == NULL) + goto err; + BN_CTX_start(ctx); + t1 = BN_CTX_get(ctx); + t2 = BN_CTX_get(ctx); + if (t2 == NULL) + goto err; + + if (dh->params.q != NULL) { + if (BN_cmp(dh->params.g, BN_value_one()) <= 0) + *ret |= DH_NOT_SUITABLE_GENERATOR; + else if (BN_cmp(dh->params.g, dh->params.p) >= 0) + *ret |= DH_NOT_SUITABLE_GENERATOR; + else { + /* Check g^q == 1 mod p */ + if (!BN_mod_exp(t1, dh->params.g, dh->params.q, dh->params.p, ctx)) + goto err; + if (!BN_is_one(t1)) + *ret |= DH_NOT_SUITABLE_GENERATOR; + } + r = BN_check_prime(dh->params.q, ctx, NULL); + if (r < 0) + goto err; + if (!r) + *ret |= DH_CHECK_Q_NOT_PRIME; + /* Check p == 1 mod q i.e. q divides p - 1 */ + if (!BN_div(t1, t2, dh->params.p, dh->params.q, ctx)) + goto err; + if (!BN_is_one(t2)) + *ret |= DH_CHECK_INVALID_Q_VALUE; + if (dh->params.j != NULL + && BN_cmp(dh->params.j, t1)) + *ret |= DH_CHECK_INVALID_J_VALUE; + } + + r = BN_check_prime(dh->params.p, ctx, NULL); + if (r < 0) + goto err; + if (!r) + *ret |= DH_CHECK_P_NOT_PRIME; + else if (dh->params.q == NULL) { + if (!BN_rshift1(t1, dh->params.p)) + goto err; + r = BN_check_prime(t1, ctx, NULL); + if (r < 0) + goto err; + if (!r) + *ret |= DH_CHECK_P_NOT_SAFE_PRIME; + } + ok = 1; + err: + BN_CTX_end(ctx); + BN_CTX_free(ctx); + return ok; +#endif /* FIPS_MODULE */ +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2023-5363/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2023-5363/fixed.c new file mode 100644 index 0000000..8d6e1e0 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2023-5363/fixed.c @@ -0,0 +1,362 @@ +/* Provenance: openssl/openssl evp_cipher_init_internal (fixed). + * repo: openssl/openssl + * commit: 0df40630850fb2740e6be6890bb905d3fc623b2d + * parent: 23d21359e35536a4ee8f7be0b245ddbfac909bff + * commit_url: https://github.com/openssl/openssl/commit/0df40630850fb2740e6be6890bb905d3fc623b2d + * cve: CVE-2023-5363 + * license: Apache-2.0 + * function: evp_cipher_init_internal + * relpath: crypto/evp/evp_enc.c + */ + +static int evp_cipher_init_internal(EVP_CIPHER_CTX *ctx, + const EVP_CIPHER *cipher, + ENGINE *impl, const unsigned char *key, + const unsigned char *iv, int enc, + const OSSL_PARAM params[]) +{ + int n; +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + ENGINE *tmpimpl = NULL; +#endif + + ctx->iv_len = -1; + + /* + * enc == 1 means we are encrypting. + * enc == 0 means we are decrypting. + * enc == -1 means, use the previously initialised value for encrypt/decrypt + */ + if (enc == -1) { + enc = ctx->encrypt; + } else { + if (enc) + enc = 1; + ctx->encrypt = enc; + } + + if (cipher == NULL && ctx->cipher == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_NO_CIPHER_SET); + return 0; + } + + /* Code below to be removed when legacy support is dropped. */ + +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + /* + * Whether it's nice or not, "Inits" can be used on "Final"'d contexts so + * this context may already have an ENGINE! Try to avoid releasing the + * previous handle, re-querying for an ENGINE, and having a + * reinitialisation, when it may all be unnecessary. + */ + if (ctx->engine && ctx->cipher + && (cipher == NULL || cipher->nid == ctx->cipher->nid)) + goto skip_to_init; + + if (cipher != NULL && impl == NULL) { + /* Ask if an ENGINE is reserved for this job */ + tmpimpl = ENGINE_get_cipher_engine(cipher->nid); + } +#endif + + /* + * If there are engines involved then we should use legacy handling for now. + */ + if (ctx->engine != NULL +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + || tmpimpl != NULL +#endif + || impl != NULL + || (cipher != NULL && cipher->origin == EVP_ORIG_METH) + || (cipher == NULL && ctx->cipher != NULL + && ctx->cipher->origin == EVP_ORIG_METH)) { + if (ctx->cipher == ctx->fetched_cipher) + ctx->cipher = NULL; + EVP_CIPHER_free(ctx->fetched_cipher); + ctx->fetched_cipher = NULL; + goto legacy; + } + /* + * Ensure a context left lying around from last time is cleared + * (legacy code) + */ + if (cipher != NULL && ctx->cipher != NULL) { + if (ctx->cipher->cleanup != NULL && !ctx->cipher->cleanup(ctx)) + return 0; + OPENSSL_clear_free(ctx->cipher_data, ctx->cipher->ctx_size); + ctx->cipher_data = NULL; + } + + /* Start of non-legacy code below */ + + /* Ensure a context left lying around from last time is cleared */ + if (cipher != NULL && ctx->cipher != NULL) { + unsigned long flags = ctx->flags; + + EVP_CIPHER_CTX_reset(ctx); + /* Restore encrypt and flags */ + ctx->encrypt = enc; + ctx->flags = flags; + } + + if (cipher == NULL) + cipher = ctx->cipher; + + if (cipher->prov == NULL) { +#ifdef FIPS_MODULE + /* We only do explicit fetches inside the FIPS module */ + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; +#else + EVP_CIPHER *provciph = + EVP_CIPHER_fetch(NULL, + cipher->nid == NID_undef ? "NULL" + : OBJ_nid2sn(cipher->nid), + ""); + + if (provciph == NULL) + return 0; + cipher = provciph; + EVP_CIPHER_free(ctx->fetched_cipher); + ctx->fetched_cipher = provciph; +#endif + } + + if (!ossl_assert(cipher->prov != NULL)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + + if (cipher != ctx->fetched_cipher) { + if (!EVP_CIPHER_up_ref((EVP_CIPHER *)cipher)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + EVP_CIPHER_free(ctx->fetched_cipher); + ctx->fetched_cipher = (EVP_CIPHER *)cipher; + } + ctx->cipher = cipher; + if (ctx->algctx == NULL) { + ctx->algctx = ctx->cipher->newctx(ossl_provider_ctx(cipher->prov)); + if (ctx->algctx == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + } + + if ((ctx->flags & EVP_CIPH_NO_PADDING) != 0) { + /* + * If this ctx was already set up for no padding then we need to tell + * the new cipher about it. + */ + if (!EVP_CIPHER_CTX_set_padding(ctx, 0)) + return 0; + } + +#ifndef FIPS_MODULE + /* + * Fix for CVE-2023-5363 + * Passing in a size as part of the init call takes effect late + * so, force such to occur before the initialisation. + * + * The FIPS provider's internal library context is used in a manner + * such that this is not an issue. + */ + if (params != NULL) { + OSSL_PARAM param_lens[3] = { OSSL_PARAM_END, OSSL_PARAM_END, + OSSL_PARAM_END }; + OSSL_PARAM *q = param_lens; + const OSSL_PARAM *p; + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL) + memcpy(q++, p, sizeof(*q)); + + /* + * Note that OSSL_CIPHER_PARAM_AEAD_IVLEN is a synomym for + * OSSL_CIPHER_PARAM_IVLEN so both are covered here. + */ + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_IVLEN); + if (p != NULL) + memcpy(q++, p, sizeof(*q)); + + if (q != param_lens) { + if (!EVP_CIPHER_CTX_set_params(ctx, param_lens)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_LENGTH); + return 0; + } + } + } +#endif + + if (enc) { + if (ctx->cipher->einit == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + + return ctx->cipher->einit(ctx->algctx, + key, + key == NULL ? 0 + : EVP_CIPHER_CTX_get_key_length(ctx), + iv, + iv == NULL ? 0 + : EVP_CIPHER_CTX_get_iv_length(ctx), + params); + } + + if (ctx->cipher->dinit == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + + return ctx->cipher->dinit(ctx->algctx, + key, + key == NULL ? 0 + : EVP_CIPHER_CTX_get_key_length(ctx), + iv, + iv == NULL ? 0 + : EVP_CIPHER_CTX_get_iv_length(ctx), + params); + + /* Code below to be removed when legacy support is dropped. */ + legacy: + + if (cipher != NULL) { + /* + * Ensure a context left lying around from last time is cleared (we + * previously attempted to avoid this if the same ENGINE and + * EVP_CIPHER could be used). + */ + if (ctx->cipher) { + unsigned long flags = ctx->flags; + EVP_CIPHER_CTX_reset(ctx); + /* Restore encrypt and flags */ + ctx->encrypt = enc; + ctx->flags = flags; + } +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + if (impl != NULL) { + if (!ENGINE_init(impl)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + } else { + impl = tmpimpl; + } + if (impl != NULL) { + /* There's an ENGINE for this job ... (apparently) */ + const EVP_CIPHER *c = ENGINE_get_cipher(impl, cipher->nid); + + if (c == NULL) { + /* + * One positive side-effect of US's export control history, + * is that we should at least be able to avoid using US + * misspellings of "initialisation"? + */ + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + /* We'll use the ENGINE's private cipher definition */ + cipher = c; + /* + * Store the ENGINE functional reference so we know 'cipher' came + * from an ENGINE and we need to release it when done. + */ + ctx->engine = impl; + } else { + ctx->engine = NULL; + } +#endif + + ctx->cipher = cipher; + if (ctx->cipher->ctx_size) { + ctx->cipher_data = OPENSSL_zalloc(ctx->cipher->ctx_size); + if (ctx->cipher_data == NULL) { + ctx->cipher = NULL; + ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); + return 0; + } + } else { + ctx->cipher_data = NULL; + } + ctx->key_len = cipher->key_len; + /* Preserve wrap enable flag, zero everything else */ + ctx->flags &= EVP_CIPHER_CTX_FLAG_WRAP_ALLOW; + if (ctx->cipher->flags & EVP_CIPH_CTRL_INIT) { + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_INIT, 0, NULL) <= 0) { + ctx->cipher = NULL; + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + } + } +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + skip_to_init: +#endif + if (ctx->cipher == NULL) + return 0; + + /* we assume block size is a power of 2 in *cryptUpdate */ + OPENSSL_assert(ctx->cipher->block_size == 1 + || ctx->cipher->block_size == 8 + || ctx->cipher->block_size == 16); + + if (!(ctx->flags & EVP_CIPHER_CTX_FLAG_WRAP_ALLOW) + && EVP_CIPHER_CTX_get_mode(ctx) == EVP_CIPH_WRAP_MODE) { + ERR_raise(ERR_LIB_EVP, EVP_R_WRAP_MODE_NOT_ALLOWED); + return 0; + } + + if ((EVP_CIPHER_get_flags(EVP_CIPHER_CTX_get0_cipher(ctx)) + & EVP_CIPH_CUSTOM_IV) == 0) { + switch (EVP_CIPHER_CTX_get_mode(ctx)) { + + case EVP_CIPH_STREAM_CIPHER: + case EVP_CIPH_ECB_MODE: + break; + + case EVP_CIPH_CFB_MODE: + case EVP_CIPH_OFB_MODE: + + ctx->num = 0; + /* fall-through */ + + case EVP_CIPH_CBC_MODE: + n = EVP_CIPHER_CTX_get_iv_length(ctx); + if (n < 0 || n > (int)sizeof(ctx->iv)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_IV_LENGTH); + return 0; + } + if (iv != NULL) + memcpy(ctx->oiv, iv, n); + memcpy(ctx->iv, ctx->oiv, n); + break; + + case EVP_CIPH_CTR_MODE: + ctx->num = 0; + /* Don't reuse IV for CTR mode */ + if (iv != NULL) { + n = EVP_CIPHER_CTX_get_iv_length(ctx); + if (n <= 0 || n > (int)sizeof(ctx->iv)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_IV_LENGTH); + return 0; + } + memcpy(ctx->iv, iv, n); + } + break; + + default: + return 0; + } + } + + if (key != NULL || (ctx->cipher->flags & EVP_CIPH_ALWAYS_CALL_INIT)) { + if (!ctx->cipher->init(ctx, key, iv, enc)) + return 0; + } + ctx->buf_len = 0; + ctx->final_used = 0; + ctx->block_mask = ctx->cipher->block_size - 1; + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2023-5363/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2023-5363/vuln.c new file mode 100644 index 0000000..6b8bbd0 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2023-5363/vuln.c @@ -0,0 +1,326 @@ +/* Provenance: openssl/openssl evp_cipher_init_internal (vuln). + * repo: openssl/openssl + * commit: 23d21359e35536a4ee8f7be0b245ddbfac909bff + * parent: 23d21359e35536a4ee8f7be0b245ddbfac909bff + * commit_url: https://github.com/openssl/openssl/commit/0df40630850fb2740e6be6890bb905d3fc623b2d + * cve: CVE-2023-5363 + * license: Apache-2.0 + * function: evp_cipher_init_internal + * relpath: crypto/evp/evp_enc.c + */ + +static int evp_cipher_init_internal(EVP_CIPHER_CTX *ctx, + const EVP_CIPHER *cipher, + ENGINE *impl, const unsigned char *key, + const unsigned char *iv, int enc, + const OSSL_PARAM params[]) +{ + int n; +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + ENGINE *tmpimpl = NULL; +#endif + + ctx->iv_len = -1; + + /* + * enc == 1 means we are encrypting. + * enc == 0 means we are decrypting. + * enc == -1 means, use the previously initialised value for encrypt/decrypt + */ + if (enc == -1) { + enc = ctx->encrypt; + } else { + if (enc) + enc = 1; + ctx->encrypt = enc; + } + + if (cipher == NULL && ctx->cipher == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_NO_CIPHER_SET); + return 0; + } + + /* Code below to be removed when legacy support is dropped. */ + +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + /* + * Whether it's nice or not, "Inits" can be used on "Final"'d contexts so + * this context may already have an ENGINE! Try to avoid releasing the + * previous handle, re-querying for an ENGINE, and having a + * reinitialisation, when it may all be unnecessary. + */ + if (ctx->engine && ctx->cipher + && (cipher == NULL || cipher->nid == ctx->cipher->nid)) + goto skip_to_init; + + if (cipher != NULL && impl == NULL) { + /* Ask if an ENGINE is reserved for this job */ + tmpimpl = ENGINE_get_cipher_engine(cipher->nid); + } +#endif + + /* + * If there are engines involved then we should use legacy handling for now. + */ + if (ctx->engine != NULL +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + || tmpimpl != NULL +#endif + || impl != NULL + || (cipher != NULL && cipher->origin == EVP_ORIG_METH) + || (cipher == NULL && ctx->cipher != NULL + && ctx->cipher->origin == EVP_ORIG_METH)) { + if (ctx->cipher == ctx->fetched_cipher) + ctx->cipher = NULL; + EVP_CIPHER_free(ctx->fetched_cipher); + ctx->fetched_cipher = NULL; + goto legacy; + } + /* + * Ensure a context left lying around from last time is cleared + * (legacy code) + */ + if (cipher != NULL && ctx->cipher != NULL) { + if (ctx->cipher->cleanup != NULL && !ctx->cipher->cleanup(ctx)) + return 0; + OPENSSL_clear_free(ctx->cipher_data, ctx->cipher->ctx_size); + ctx->cipher_data = NULL; + } + + /* Start of non-legacy code below */ + + /* Ensure a context left lying around from last time is cleared */ + if (cipher != NULL && ctx->cipher != NULL) { + unsigned long flags = ctx->flags; + + EVP_CIPHER_CTX_reset(ctx); + /* Restore encrypt and flags */ + ctx->encrypt = enc; + ctx->flags = flags; + } + + if (cipher == NULL) + cipher = ctx->cipher; + + if (cipher->prov == NULL) { +#ifdef FIPS_MODULE + /* We only do explicit fetches inside the FIPS module */ + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; +#else + EVP_CIPHER *provciph = + EVP_CIPHER_fetch(NULL, + cipher->nid == NID_undef ? "NULL" + : OBJ_nid2sn(cipher->nid), + ""); + + if (provciph == NULL) + return 0; + cipher = provciph; + EVP_CIPHER_free(ctx->fetched_cipher); + ctx->fetched_cipher = provciph; +#endif + } + + if (!ossl_assert(cipher->prov != NULL)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + + if (cipher != ctx->fetched_cipher) { + if (!EVP_CIPHER_up_ref((EVP_CIPHER *)cipher)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + EVP_CIPHER_free(ctx->fetched_cipher); + ctx->fetched_cipher = (EVP_CIPHER *)cipher; + } + ctx->cipher = cipher; + if (ctx->algctx == NULL) { + ctx->algctx = ctx->cipher->newctx(ossl_provider_ctx(cipher->prov)); + if (ctx->algctx == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + } + + if ((ctx->flags & EVP_CIPH_NO_PADDING) != 0) { + /* + * If this ctx was already set up for no padding then we need to tell + * the new cipher about it. + */ + if (!EVP_CIPHER_CTX_set_padding(ctx, 0)) + return 0; + } + + if (enc) { + if (ctx->cipher->einit == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + + return ctx->cipher->einit(ctx->algctx, + key, + key == NULL ? 0 + : EVP_CIPHER_CTX_get_key_length(ctx), + iv, + iv == NULL ? 0 + : EVP_CIPHER_CTX_get_iv_length(ctx), + params); + } + + if (ctx->cipher->dinit == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + + return ctx->cipher->dinit(ctx->algctx, + key, + key == NULL ? 0 + : EVP_CIPHER_CTX_get_key_length(ctx), + iv, + iv == NULL ? 0 + : EVP_CIPHER_CTX_get_iv_length(ctx), + params); + + /* Code below to be removed when legacy support is dropped. */ + legacy: + + if (cipher != NULL) { + /* + * Ensure a context left lying around from last time is cleared (we + * previously attempted to avoid this if the same ENGINE and + * EVP_CIPHER could be used). + */ + if (ctx->cipher) { + unsigned long flags = ctx->flags; + EVP_CIPHER_CTX_reset(ctx); + /* Restore encrypt and flags */ + ctx->encrypt = enc; + ctx->flags = flags; + } +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + if (impl != NULL) { + if (!ENGINE_init(impl)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + } else { + impl = tmpimpl; + } + if (impl != NULL) { + /* There's an ENGINE for this job ... (apparently) */ + const EVP_CIPHER *c = ENGINE_get_cipher(impl, cipher->nid); + + if (c == NULL) { + /* + * One positive side-effect of US's export control history, + * is that we should at least be able to avoid using US + * misspellings of "initialisation"? + */ + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + /* We'll use the ENGINE's private cipher definition */ + cipher = c; + /* + * Store the ENGINE functional reference so we know 'cipher' came + * from an ENGINE and we need to release it when done. + */ + ctx->engine = impl; + } else { + ctx->engine = NULL; + } +#endif + + ctx->cipher = cipher; + if (ctx->cipher->ctx_size) { + ctx->cipher_data = OPENSSL_zalloc(ctx->cipher->ctx_size); + if (ctx->cipher_data == NULL) { + ctx->cipher = NULL; + ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); + return 0; + } + } else { + ctx->cipher_data = NULL; + } + ctx->key_len = cipher->key_len; + /* Preserve wrap enable flag, zero everything else */ + ctx->flags &= EVP_CIPHER_CTX_FLAG_WRAP_ALLOW; + if (ctx->cipher->flags & EVP_CIPH_CTRL_INIT) { + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_INIT, 0, NULL) <= 0) { + ctx->cipher = NULL; + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + return 0; + } + } + } +#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) + skip_to_init: +#endif + if (ctx->cipher == NULL) + return 0; + + /* we assume block size is a power of 2 in *cryptUpdate */ + OPENSSL_assert(ctx->cipher->block_size == 1 + || ctx->cipher->block_size == 8 + || ctx->cipher->block_size == 16); + + if (!(ctx->flags & EVP_CIPHER_CTX_FLAG_WRAP_ALLOW) + && EVP_CIPHER_CTX_get_mode(ctx) == EVP_CIPH_WRAP_MODE) { + ERR_raise(ERR_LIB_EVP, EVP_R_WRAP_MODE_NOT_ALLOWED); + return 0; + } + + if ((EVP_CIPHER_get_flags(EVP_CIPHER_CTX_get0_cipher(ctx)) + & EVP_CIPH_CUSTOM_IV) == 0) { + switch (EVP_CIPHER_CTX_get_mode(ctx)) { + + case EVP_CIPH_STREAM_CIPHER: + case EVP_CIPH_ECB_MODE: + break; + + case EVP_CIPH_CFB_MODE: + case EVP_CIPH_OFB_MODE: + + ctx->num = 0; + /* fall-through */ + + case EVP_CIPH_CBC_MODE: + n = EVP_CIPHER_CTX_get_iv_length(ctx); + if (n < 0 || n > (int)sizeof(ctx->iv)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_IV_LENGTH); + return 0; + } + if (iv != NULL) + memcpy(ctx->oiv, iv, n); + memcpy(ctx->iv, ctx->oiv, n); + break; + + case EVP_CIPH_CTR_MODE: + ctx->num = 0; + /* Don't reuse IV for CTR mode */ + if (iv != NULL) { + n = EVP_CIPHER_CTX_get_iv_length(ctx); + if (n <= 0 || n > (int)sizeof(ctx->iv)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_IV_LENGTH); + return 0; + } + memcpy(ctx->iv, iv, n); + } + break; + + default: + return 0; + } + } + + if (key != NULL || (ctx->cipher->flags & EVP_CIPH_ALWAYS_CALL_INIT)) { + if (!ctx->cipher->init(ctx, key, iv, enc)) + return 0; + } + ctx->buf_len = 0; + ctx->final_used = 0; + ctx->block_mask = ctx->cipher->block_size - 1; + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-0727-smime_write_pkcs7/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2024-0727-smime_write_pkcs7/fixed.c new file mode 100644 index 0000000..aaf0707 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-0727-smime_write_pkcs7/fixed.c @@ -0,0 +1,32 @@ +/* Provenance: openssl/openssl SMIME_write_PKCS7 (fixed). + * repo: openssl/openssl + * commit: 09df4395b5071217b76dc7d3d2e630eb8c5a79c2 + * parent: 6c70934a46eaa1734c2efbe9d7baac51c607062e + * commit_url: https://github.com/openssl/openssl/commit/09df4395b5071217b76dc7d3d2e630eb8c5a79c2 + * cve: CVE-2024-0727 + * license: Apache-2.0 + * function: SMIME_write_PKCS7 + * relpath: crypto/pkcs7/pk7_mime.c + */ + +int SMIME_write_PKCS7(BIO *bio, PKCS7 *p7, BIO *data, int flags) +{ + STACK_OF(X509_ALGOR) *mdalgs; + int ctype_nid = OBJ_obj2nid(p7->type); + const PKCS7_CTX *ctx = ossl_pkcs7_get0_ctx(p7); + + if (ctype_nid == NID_pkcs7_signed) { + if (p7->d.sign == NULL) + return 0; + mdalgs = p7->d.sign->md_algs; + } else { + mdalgs = NULL; + } + + flags ^= SMIME_OLDMIME; + + return SMIME_write_ASN1_ex(bio, (ASN1_VALUE *)p7, data, flags, ctype_nid, + NID_undef, mdalgs, ASN1_ITEM_rptr(PKCS7), + ossl_pkcs7_ctx_get0_libctx(ctx), + ossl_pkcs7_ctx_get0_propq(ctx)); +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-0727-smime_write_pkcs7/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2024-0727-smime_write_pkcs7/vuln.c new file mode 100644 index 0000000..f6cfff1 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-0727-smime_write_pkcs7/vuln.c @@ -0,0 +1,29 @@ +/* Provenance: openssl/openssl SMIME_write_PKCS7 (vuln). + * repo: openssl/openssl + * commit: 6c70934a46eaa1734c2efbe9d7baac51c607062e + * parent: 6c70934a46eaa1734c2efbe9d7baac51c607062e + * commit_url: https://github.com/openssl/openssl/commit/09df4395b5071217b76dc7d3d2e630eb8c5a79c2 + * cve: CVE-2024-0727 + * license: Apache-2.0 + * function: SMIME_write_PKCS7 + * relpath: crypto/pkcs7/pk7_mime.c + */ + +int SMIME_write_PKCS7(BIO *bio, PKCS7 *p7, BIO *data, int flags) +{ + STACK_OF(X509_ALGOR) *mdalgs; + int ctype_nid = OBJ_obj2nid(p7->type); + const PKCS7_CTX *ctx = ossl_pkcs7_get0_ctx(p7); + + if (ctype_nid == NID_pkcs7_signed) + mdalgs = p7->d.sign->md_algs; + else + mdalgs = NULL; + + flags ^= SMIME_OLDMIME; + + return SMIME_write_ASN1_ex(bio, (ASN1_VALUE *)p7, data, flags, ctype_nid, + NID_undef, mdalgs, ASN1_ITEM_rptr(PKCS7), + ossl_pkcs7_ctx_get0_libctx(ctx), + ossl_pkcs7_ctx_get0_propq(ctx)); +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-0727/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2024-0727/fixed.c new file mode 100644 index 0000000..4f2376b --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-0727/fixed.c @@ -0,0 +1,112 @@ +/* Provenance: openssl/openssl pkcs12_gen_mac (fixed). + * repo: openssl/openssl + * commit: 09df4395b5071217b76dc7d3d2e630eb8c5a79c2 + * parent: 6c70934a46eaa1734c2efbe9d7baac51c607062e + * commit_url: https://github.com/openssl/openssl/commit/09df4395b5071217b76dc7d3d2e630eb8c5a79c2 + * cve: CVE-2024-0727 + * license: Apache-2.0 + * function: pkcs12_gen_mac + * relpath: crypto/pkcs12/p12_mutl.c + */ + +static int pkcs12_gen_mac(PKCS12 *p12, const char *pass, int passlen, + unsigned char *mac, unsigned int *maclen, + int (*pkcs12_key_gen)(const char *pass, int passlen, + unsigned char *salt, int slen, + int id, int iter, int n, + unsigned char *out, + const EVP_MD *md_type)) +{ + int ret = 0; + const EVP_MD *md; + EVP_MD *md_fetch; + HMAC_CTX *hmac = NULL; + unsigned char key[EVP_MAX_MD_SIZE], *salt; + int saltlen, iter; + char md_name[80]; + int md_size = 0; + int md_nid; + const X509_ALGOR *macalg; + const ASN1_OBJECT *macoid; + + if (!PKCS7_type_is_data(p12->authsafes)) { + ERR_raise(ERR_LIB_PKCS12, PKCS12_R_CONTENT_TYPE_NOT_DATA); + return 0; + } + + if (p12->authsafes->d.data == NULL) { + ERR_raise(ERR_LIB_PKCS12, PKCS12_R_DECODE_ERROR); + return 0; + } + + salt = p12->mac->salt->data; + saltlen = p12->mac->salt->length; + if (p12->mac->iter == NULL) + iter = 1; + else + iter = ASN1_INTEGER_get(p12->mac->iter); + X509_SIG_get0(p12->mac->dinfo, &macalg, NULL); + X509_ALGOR_get0(&macoid, NULL, NULL, macalg); + if (OBJ_obj2txt(md_name, sizeof(md_name), macoid, 0) < 0) + return 0; + + (void)ERR_set_mark(); + md = md_fetch = EVP_MD_fetch(p12->authsafes->ctx.libctx, md_name, + p12->authsafes->ctx.propq); + if (md == NULL) + md = EVP_get_digestbynid(OBJ_obj2nid(macoid)); + + if (md == NULL) { + (void)ERR_clear_last_mark(); + ERR_raise(ERR_LIB_PKCS12, PKCS12_R_UNKNOWN_DIGEST_ALGORITHM); + return 0; + } + (void)ERR_pop_to_mark(); + + md_size = EVP_MD_get_size(md); + md_nid = EVP_MD_get_type(md); + if (md_size < 0) + goto err; + if ((md_nid == NID_id_GostR3411_94 + || md_nid == NID_id_GostR3411_2012_256 + || md_nid == NID_id_GostR3411_2012_512) + && ossl_safe_getenv("LEGACY_GOST_PKCS12") == NULL) { + md_size = TK26_MAC_KEY_LEN; + if (!pkcs12_gen_gost_mac_key(pass, passlen, salt, saltlen, iter, + md_size, key, md)) { + ERR_raise(ERR_LIB_PKCS12, PKCS12_R_KEY_GEN_ERROR); + goto err; + } + } else { + if (pkcs12_key_gen != NULL) { + if (!(*pkcs12_key_gen)(pass, passlen, salt, saltlen, PKCS12_MAC_ID, + iter, md_size, key, md)) { + ERR_raise(ERR_LIB_PKCS12, PKCS12_R_KEY_GEN_ERROR); + goto err; + } + } else { + /* Default to UTF-8 password */ + if (!PKCS12_key_gen_utf8_ex(pass, passlen, salt, saltlen, PKCS12_MAC_ID, + iter, md_size, key, md, + p12->authsafes->ctx.libctx, + p12->authsafes->ctx.propq)) { + ERR_raise(ERR_LIB_PKCS12, PKCS12_R_KEY_GEN_ERROR); + goto err; + } + } + } + if ((hmac = HMAC_CTX_new()) == NULL + || !HMAC_Init_ex(hmac, key, md_size, md, NULL) + || !HMAC_Update(hmac, p12->authsafes->d.data->data, + p12->authsafes->d.data->length) + || !HMAC_Final(hmac, mac, maclen)) { + goto err; + } + ret = 1; + +err: + OPENSSL_cleanse(key, sizeof(key)); + HMAC_CTX_free(hmac); + EVP_MD_free(md_fetch); + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-0727/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2024-0727/vuln.c new file mode 100644 index 0000000..19ef824 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-0727/vuln.c @@ -0,0 +1,107 @@ +/* Provenance: openssl/openssl pkcs12_gen_mac (vuln). + * repo: openssl/openssl + * commit: 6c70934a46eaa1734c2efbe9d7baac51c607062e + * parent: 6c70934a46eaa1734c2efbe9d7baac51c607062e + * commit_url: https://github.com/openssl/openssl/commit/09df4395b5071217b76dc7d3d2e630eb8c5a79c2 + * cve: CVE-2024-0727 + * license: Apache-2.0 + * function: pkcs12_gen_mac + * relpath: crypto/pkcs12/p12_mutl.c + */ + +static int pkcs12_gen_mac(PKCS12 *p12, const char *pass, int passlen, + unsigned char *mac, unsigned int *maclen, + int (*pkcs12_key_gen)(const char *pass, int passlen, + unsigned char *salt, int slen, + int id, int iter, int n, + unsigned char *out, + const EVP_MD *md_type)) +{ + int ret = 0; + const EVP_MD *md; + EVP_MD *md_fetch; + HMAC_CTX *hmac = NULL; + unsigned char key[EVP_MAX_MD_SIZE], *salt; + int saltlen, iter; + char md_name[80]; + int md_size = 0; + int md_nid; + const X509_ALGOR *macalg; + const ASN1_OBJECT *macoid; + + if (!PKCS7_type_is_data(p12->authsafes)) { + ERR_raise(ERR_LIB_PKCS12, PKCS12_R_CONTENT_TYPE_NOT_DATA); + return 0; + } + + salt = p12->mac->salt->data; + saltlen = p12->mac->salt->length; + if (p12->mac->iter == NULL) + iter = 1; + else + iter = ASN1_INTEGER_get(p12->mac->iter); + X509_SIG_get0(p12->mac->dinfo, &macalg, NULL); + X509_ALGOR_get0(&macoid, NULL, NULL, macalg); + if (OBJ_obj2txt(md_name, sizeof(md_name), macoid, 0) < 0) + return 0; + + (void)ERR_set_mark(); + md = md_fetch = EVP_MD_fetch(p12->authsafes->ctx.libctx, md_name, + p12->authsafes->ctx.propq); + if (md == NULL) + md = EVP_get_digestbynid(OBJ_obj2nid(macoid)); + + if (md == NULL) { + (void)ERR_clear_last_mark(); + ERR_raise(ERR_LIB_PKCS12, PKCS12_R_UNKNOWN_DIGEST_ALGORITHM); + return 0; + } + (void)ERR_pop_to_mark(); + + md_size = EVP_MD_get_size(md); + md_nid = EVP_MD_get_type(md); + if (md_size < 0) + goto err; + if ((md_nid == NID_id_GostR3411_94 + || md_nid == NID_id_GostR3411_2012_256 + || md_nid == NID_id_GostR3411_2012_512) + && ossl_safe_getenv("LEGACY_GOST_PKCS12") == NULL) { + md_size = TK26_MAC_KEY_LEN; + if (!pkcs12_gen_gost_mac_key(pass, passlen, salt, saltlen, iter, + md_size, key, md)) { + ERR_raise(ERR_LIB_PKCS12, PKCS12_R_KEY_GEN_ERROR); + goto err; + } + } else { + if (pkcs12_key_gen != NULL) { + if (!(*pkcs12_key_gen)(pass, passlen, salt, saltlen, PKCS12_MAC_ID, + iter, md_size, key, md)) { + ERR_raise(ERR_LIB_PKCS12, PKCS12_R_KEY_GEN_ERROR); + goto err; + } + } else { + /* Default to UTF-8 password */ + if (!PKCS12_key_gen_utf8_ex(pass, passlen, salt, saltlen, PKCS12_MAC_ID, + iter, md_size, key, md, + p12->authsafes->ctx.libctx, + p12->authsafes->ctx.propq)) { + ERR_raise(ERR_LIB_PKCS12, PKCS12_R_KEY_GEN_ERROR); + goto err; + } + } + } + if ((hmac = HMAC_CTX_new()) == NULL + || !HMAC_Init_ex(hmac, key, md_size, md, NULL) + || !HMAC_Update(hmac, p12->authsafes->d.data->data, + p12->authsafes->d.data->length) + || !HMAC_Final(hmac, mac, maclen)) { + goto err; + } + ret = 1; + +err: + OPENSSL_cleanse(key, sizeof(key)); + HMAC_CTX_free(hmac); + EVP_MD_free(md_fetch); + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-12797/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2024-12797/fixed.c new file mode 100644 index 0000000..eb2bcb5 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-12797/fixed.c @@ -0,0 +1,76 @@ +/* Provenance: openssl/openssl tls_post_process_server_rpk (fixed). + * repo: openssl/openssl + * commit: 798779d43494549b611233f92652f0da5328fbe7 + * parent: 0db27ec7f8abd258d2e8849ac555ca26ba0cd8d6 + * commit_url: https://github.com/openssl/openssl/commit/798779d43494549b611233f92652f0da5328fbe7 + * cve: CVE-2024-12797 + * license: Apache-2.0 + * function: tls_post_process_server_rpk + * relpath: ssl/statem/statem_clnt.c + */ + +static WORK_STATE tls_post_process_server_rpk(SSL_CONNECTION *sc, + WORK_STATE wst) +{ + size_t certidx; + const SSL_CERT_LOOKUP *clu; + int v_ok; + + if (sc->session->peer_rpk == NULL) { + SSLfatal(sc, SSL_AD_ILLEGAL_PARAMETER, + SSL_R_INVALID_RAW_PUBLIC_KEY); + return WORK_ERROR; + } + + if (sc->rwstate == SSL_RETRY_VERIFY) + sc->rwstate = SSL_NOTHING; + + ERR_set_mark(); + v_ok = ssl_verify_rpk(sc, sc->session->peer_rpk); + if (v_ok <= 0 && sc->verify_mode != SSL_VERIFY_NONE) { + ERR_clear_last_mark(); + SSLfatal(sc, ssl_x509err2alert(sc->verify_result), + SSL_R_CERTIFICATE_VERIFY_FAILED); + return WORK_ERROR; + } + ERR_pop_to_mark(); /* but we keep s->verify_result */ + if (v_ok > 0 && sc->rwstate == SSL_RETRY_VERIFY) { + return WORK_MORE_A; + } + + if ((clu = ssl_cert_lookup_by_pkey(sc->session->peer_rpk, &certidx, + SSL_CONNECTION_GET_CTX(sc))) == NULL) { + SSLfatal(sc, SSL_AD_ILLEGAL_PARAMETER, SSL_R_UNKNOWN_CERTIFICATE_TYPE); + return WORK_ERROR; + } + + /* + * Check certificate type is consistent with ciphersuite. For TLS 1.3 + * skip check since TLS 1.3 ciphersuites can be used with any certificate + * type. + */ + if (!SSL_CONNECTION_IS_TLS13(sc)) { + if ((clu->amask & sc->s3.tmp.new_cipher->algorithm_auth) == 0) { + SSLfatal(sc, SSL_AD_ILLEGAL_PARAMETER, SSL_R_WRONG_RPK_TYPE); + return WORK_ERROR; + } + } + + /* Ensure there is no peer/peer_chain */ + X509_free(sc->session->peer); + sc->session->peer = NULL; + sk_X509_pop_free(sc->session->peer_chain, X509_free); + sc->session->peer_chain = NULL; + sc->session->verify_result = sc->verify_result; + + /* Save the current hash state for when we receive the CertificateVerify */ + if (SSL_CONNECTION_IS_TLS13(sc) + && !ssl_handshake_hash(sc, sc->cert_verify_hash, + sizeof(sc->cert_verify_hash), + &sc->cert_verify_hash_len)) { + /* SSLfatal() already called */ + return WORK_ERROR; + } + + return WORK_FINISHED_CONTINUE; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-12797/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2024-12797/vuln.c new file mode 100644 index 0000000..1f21ff1 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-12797/vuln.c @@ -0,0 +1,65 @@ +/* Provenance: openssl/openssl tls_post_process_server_rpk (vuln). + * repo: openssl/openssl + * commit: 0db27ec7f8abd258d2e8849ac555ca26ba0cd8d6 + * parent: 0db27ec7f8abd258d2e8849ac555ca26ba0cd8d6 + * commit_url: https://github.com/openssl/openssl/commit/798779d43494549b611233f92652f0da5328fbe7 + * cve: CVE-2024-12797 + * license: Apache-2.0 + * function: tls_post_process_server_rpk + * relpath: ssl/statem/statem_clnt.c + */ + +static WORK_STATE tls_post_process_server_rpk(SSL_CONNECTION *sc, + WORK_STATE wst) +{ + size_t certidx; + const SSL_CERT_LOOKUP *clu; + + if (sc->session->peer_rpk == NULL) { + SSLfatal(sc, SSL_AD_ILLEGAL_PARAMETER, + SSL_R_INVALID_RAW_PUBLIC_KEY); + return WORK_ERROR; + } + + if (sc->rwstate == SSL_RETRY_VERIFY) + sc->rwstate = SSL_NOTHING; + if (ssl_verify_rpk(sc, sc->session->peer_rpk) > 0 + && sc->rwstate == SSL_RETRY_VERIFY) + return WORK_MORE_A; + + if ((clu = ssl_cert_lookup_by_pkey(sc->session->peer_rpk, &certidx, + SSL_CONNECTION_GET_CTX(sc))) == NULL) { + SSLfatal(sc, SSL_AD_ILLEGAL_PARAMETER, SSL_R_UNKNOWN_CERTIFICATE_TYPE); + return WORK_ERROR; + } + + /* + * Check certificate type is consistent with ciphersuite. For TLS 1.3 + * skip check since TLS 1.3 ciphersuites can be used with any certificate + * type. + */ + if (!SSL_CONNECTION_IS_TLS13(sc)) { + if ((clu->amask & sc->s3.tmp.new_cipher->algorithm_auth) == 0) { + SSLfatal(sc, SSL_AD_ILLEGAL_PARAMETER, SSL_R_WRONG_RPK_TYPE); + return WORK_ERROR; + } + } + + /* Ensure there is no peer/peer_chain */ + X509_free(sc->session->peer); + sc->session->peer = NULL; + sk_X509_pop_free(sc->session->peer_chain, X509_free); + sc->session->peer_chain = NULL; + sc->session->verify_result = sc->verify_result; + + /* Save the current hash state for when we receive the CertificateVerify */ + if (SSL_CONNECTION_IS_TLS13(sc) + && !ssl_handshake_hash(sc, sc->cert_verify_hash, + sizeof(sc->cert_verify_hash), + &sc->cert_verify_hash_len)) { + /* SSLfatal() already called */ + return WORK_ERROR; + } + + return WORK_FINISHED_CONTINUE; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-13176-ec_field_inverse_mod_ord/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2024-13176-ec_field_inverse_mod_ord/fixed.c new file mode 100644 index 0000000..a774a85 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-13176-ec_field_inverse_mod_ord/fixed.c @@ -0,0 +1,58 @@ +/* Provenance: openssl/openssl ec_field_inverse_mod_ord (fixed). + * repo: openssl/openssl + * commit: 07272b05b04836a762b4baa874958af51d513844 + * parent: 643de602771f6b38ad7823e26d5a63c669eb185b + * commit_url: https://github.com/openssl/openssl/commit/07272b05b04836a762b4baa874958af51d513844 + * cve: CVE-2024-13176 + * license: Apache-2.0 + * function: ec_field_inverse_mod_ord + * relpath: crypto/ec/ec_lib.c + */ + +static int ec_field_inverse_mod_ord(const EC_GROUP *group, BIGNUM *r, + const BIGNUM *x, BN_CTX *ctx) +{ + BIGNUM *e = NULL; + int ret = 0; +#ifndef FIPS_MODULE + BN_CTX *new_ctx = NULL; +#endif + + if (group->mont_data == NULL) + return 0; + +#ifndef FIPS_MODULE + if (ctx == NULL) + ctx = new_ctx = BN_CTX_secure_new(); +#endif + if (ctx == NULL) + return 0; + + BN_CTX_start(ctx); + if ((e = BN_CTX_get(ctx)) == NULL) + goto err; + + /*- + * We want inverse in constant time, therefore we utilize the fact + * order must be prime and use Fermats Little Theorem instead. + */ + if (!BN_set_word(e, 2)) + goto err; + if (!BN_sub(e, group->order, e)) + goto err; + /*- + * Although the exponent is public we want the result to be + * fixed top. + */ + if (!bn_mod_exp_mont_fixed_top(r, x, e, group->order, ctx, group->mont_data)) + goto err; + + ret = 1; + + err: + BN_CTX_end(ctx); +#ifndef FIPS_MODULE + BN_CTX_free(new_ctx); +#endif + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-13176-ec_field_inverse_mod_ord/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2024-13176-ec_field_inverse_mod_ord/vuln.c new file mode 100644 index 0000000..49b66a2 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-13176-ec_field_inverse_mod_ord/vuln.c @@ -0,0 +1,58 @@ +/* Provenance: openssl/openssl ec_field_inverse_mod_ord (vuln). + * repo: openssl/openssl + * commit: 643de602771f6b38ad7823e26d5a63c669eb185b + * parent: 643de602771f6b38ad7823e26d5a63c669eb185b + * commit_url: https://github.com/openssl/openssl/commit/07272b05b04836a762b4baa874958af51d513844 + * cve: CVE-2024-13176 + * license: Apache-2.0 + * function: ec_field_inverse_mod_ord + * relpath: crypto/ec/ec_lib.c + */ + +static int ec_field_inverse_mod_ord(const EC_GROUP *group, BIGNUM *r, + const BIGNUM *x, BN_CTX *ctx) +{ + BIGNUM *e = NULL; + int ret = 0; +#ifndef FIPS_MODULE + BN_CTX *new_ctx = NULL; +#endif + + if (group->mont_data == NULL) + return 0; + +#ifndef FIPS_MODULE + if (ctx == NULL) + ctx = new_ctx = BN_CTX_secure_new(); +#endif + if (ctx == NULL) + return 0; + + BN_CTX_start(ctx); + if ((e = BN_CTX_get(ctx)) == NULL) + goto err; + + /*- + * We want inverse in constant time, therefore we utilize the fact + * order must be prime and use Fermats Little Theorem instead. + */ + if (!BN_set_word(e, 2)) + goto err; + if (!BN_sub(e, group->order, e)) + goto err; + /*- + * Exponent e is public. + * No need for scatter-gather or BN_FLG_CONSTTIME. + */ + if (!BN_mod_exp_mont(r, x, e, group->order, ctx, group->mont_data)) + goto err; + + ret = 1; + + err: + BN_CTX_end(ctx); +#ifndef FIPS_MODULE + BN_CTX_free(new_ctx); +#endif + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-2511-tls_construct_server_hel/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2024-2511-tls_construct_server_hel/fixed.c new file mode 100644 index 0000000..4148024 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-2511-tls_construct_server_hel/fixed.c @@ -0,0 +1,118 @@ +/* Provenance: openssl/openssl tls_construct_server_hello (fixed). + * repo: openssl/openssl + * commit: b52867a9f618bb955bed2a3ce3db4d4f97ed8e5d + * parent: c1e462ee4bd61867ee391fc13110ca41e4889535 + * commit_url: https://github.com/openssl/openssl/commit/b52867a9f618bb955bed2a3ce3db4d4f97ed8e5d + * cve: CVE-2024-2511 + * license: Apache-2.0 + * function: tls_construct_server_hello + * relpath: ssl/statem/statem_srvr.c + */ + +int tls_construct_server_hello(SSL *s, WPACKET *pkt) +{ + int compm; + size_t sl, len; + int version; + unsigned char *session_id; + int usetls13 = SSL_IS_TLS13(s) || s->hello_retry_request == SSL_HRR_PENDING; + + version = usetls13 ? TLS1_2_VERSION : s->version; + if (!WPACKET_put_bytes_u16(pkt, version) + /* + * Random stuff. Filling of the server_random takes place in + * tls_process_client_hello() + */ + || !WPACKET_memcpy(pkt, + s->hello_retry_request == SSL_HRR_PENDING + ? hrrrandom : s->s3.server_random, + SSL3_RANDOM_SIZE)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + + /*- + * There are several cases for the session ID to send + * back in the server hello: + * - For session reuse from the session cache, + * we send back the old session ID. + * - If stateless session reuse (using a session ticket) + * is successful, we send back the client's "session ID" + * (which doesn't actually identify the session). + * - If it is a new session, we send back the new + * session ID. + * - However, if we want the new session to be single-use, + * we send back a 0-length session ID. + * - In TLSv1.3 we echo back the session id sent to us by the client + * regardless + * s->hit is non-zero in either case of session reuse, + * so the following won't overwrite an ID that we're supposed + * to send back. + */ + if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER) + && !s->hit) + s->session->session_id_length = 0; + + if (usetls13) { + sl = s->tmp_session_id_len; + session_id = s->tmp_session_id; + } else { + sl = s->session->session_id_length; + session_id = s->session->session_id; + } + + if (sl > sizeof(s->session->session_id)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + + /* set up the compression method */ +#ifdef OPENSSL_NO_COMP + compm = 0; +#else + if (usetls13 || s->s3.tmp.new_compression == NULL) + compm = 0; + else + compm = s->s3.tmp.new_compression->id; +#endif + + if (!WPACKET_sub_memcpy_u8(pkt, session_id, sl) + || !s->method->put_cipher_by_char(s->s3.tmp.new_cipher, pkt, &len) + || !WPACKET_put_bytes_u8(pkt, compm)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + + if (!tls_construct_extensions(s, pkt, + s->hello_retry_request == SSL_HRR_PENDING + ? SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST + : (SSL_IS_TLS13(s) + ? SSL_EXT_TLS1_3_SERVER_HELLO + : SSL_EXT_TLS1_2_SERVER_HELLO), + NULL, 0)) { + /* SSLfatal() already called */ + return 0; + } + + if (s->hello_retry_request == SSL_HRR_PENDING) { + /* Ditch the session. We'll create a new one next time around */ + SSL_SESSION_free(s->session); + s->session = NULL; + s->hit = 0; + + /* + * Re-initialise the Transcript Hash. We're going to prepopulate it with + * a synthetic message_hash in place of ClientHello1. + */ + if (!create_synthetic_message_hash(s, NULL, 0, NULL, 0)) { + /* SSLfatal() already called */ + return 0; + } + } else if (!(s->verify_mode & SSL_VERIFY_PEER) + && !ssl3_digest_cached_records(s, 0)) { + /* SSLfatal() already called */; + return 0; + } + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-2511-tls_construct_server_hel/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2024-2511-tls_construct_server_hel/vuln.c new file mode 100644 index 0000000..9e26228 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-2511-tls_construct_server_hel/vuln.c @@ -0,0 +1,119 @@ +/* Provenance: openssl/openssl tls_construct_server_hello (vuln). + * repo: openssl/openssl + * commit: c1e462ee4bd61867ee391fc13110ca41e4889535 + * parent: c1e462ee4bd61867ee391fc13110ca41e4889535 + * commit_url: https://github.com/openssl/openssl/commit/b52867a9f618bb955bed2a3ce3db4d4f97ed8e5d + * cve: CVE-2024-2511 + * license: Apache-2.0 + * function: tls_construct_server_hello + * relpath: ssl/statem/statem_srvr.c + */ + +int tls_construct_server_hello(SSL *s, WPACKET *pkt) +{ + int compm; + size_t sl, len; + int version; + unsigned char *session_id; + int usetls13 = SSL_IS_TLS13(s) || s->hello_retry_request == SSL_HRR_PENDING; + + version = usetls13 ? TLS1_2_VERSION : s->version; + if (!WPACKET_put_bytes_u16(pkt, version) + /* + * Random stuff. Filling of the server_random takes place in + * tls_process_client_hello() + */ + || !WPACKET_memcpy(pkt, + s->hello_retry_request == SSL_HRR_PENDING + ? hrrrandom : s->s3.server_random, + SSL3_RANDOM_SIZE)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + + /*- + * There are several cases for the session ID to send + * back in the server hello: + * - For session reuse from the session cache, + * we send back the old session ID. + * - If stateless session reuse (using a session ticket) + * is successful, we send back the client's "session ID" + * (which doesn't actually identify the session). + * - If it is a new session, we send back the new + * session ID. + * - However, if we want the new session to be single-use, + * we send back a 0-length session ID. + * - In TLSv1.3 we echo back the session id sent to us by the client + * regardless + * s->hit is non-zero in either case of session reuse, + * so the following won't overwrite an ID that we're supposed + * to send back. + */ + if (s->session->not_resumable || + (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER) + && !s->hit)) + s->session->session_id_length = 0; + + if (usetls13) { + sl = s->tmp_session_id_len; + session_id = s->tmp_session_id; + } else { + sl = s->session->session_id_length; + session_id = s->session->session_id; + } + + if (sl > sizeof(s->session->session_id)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + + /* set up the compression method */ +#ifdef OPENSSL_NO_COMP + compm = 0; +#else + if (usetls13 || s->s3.tmp.new_compression == NULL) + compm = 0; + else + compm = s->s3.tmp.new_compression->id; +#endif + + if (!WPACKET_sub_memcpy_u8(pkt, session_id, sl) + || !s->method->put_cipher_by_char(s->s3.tmp.new_cipher, pkt, &len) + || !WPACKET_put_bytes_u8(pkt, compm)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + + if (!tls_construct_extensions(s, pkt, + s->hello_retry_request == SSL_HRR_PENDING + ? SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST + : (SSL_IS_TLS13(s) + ? SSL_EXT_TLS1_3_SERVER_HELLO + : SSL_EXT_TLS1_2_SERVER_HELLO), + NULL, 0)) { + /* SSLfatal() already called */ + return 0; + } + + if (s->hello_retry_request == SSL_HRR_PENDING) { + /* Ditch the session. We'll create a new one next time around */ + SSL_SESSION_free(s->session); + s->session = NULL; + s->hit = 0; + + /* + * Re-initialise the Transcript Hash. We're going to prepopulate it with + * a synthetic message_hash in place of ClientHello1. + */ + if (!create_synthetic_message_hash(s, NULL, 0, NULL, 0)) { + /* SSLfatal() already called */ + return 0; + } + } else if (!(s->verify_mode & SSL_VERIFY_PEER) + && !ssl3_digest_cached_records(s, 0)) { + /* SSLfatal() already called */; + return 0; + } + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-2511/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2024-2511/fixed.c new file mode 100644 index 0000000..01e5d1d --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-2511/fixed.c @@ -0,0 +1,83 @@ +/* Provenance: openssl/openssl ssl_update_cache (fixed). + * repo: openssl/openssl + * commit: b52867a9f618bb955bed2a3ce3db4d4f97ed8e5d + * parent: c1e462ee4bd61867ee391fc13110ca41e4889535 + * commit_url: https://github.com/openssl/openssl/commit/b52867a9f618bb955bed2a3ce3db4d4f97ed8e5d + * cve: CVE-2024-2511 + * license: Apache-2.0 + * function: ssl_update_cache + * relpath: ssl/ssl_lib.c + */ + +void ssl_update_cache(SSL *s, int mode) +{ + int i; + + /* + * If the session_id_length is 0, we are not supposed to cache it, and it + * would be rather hard to do anyway :-). Also if the session has already + * been marked as not_resumable we should not cache it for later reuse. + */ + if (s->session->session_id_length == 0 || s->session->not_resumable) + return; + + /* + * If sid_ctx_length is 0 there is no specific application context + * associated with this session, so when we try to resume it and + * SSL_VERIFY_PEER is requested to verify the client identity, we have no + * indication that this is actually a session for the proper application + * context, and the *handshake* will fail, not just the resumption attempt. + * Do not cache (on the server) these sessions that are not resumable + * (clients can set SSL_VERIFY_PEER without needing a sid_ctx set). + */ + if (s->server && s->session->sid_ctx_length == 0 + && (s->verify_mode & SSL_VERIFY_PEER) != 0) + return; + + i = s->session_ctx->session_cache_mode; + if ((i & mode) != 0 + && (!s->hit || SSL_IS_TLS13(s))) { + /* + * Add the session to the internal cache. In server side TLSv1.3 we + * normally don't do this because by default it's a full stateless ticket + * with only a dummy session id so there is no reason to cache it, + * unless: + * - we are doing early_data, in which case we cache so that we can + * detect replays + * - the application has set a remove_session_cb so needs to know about + * session timeout events + * - SSL_OP_NO_TICKET is set in which case it is a stateful ticket + */ + if ((i & SSL_SESS_CACHE_NO_INTERNAL_STORE) == 0 + && (!SSL_IS_TLS13(s) + || !s->server + || (s->max_early_data > 0 + && (s->options & SSL_OP_NO_ANTI_REPLAY) == 0) + || s->session_ctx->remove_session_cb != NULL + || (s->options & SSL_OP_NO_TICKET) != 0)) + SSL_CTX_add_session(s->session_ctx, s->session); + + /* + * Add the session to the external cache. We do this even in server side + * TLSv1.3 without early data because some applications just want to + * know about the creation of a session and aren't doing a full cache. + */ + if (s->session_ctx->new_session_cb != NULL) { + SSL_SESSION_up_ref(s->session); + if (!s->session_ctx->new_session_cb(s, s->session)) + SSL_SESSION_free(s->session); + } + } + + /* auto flush every 255 connections */ + if ((!(i & SSL_SESS_CACHE_NO_AUTO_CLEAR)) && ((i & mode) == mode)) { + TSAN_QUALIFIER int *stat; + + if (mode & SSL_SESS_CACHE_CLIENT) + stat = &s->session_ctx->stats.sess_connect_good; + else + stat = &s->session_ctx->stats.sess_accept_good; + if ((ssl_tsan_load(s->session_ctx, stat) & 0xff) == 0xff) + SSL_CTX_flush_sessions(s->session_ctx, (unsigned long)time(NULL)); + } +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-2511/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2024-2511/vuln.c new file mode 100644 index 0000000..ef6dee9 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-2511/vuln.c @@ -0,0 +1,82 @@ +/* Provenance: openssl/openssl ssl_update_cache (vuln). + * repo: openssl/openssl + * commit: c1e462ee4bd61867ee391fc13110ca41e4889535 + * parent: c1e462ee4bd61867ee391fc13110ca41e4889535 + * commit_url: https://github.com/openssl/openssl/commit/b52867a9f618bb955bed2a3ce3db4d4f97ed8e5d + * cve: CVE-2024-2511 + * license: Apache-2.0 + * function: ssl_update_cache + * relpath: ssl/ssl_lib.c + */ + +void ssl_update_cache(SSL *s, int mode) +{ + int i; + + /* + * If the session_id_length is 0, we are not supposed to cache it, and it + * would be rather hard to do anyway :-) + */ + if (s->session->session_id_length == 0) + return; + + /* + * If sid_ctx_length is 0 there is no specific application context + * associated with this session, so when we try to resume it and + * SSL_VERIFY_PEER is requested to verify the client identity, we have no + * indication that this is actually a session for the proper application + * context, and the *handshake* will fail, not just the resumption attempt. + * Do not cache (on the server) these sessions that are not resumable + * (clients can set SSL_VERIFY_PEER without needing a sid_ctx set). + */ + if (s->server && s->session->sid_ctx_length == 0 + && (s->verify_mode & SSL_VERIFY_PEER) != 0) + return; + + i = s->session_ctx->session_cache_mode; + if ((i & mode) != 0 + && (!s->hit || SSL_IS_TLS13(s))) { + /* + * Add the session to the internal cache. In server side TLSv1.3 we + * normally don't do this because by default it's a full stateless ticket + * with only a dummy session id so there is no reason to cache it, + * unless: + * - we are doing early_data, in which case we cache so that we can + * detect replays + * - the application has set a remove_session_cb so needs to know about + * session timeout events + * - SSL_OP_NO_TICKET is set in which case it is a stateful ticket + */ + if ((i & SSL_SESS_CACHE_NO_INTERNAL_STORE) == 0 + && (!SSL_IS_TLS13(s) + || !s->server + || (s->max_early_data > 0 + && (s->options & SSL_OP_NO_ANTI_REPLAY) == 0) + || s->session_ctx->remove_session_cb != NULL + || (s->options & SSL_OP_NO_TICKET) != 0)) + SSL_CTX_add_session(s->session_ctx, s->session); + + /* + * Add the session to the external cache. We do this even in server side + * TLSv1.3 without early data because some applications just want to + * know about the creation of a session and aren't doing a full cache. + */ + if (s->session_ctx->new_session_cb != NULL) { + SSL_SESSION_up_ref(s->session); + if (!s->session_ctx->new_session_cb(s, s->session)) + SSL_SESSION_free(s->session); + } + } + + /* auto flush every 255 connections */ + if ((!(i & SSL_SESS_CACHE_NO_AUTO_CLEAR)) && ((i & mode) == mode)) { + TSAN_QUALIFIER int *stat; + + if (mode & SSL_SESS_CACHE_CLIENT) + stat = &s->session_ctx->stats.sess_connect_good; + else + stat = &s->session_ctx->stats.sess_accept_good; + if ((ssl_tsan_load(s->session_ctx, stat) & 0xff) == 0xff) + SSL_CTX_flush_sessions(s->session_ctx, (unsigned long)time(NULL)); + } +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-4603/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2024-4603/fixed.c new file mode 100644 index 0000000..d92f0fc --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-4603/fixed.c @@ -0,0 +1,28 @@ +/* Provenance: openssl/openssl ossl_dsa_check_params (fixed). + * repo: openssl/openssl + * commit: 3559e868e58005d15c6013a0c1fd832e51c73397 + * parent: d4b119c567cb5dcaf83add7ca2ea1d646eb3ef9f + * commit_url: https://github.com/openssl/openssl/commit/3559e868e58005d15c6013a0c1fd832e51c73397 + * cve: CVE-2024-4603 + * license: Apache-2.0 + * function: ossl_dsa_check_params + * relpath: crypto/dsa/dsa_check.c + */ + +int ossl_dsa_check_params(const DSA *dsa, int checktype, int *ret) +{ + if (!dsa_precheck_params(dsa, ret)) + return 0; + + if (checktype == OSSL_KEYMGMT_VALIDATE_QUICK_CHECK) + return ossl_ffc_params_simple_validate(dsa->libctx, &dsa->params, + FFC_PARAM_TYPE_DSA, ret); + else + /* + * Do full FFC domain params validation according to FIPS-186-4 + * - always in FIPS_MODULE + * - only if possible (i.e., seed is set) in default provider + */ + return ossl_ffc_params_full_validate(dsa->libctx, &dsa->params, + FFC_PARAM_TYPE_DSA, ret); +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-4603/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2024-4603/vuln.c new file mode 100644 index 0000000..3a211ca --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-4603/vuln.c @@ -0,0 +1,25 @@ +/* Provenance: openssl/openssl ossl_dsa_check_params (vuln). + * repo: openssl/openssl + * commit: d4b119c567cb5dcaf83add7ca2ea1d646eb3ef9f + * parent: d4b119c567cb5dcaf83add7ca2ea1d646eb3ef9f + * commit_url: https://github.com/openssl/openssl/commit/3559e868e58005d15c6013a0c1fd832e51c73397 + * cve: CVE-2024-4603 + * license: Apache-2.0 + * function: ossl_dsa_check_params + * relpath: crypto/dsa/dsa_check.c + */ + +int ossl_dsa_check_params(const DSA *dsa, int checktype, int *ret) +{ + if (checktype == OSSL_KEYMGMT_VALIDATE_QUICK_CHECK) + return ossl_ffc_params_simple_validate(dsa->libctx, &dsa->params, + FFC_PARAM_TYPE_DSA, ret); + else + /* + * Do full FFC domain params validation according to FIPS-186-4 + * - always in FIPS_MODULE + * - only if possible (i.e., seed is set) in default provider + */ + return ossl_ffc_params_full_validate(dsa->libctx, &dsa->params, + FFC_PARAM_TYPE_DSA, ret); +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-4741-ssl3_release_read_buffer/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2024-4741-ssl3_release_read_buffer/fixed.c new file mode 100644 index 0000000..b725075 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-4741-ssl3_release_read_buffer/fixed.c @@ -0,0 +1,24 @@ +/* Provenance: openssl/openssl ssl3_release_read_buffer (fixed). + * repo: openssl/openssl + * commit: 2d05959073c4bf8803401668b9df85931a08e020 + * parent: b3f0eb0a295f58f16ba43ba99dad70d4ee5c437d + * commit_url: https://github.com/openssl/openssl/commit/2d05959073c4bf8803401668b9df85931a08e020 + * cve: CVE-2024-4741 + * license: Apache-2.0 + * function: ssl3_release_read_buffer + * relpath: ssl/record/ssl3_buffer.c + */ + +int ssl3_release_read_buffer(SSL *s) +{ + SSL3_BUFFER *b; + + b = RECORD_LAYER_get_rbuf(&s->rlayer); + if (s->options & SSL_OP_CLEANSE_PLAINTEXT) + OPENSSL_cleanse(b->buf, b->len); + OPENSSL_free(b->buf); + b->buf = NULL; + s->rlayer.packet = NULL; + s->rlayer.packet_length = 0; + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-4741-ssl3_release_read_buffer/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2024-4741-ssl3_release_read_buffer/vuln.c new file mode 100644 index 0000000..92c7566 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-4741-ssl3_release_read_buffer/vuln.c @@ -0,0 +1,22 @@ +/* Provenance: openssl/openssl ssl3_release_read_buffer (vuln). + * repo: openssl/openssl + * commit: b3f0eb0a295f58f16ba43ba99dad70d4ee5c437d + * parent: b3f0eb0a295f58f16ba43ba99dad70d4ee5c437d + * commit_url: https://github.com/openssl/openssl/commit/2d05959073c4bf8803401668b9df85931a08e020 + * cve: CVE-2024-4741 + * license: Apache-2.0 + * function: ssl3_release_read_buffer + * relpath: ssl/record/ssl3_buffer.c + */ + +int ssl3_release_read_buffer(SSL *s) +{ + SSL3_BUFFER *b; + + b = RECORD_LAYER_get_rbuf(&s->rlayer); + if (s->options & SSL_OP_CLEANSE_PLAINTEXT) + OPENSSL_cleanse(b->buf, b->len); + OPENSSL_free(b->buf); + b->buf = NULL; + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-4741-ssl_free_buffers/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2024-4741-ssl_free_buffers/fixed.c new file mode 100644 index 0000000..a972491 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-4741-ssl_free_buffers/fixed.c @@ -0,0 +1,24 @@ +/* Provenance: openssl/openssl SSL_free_buffers (fixed). + * repo: openssl/openssl + * commit: b3f0eb0a295f58f16ba43ba99dad70d4ee5c437d + * parent: ec559c2a6cca3fd4cedae5c47f2dfa38e5e24865 + * commit_url: https://github.com/openssl/openssl/commit/b3f0eb0a295f58f16ba43ba99dad70d4ee5c437d + * cve: CVE-2024-4741 + * license: Apache-2.0 + * function: SSL_free_buffers + * relpath: ssl/ssl_lib.c + */ + +int SSL_free_buffers(SSL *ssl) +{ + RECORD_LAYER *rl = &ssl->rlayer; + + if (RECORD_LAYER_read_pending(rl) || RECORD_LAYER_write_pending(rl)) + return 0; + + if (RECORD_LAYER_data_present(rl)) + return 0; + + RECORD_LAYER_release(rl); + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-4741-ssl_free_buffers/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2024-4741-ssl_free_buffers/vuln.c new file mode 100644 index 0000000..c84145e --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-4741-ssl_free_buffers/vuln.c @@ -0,0 +1,21 @@ +/* Provenance: openssl/openssl SSL_free_buffers (vuln). + * repo: openssl/openssl + * commit: ec559c2a6cca3fd4cedae5c47f2dfa38e5e24865 + * parent: ec559c2a6cca3fd4cedae5c47f2dfa38e5e24865 + * commit_url: https://github.com/openssl/openssl/commit/b3f0eb0a295f58f16ba43ba99dad70d4ee5c437d + * cve: CVE-2024-4741 + * license: Apache-2.0 + * function: SSL_free_buffers + * relpath: ssl/ssl_lib.c + */ + +int SSL_free_buffers(SSL *ssl) +{ + RECORD_LAYER *rl = &ssl->rlayer; + + if (RECORD_LAYER_read_pending(rl) || RECORD_LAYER_write_pending(rl)) + return 0; + + RECORD_LAYER_release(rl); + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-4741-tls_free_buffers/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2024-4741-tls_free_buffers/fixed.c new file mode 100644 index 0000000..cd83a20 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-4741-tls_free_buffers/fixed.c @@ -0,0 +1,41 @@ +/* Provenance: openssl/openssl tls_free_buffers (fixed). + * repo: openssl/openssl + * commit: c88c3de51020c37e8706bf7a682a162593053aac + * parent: 17765d9cefed8b4ada6548719beb98e22672a9bd + * commit_url: https://github.com/openssl/openssl/commit/c88c3de51020c37e8706bf7a682a162593053aac + * cve: CVE-2024-4741 + * license: Apache-2.0 + * function: tls_free_buffers + * relpath: ssl/record/methods/tls_common.c + */ + +int tls_free_buffers(OSSL_RECORD_LAYER *rl) +{ + if (rl->direction == OSSL_RECORD_DIRECTION_WRITE) { + if (rl->nextwbuf < rl->numwpipes) { + /* + * We may have pending data. If we've just got one empty buffer + * allocated then it has probably just been alloc'd via + * tls_alloc_buffers, and it is fine to free it. Otherwise this + * looks like real pending data and it is an error. + */ + if (rl->nextwbuf != 0 + || rl->numwpipes != 1 + || TLS_BUFFER_get_left(&rl->wbuf[0]) != 0) + return 0; + } + tls_release_write_buffer(rl); + return 1; + } + + /* Read direction */ + + /* If we have pending data to be read then fail */ + if (rl->curr_rec < rl->num_recs + || rl->curr_rec != rl->num_released + || TLS_BUFFER_get_left(&rl->rbuf) != 0 + || rl->rstate == SSL_ST_READ_BODY) + return 0; + + return tls_release_read_buffer(rl); +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-4741-tls_free_buffers/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2024-4741-tls_free_buffers/vuln.c new file mode 100644 index 0000000..e6ab4a4 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-4741-tls_free_buffers/vuln.c @@ -0,0 +1,38 @@ +/* Provenance: openssl/openssl tls_free_buffers (vuln). + * repo: openssl/openssl + * commit: 17765d9cefed8b4ada6548719beb98e22672a9bd + * parent: 17765d9cefed8b4ada6548719beb98e22672a9bd + * commit_url: https://github.com/openssl/openssl/commit/c88c3de51020c37e8706bf7a682a162593053aac + * cve: CVE-2024-4741 + * license: Apache-2.0 + * function: tls_free_buffers + * relpath: ssl/record/methods/tls_common.c + */ + +int tls_free_buffers(OSSL_RECORD_LAYER *rl) +{ + if (rl->direction == OSSL_RECORD_DIRECTION_WRITE) { + if (rl->nextwbuf < rl->numwpipes) { + /* + * We may have pending data. If we've just got one empty buffer + * allocated then it has probably just been alloc'd via + * tls_alloc_buffers, and it is fine to free it. Otherwise this + * looks like real pending data and it is an error. + */ + if (rl->nextwbuf != 0 + || rl->numwpipes != 1 + || TLS_BUFFER_get_left(&rl->wbuf[0]) != 0) + return 0; + } + tls_release_write_buffer(rl); + return 1; + } + + /* Read direction */ + + /* If we have pending data to be read then fail */ + if (rl->curr_rec < rl->num_recs || TLS_BUFFER_get_left(&rl->rbuf) != 0) + return 0; + + return tls_release_read_buffer(rl); +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-4741-tls_release_read_buffer/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2024-4741-tls_release_read_buffer/fixed.c new file mode 100644 index 0000000..8422206 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-4741-tls_release_read_buffer/fixed.c @@ -0,0 +1,24 @@ +/* Provenance: openssl/openssl tls_release_read_buffer (fixed). + * repo: openssl/openssl + * commit: 10171e5b511b700c5ecd4fd3e1086b19c34b1ae3 + * parent: c88c3de51020c37e8706bf7a682a162593053aac + * commit_url: https://github.com/openssl/openssl/commit/10171e5b511b700c5ecd4fd3e1086b19c34b1ae3 + * cve: CVE-2024-4741 + * license: Apache-2.0 + * function: tls_release_read_buffer + * relpath: ssl/record/methods/tls_common.c + */ + +static int tls_release_read_buffer(OSSL_RECORD_LAYER *rl) +{ + TLS_BUFFER *b; + + b = &rl->rbuf; + if ((rl->options & SSL_OP_CLEANSE_PLAINTEXT) != 0) + OPENSSL_cleanse(b->buf, b->len); + OPENSSL_free(b->buf); + b->buf = NULL; + rl->packet = NULL; + rl->packet_length = 0; + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-4741-tls_release_read_buffer/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2024-4741-tls_release_read_buffer/vuln.c new file mode 100644 index 0000000..be5211a --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-4741-tls_release_read_buffer/vuln.c @@ -0,0 +1,22 @@ +/* Provenance: openssl/openssl tls_release_read_buffer (vuln). + * repo: openssl/openssl + * commit: c88c3de51020c37e8706bf7a682a162593053aac + * parent: c88c3de51020c37e8706bf7a682a162593053aac + * commit_url: https://github.com/openssl/openssl/commit/10171e5b511b700c5ecd4fd3e1086b19c34b1ae3 + * cve: CVE-2024-4741 + * license: Apache-2.0 + * function: tls_release_read_buffer + * relpath: ssl/record/methods/tls_common.c + */ + +static int tls_release_read_buffer(OSSL_RECORD_LAYER *rl) +{ + TLS_BUFFER *b; + + b = &rl->rbuf; + if ((rl->options & SSL_OP_CLEANSE_PLAINTEXT) != 0) + OPENSSL_cleanse(b->buf, b->len); + OPENSSL_free(b->buf); + b->buf = NULL; + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-4741/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2024-4741/fixed.c new file mode 100644 index 0000000..b70df86 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-4741/fixed.c @@ -0,0 +1,178 @@ +/* Provenance: openssl/openssl ssl3_read_n (fixed). + * repo: openssl/openssl + * commit: 2d05959073c4bf8803401668b9df85931a08e020 + * parent: b3f0eb0a295f58f16ba43ba99dad70d4ee5c437d + * commit_url: https://github.com/openssl/openssl/commit/2d05959073c4bf8803401668b9df85931a08e020 + * cve: CVE-2024-4741 + * license: Apache-2.0 + * function: ssl3_read_n + * relpath: ssl/record/rec_layer_s3.c + */ + +int ssl3_read_n(SSL *s, size_t n, size_t max, int extend, int clearold, + size_t *readbytes) +{ + /* + * If extend == 0, obtain new n-byte packet; if extend == 1, increase + * packet by another n bytes. The packet will be in the sub-array of + * s->rlayer.rbuf.buf specified by s->rlayer.packet and + * s->rlayer.packet_length. (If s->rlayer.read_ahead is set, 'max' bytes may + * be stored in rbuf [plus s->rlayer.packet_length bytes if extend == 1].) + * if clearold == 1, move the packet to the start of the buffer; if + * clearold == 0 then leave any old packets where they were + */ + size_t len, left, align = 0; + unsigned char *pkt; + SSL3_BUFFER *rb; + + if (n == 0) + return 0; + + rb = &s->rlayer.rbuf; + if (rb->buf == NULL) + if (!ssl3_setup_read_buffer(s)) { + /* SSLfatal() already called */ + return -1; + } + + left = rb->left; +#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0 + align = (size_t)rb->buf + SSL3_RT_HEADER_LENGTH; + align = SSL3_ALIGN_PAYLOAD - 1 - ((align - 1) % SSL3_ALIGN_PAYLOAD); +#endif + + if (!extend) { + /* start with empty packet ... */ + if (left == 0) + rb->offset = align; + + s->rlayer.packet = rb->buf + rb->offset; + s->rlayer.packet_length = 0; + /* ... now we can act as if 'extend' was set */ + } + + if (!ossl_assert(s->rlayer.packet != NULL)) { + /* does not happen */ + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return -1; + } + + len = s->rlayer.packet_length; + pkt = rb->buf + align; + /* + * Move any available bytes to front of buffer: 'len' bytes already + * pointed to by 'packet', 'left' extra ones at the end + */ + if (s->rlayer.packet != pkt && clearold == 1) { + memmove(pkt, s->rlayer.packet, len + left); + s->rlayer.packet = pkt; + rb->offset = len + align; + } + + /* + * For DTLS/UDP reads should not span multiple packets because the read + * operation returns the whole packet at once (as long as it fits into + * the buffer). + */ + if (SSL_IS_DTLS(s)) { + if (left == 0 && extend) + return 0; + if (left > 0 && n > left) + n = left; + } + + /* if there is enough in the buffer from a previous read, take some */ + if (left >= n) { + s->rlayer.packet_length += n; + rb->left = left - n; + rb->offset += n; + *readbytes = n; + return 1; + } + + /* else we need to read more data */ + + if (n > rb->len - rb->offset) { + /* does not happen */ + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return -1; + } + + /* + * Ktls always reads full records. + * Also, we always act like read_ahead is set for DTLS. + */ + if (!BIO_get_ktls_recv(s->rbio) && !s->rlayer.read_ahead + && !SSL_IS_DTLS(s)) { + /* ignore max parameter */ + max = n; + } else { + if (max < n) + max = n; + if (max > rb->len - rb->offset) + max = rb->len - rb->offset; + } + + while (left < n) { + size_t bioread = 0; + int ret; + + /* + * Now we have len+left bytes at the front of s->s3.rbuf.buf and + * need to read in more until we have len+n (up to len+max if + * possible) + */ + + clear_sys_error(); + if (s->rbio != NULL) { + s->rwstate = SSL_READING; + ret = BIO_read(s->rbio, pkt + len + left, max - left); + if (ret >= 0) + bioread = ret; + if (ret <= 0 + && !BIO_should_retry(s->rbio) + && BIO_eof(s->rbio)) { + if (s->options & SSL_OP_IGNORE_UNEXPECTED_EOF) { + SSL_set_shutdown(s, SSL_RECEIVED_SHUTDOWN); + s->s3.warn_alert = SSL_AD_CLOSE_NOTIFY; + } else { + /* + * This reason code is part of the API and may be used by + * applications for control flow decisions. + */ + SSLfatal(s, SSL_AD_DECODE_ERROR, + SSL_R_UNEXPECTED_EOF_WHILE_READING); + } + } + } else { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_READ_BIO_NOT_SET); + ret = -1; + } + + if (ret <= 0) { + rb->left = left; + if (s->mode & SSL_MODE_RELEASE_BUFFERS && !SSL_IS_DTLS(s)) + if (len + left == 0) + ssl3_release_read_buffer(s); + return ret; + } + left += bioread; + /* + * reads should *never* span multiple packets for DTLS because the + * underlying transport protocol is message oriented as opposed to + * byte oriented as in the TLS case. + */ + if (SSL_IS_DTLS(s)) { + if (n > left) + n = left; /* makes the while condition false */ + } + } + + /* done reading, now the book-keeping */ + rb->offset += n; + rb->left = left - n; + s->rlayer.packet_length += n; + s->rwstate = SSL_NOTHING; + *readbytes = n; + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-4741/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2024-4741/vuln.c new file mode 100644 index 0000000..ccaf7f2 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-4741/vuln.c @@ -0,0 +1,172 @@ +/* Provenance: openssl/openssl ssl3_read_n (vuln). + * repo: openssl/openssl + * commit: b3f0eb0a295f58f16ba43ba99dad70d4ee5c437d + * parent: b3f0eb0a295f58f16ba43ba99dad70d4ee5c437d + * commit_url: https://github.com/openssl/openssl/commit/2d05959073c4bf8803401668b9df85931a08e020 + * cve: CVE-2024-4741 + * license: Apache-2.0 + * function: ssl3_read_n + * relpath: ssl/record/rec_layer_s3.c + */ + +int ssl3_read_n(SSL *s, size_t n, size_t max, int extend, int clearold, + size_t *readbytes) +{ + /* + * If extend == 0, obtain new n-byte packet; if extend == 1, increase + * packet by another n bytes. The packet will be in the sub-array of + * s->rlayer.rbuf.buf specified by s->rlayer.packet and + * s->rlayer.packet_length. (If s->rlayer.read_ahead is set, 'max' bytes may + * be stored in rbuf [plus s->rlayer.packet_length bytes if extend == 1].) + * if clearold == 1, move the packet to the start of the buffer; if + * clearold == 0 then leave any old packets where they were + */ + size_t len, left, align = 0; + unsigned char *pkt; + SSL3_BUFFER *rb; + + if (n == 0) + return 0; + + rb = &s->rlayer.rbuf; + if (rb->buf == NULL) + if (!ssl3_setup_read_buffer(s)) { + /* SSLfatal() already called */ + return -1; + } + + left = rb->left; +#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0 + align = (size_t)rb->buf + SSL3_RT_HEADER_LENGTH; + align = SSL3_ALIGN_PAYLOAD - 1 - ((align - 1) % SSL3_ALIGN_PAYLOAD); +#endif + + if (!extend) { + /* start with empty packet ... */ + if (left == 0) + rb->offset = align; + + s->rlayer.packet = rb->buf + rb->offset; + s->rlayer.packet_length = 0; + /* ... now we can act as if 'extend' was set */ + } + + len = s->rlayer.packet_length; + pkt = rb->buf + align; + /* + * Move any available bytes to front of buffer: 'len' bytes already + * pointed to by 'packet', 'left' extra ones at the end + */ + if (s->rlayer.packet != pkt && clearold == 1) { + memmove(pkt, s->rlayer.packet, len + left); + s->rlayer.packet = pkt; + rb->offset = len + align; + } + + /* + * For DTLS/UDP reads should not span multiple packets because the read + * operation returns the whole packet at once (as long as it fits into + * the buffer). + */ + if (SSL_IS_DTLS(s)) { + if (left == 0 && extend) + return 0; + if (left > 0 && n > left) + n = left; + } + + /* if there is enough in the buffer from a previous read, take some */ + if (left >= n) { + s->rlayer.packet_length += n; + rb->left = left - n; + rb->offset += n; + *readbytes = n; + return 1; + } + + /* else we need to read more data */ + + if (n > rb->len - rb->offset) { + /* does not happen */ + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return -1; + } + + /* + * Ktls always reads full records. + * Also, we always act like read_ahead is set for DTLS. + */ + if (!BIO_get_ktls_recv(s->rbio) && !s->rlayer.read_ahead + && !SSL_IS_DTLS(s)) { + /* ignore max parameter */ + max = n; + } else { + if (max < n) + max = n; + if (max > rb->len - rb->offset) + max = rb->len - rb->offset; + } + + while (left < n) { + size_t bioread = 0; + int ret; + + /* + * Now we have len+left bytes at the front of s->s3.rbuf.buf and + * need to read in more until we have len+n (up to len+max if + * possible) + */ + + clear_sys_error(); + if (s->rbio != NULL) { + s->rwstate = SSL_READING; + ret = BIO_read(s->rbio, pkt + len + left, max - left); + if (ret >= 0) + bioread = ret; + if (ret <= 0 + && !BIO_should_retry(s->rbio) + && BIO_eof(s->rbio)) { + if (s->options & SSL_OP_IGNORE_UNEXPECTED_EOF) { + SSL_set_shutdown(s, SSL_RECEIVED_SHUTDOWN); + s->s3.warn_alert = SSL_AD_CLOSE_NOTIFY; + } else { + /* + * This reason code is part of the API and may be used by + * applications for control flow decisions. + */ + SSLfatal(s, SSL_AD_DECODE_ERROR, + SSL_R_UNEXPECTED_EOF_WHILE_READING); + } + } + } else { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_READ_BIO_NOT_SET); + ret = -1; + } + + if (ret <= 0) { + rb->left = left; + if (s->mode & SSL_MODE_RELEASE_BUFFERS && !SSL_IS_DTLS(s)) + if (len + left == 0) + ssl3_release_read_buffer(s); + return ret; + } + left += bioread; + /* + * reads should *never* span multiple packets for DTLS because the + * underlying transport protocol is message oriented as opposed to + * byte oriented as in the TLS case. + */ + if (SSL_IS_DTLS(s)) { + if (n > left) + n = left; /* makes the while condition false */ + } + } + + /* done reading, now the book-keeping */ + rb->offset += n; + rb->left = left - n; + s->rlayer.packet_length += n; + s->rwstate = SSL_NOTHING; + *readbytes = n; + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-5535-alpn_select_cb/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2024-5535-alpn_select_cb/fixed.c new file mode 100644 index 0000000..4742f43 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-5535-alpn_select_cb/fixed.c @@ -0,0 +1,36 @@ +/* Provenance: openssl/openssl alpn_select_cb (fixed). + * repo: openssl/openssl + * commit: 6cc511826f09e513b4ec066d9b95acaf4f86d991 + * parent: 015255851371757d54c2560643eb3b3a88123cf1 + * commit_url: https://github.com/openssl/openssl/commit/6cc511826f09e513b4ec066d9b95acaf4f86d991 + * cve: CVE-2024-5535 + * license: Apache-2.0 + * function: alpn_select_cb + * relpath: ssl/quic/quic_tserver.c + */ + +static int alpn_select_cb(SSL *ssl, const unsigned char **out, + unsigned char *outlen, const unsigned char *in, + unsigned int inlen, void *arg) +{ + QUIC_TSERVER *srv = arg; + static const unsigned char alpndeflt[] = { + 8, 'o', 's', 's', 'l', 't', 'e', 's', 't' + }; + static const unsigned char *alpn; + size_t alpnlen; + + if (srv->args.alpn == NULL) { + alpn = alpndeflt; + alpnlen = sizeof(alpndeflt); + } else { + alpn = srv->args.alpn; + alpnlen = srv->args.alpnlen; + } + + if (SSL_select_next_proto((unsigned char **)out, outlen, alpn, alpnlen, + in, inlen) != OPENSSL_NPN_NEGOTIATED) + return SSL_TLSEXT_ERR_ALERT_FATAL; + + return SSL_TLSEXT_ERR_OK; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-5535-alpn_select_cb/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2024-5535-alpn_select_cb/vuln.c new file mode 100644 index 0000000..4e821da --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-5535-alpn_select_cb/vuln.c @@ -0,0 +1,36 @@ +/* Provenance: openssl/openssl alpn_select_cb (vuln). + * repo: openssl/openssl + * commit: 015255851371757d54c2560643eb3b3a88123cf1 + * parent: 015255851371757d54c2560643eb3b3a88123cf1 + * commit_url: https://github.com/openssl/openssl/commit/6cc511826f09e513b4ec066d9b95acaf4f86d991 + * cve: CVE-2024-5535 + * license: Apache-2.0 + * function: alpn_select_cb + * relpath: ssl/quic/quic_tserver.c + */ + +static int alpn_select_cb(SSL *ssl, const unsigned char **out, + unsigned char *outlen, const unsigned char *in, + unsigned int inlen, void *arg) +{ + QUIC_TSERVER *srv = arg; + static const unsigned char alpndeflt[] = { + 8, 'o', 's', 's', 'l', 't', 'e', 's', 't' + }; + static const unsigned char *alpn; + size_t alpnlen; + + if (srv->args.alpn == NULL) { + alpn = alpndeflt; + alpnlen = sizeof(alpn); + } else { + alpn = srv->args.alpn; + alpnlen = srv->args.alpnlen; + } + + if (SSL_select_next_proto((unsigned char **)out, outlen, alpn, alpnlen, + in, inlen) != OPENSSL_NPN_NEGOTIATED) + return SSL_TLSEXT_ERR_ALERT_FATAL; + + return SSL_TLSEXT_ERR_OK; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-5535-ssl_select_next_proto/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2024-5535-ssl_select_next_proto/fixed.c new file mode 100644 index 0000000..2e6bd36 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-5535-ssl_select_next_proto/fixed.c @@ -0,0 +1,65 @@ +/* Provenance: openssl/openssl SSL_select_next_proto (fixed). + * repo: openssl/openssl + * commit: cf6f91f6121f4db167405db2f0de410a456f260c + * parent: a6facb1042adda2394dc5c98fbceb7625eef141a + * commit_url: https://github.com/openssl/openssl/commit/cf6f91f6121f4db167405db2f0de410a456f260c + * cve: CVE-2024-5535 + * license: Apache-2.0 + * function: SSL_select_next_proto + * relpath: ssl/ssl_lib.c + */ + +int SSL_select_next_proto(unsigned char **out, unsigned char *outlen, + const unsigned char *server, + unsigned int server_len, + const unsigned char *client, unsigned int client_len) +{ + PACKET cpkt, csubpkt, spkt, ssubpkt; + + if (!PACKET_buf_init(&cpkt, client, client_len) + || !PACKET_get_length_prefixed_1(&cpkt, &csubpkt) + || PACKET_remaining(&csubpkt) == 0) { + *out = NULL; + *outlen = 0; + return OPENSSL_NPN_NO_OVERLAP; + } + + /* + * Set the default opportunistic protocol. Will be overwritten if we find + * a match. + */ + *out = (unsigned char *)PACKET_data(&csubpkt); + *outlen = (unsigned char)PACKET_remaining(&csubpkt); + + /* + * For each protocol in server preference order, see if we support it. + */ + if (PACKET_buf_init(&spkt, server, server_len)) { + while (PACKET_get_length_prefixed_1(&spkt, &ssubpkt)) { + if (PACKET_remaining(&ssubpkt) == 0) + continue; /* Invalid - ignore it */ + if (PACKET_buf_init(&cpkt, client, client_len)) { + while (PACKET_get_length_prefixed_1(&cpkt, &csubpkt)) { + if (PACKET_equal(&csubpkt, PACKET_data(&ssubpkt), + PACKET_remaining(&ssubpkt))) { + /* We found a match */ + *out = (unsigned char *)PACKET_data(&ssubpkt); + *outlen = (unsigned char)PACKET_remaining(&ssubpkt); + return OPENSSL_NPN_NEGOTIATED; + } + } + /* Ignore spurious trailing bytes in the client list */ + } else { + /* This should never happen */ + return OPENSSL_NPN_NO_OVERLAP; + } + } + /* Ignore spurious trailing bytes in the server list */ + } + + /* + * There's no overlap between our protocols and the server's list. We use + * the default opportunistic protocol selected earlier + */ + return OPENSSL_NPN_NO_OVERLAP; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-5535-ssl_select_next_proto/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2024-5535-ssl_select_next_proto/vuln.c new file mode 100644 index 0000000..6d1548d --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-5535-ssl_select_next_proto/vuln.c @@ -0,0 +1,48 @@ +/* Provenance: openssl/openssl SSL_select_next_proto (vuln). + * repo: openssl/openssl + * commit: a6facb1042adda2394dc5c98fbceb7625eef141a + * parent: a6facb1042adda2394dc5c98fbceb7625eef141a + * commit_url: https://github.com/openssl/openssl/commit/cf6f91f6121f4db167405db2f0de410a456f260c + * cve: CVE-2024-5535 + * license: Apache-2.0 + * function: SSL_select_next_proto + * relpath: ssl/ssl_lib.c + */ + +int SSL_select_next_proto(unsigned char **out, unsigned char *outlen, + const unsigned char *server, + unsigned int server_len, + const unsigned char *client, unsigned int client_len) +{ + unsigned int i, j; + const unsigned char *result; + int status = OPENSSL_NPN_UNSUPPORTED; + + /* + * For each protocol in server preference order, see if we support it. + */ + for (i = 0; i < server_len;) { + for (j = 0; j < client_len;) { + if (server[i] == client[j] && + memcmp(&server[i + 1], &client[j + 1], server[i]) == 0) { + /* We found a match */ + result = &server[i]; + status = OPENSSL_NPN_NEGOTIATED; + goto found; + } + j += client[j]; + j++; + } + i += server[i]; + i++; + } + + /* There's no overlap between our protocols and the server's list. */ + result = client; + status = OPENSSL_NPN_NO_OVERLAP; + + found: + *out = (unsigned char *)result + 1; + *outlen = result[0]; + return status; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-5535-tls_construct_stoc_next_/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2024-5535-tls_construct_stoc_next_/fixed.c new file mode 100644 index 0000000..9cbe345 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-5535-tls_construct_stoc_next_/fixed.c @@ -0,0 +1,38 @@ +/* Provenance: openssl/openssl tls_construct_stoc_next_proto_neg (fixed). + * repo: openssl/openssl + * commit: 189a7ed3e380e34ea38fe4190a7c9396bace0fb7 + * parent: 72394c9a1a6a6b07edf43eb2ad7e95e1093ada1b + * commit_url: https://github.com/openssl/openssl/commit/189a7ed3e380e34ea38fe4190a7c9396bace0fb7 + * cve: CVE-2024-5535 + * license: Apache-2.0 + * function: tls_construct_stoc_next_proto_neg + * relpath: ssl/statem/extensions_srvr.c + */ + +EXT_RETURN tls_construct_stoc_next_proto_neg(SSL *s, WPACKET *pkt, + unsigned int context, X509 *x, + size_t chainidx) +{ + const unsigned char *npa; + unsigned int npalen; + int ret; + int npn_seen = s->s3.npn_seen; + + s->s3.npn_seen = 0; + if (!npn_seen || s->ctx->ext.npn_advertised_cb == NULL) + return EXT_RETURN_NOT_SENT; + + ret = s->ctx->ext.npn_advertised_cb(s, &npa, &npalen, + s->ctx->ext.npn_advertised_cb_arg); + if (ret == SSL_TLSEXT_ERR_OK) { + if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_next_proto_neg) + || !WPACKET_sub_memcpy_u16(pkt, npa, npalen)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return EXT_RETURN_FAIL; + } + s->s3.npn_seen = 1; + return EXT_RETURN_SENT; + } + + return EXT_RETURN_NOT_SENT; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-5535-tls_construct_stoc_next_/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2024-5535-tls_construct_stoc_next_/vuln.c new file mode 100644 index 0000000..83f4f0e --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-5535-tls_construct_stoc_next_/vuln.c @@ -0,0 +1,37 @@ +/* Provenance: openssl/openssl tls_construct_stoc_next_proto_neg (vuln). + * repo: openssl/openssl + * commit: 72394c9a1a6a6b07edf43eb2ad7e95e1093ada1b + * parent: 72394c9a1a6a6b07edf43eb2ad7e95e1093ada1b + * commit_url: https://github.com/openssl/openssl/commit/189a7ed3e380e34ea38fe4190a7c9396bace0fb7 + * cve: CVE-2024-5535 + * license: Apache-2.0 + * function: tls_construct_stoc_next_proto_neg + * relpath: ssl/statem/extensions_srvr.c + */ + +EXT_RETURN tls_construct_stoc_next_proto_neg(SSL *s, WPACKET *pkt, + unsigned int context, X509 *x, + size_t chainidx) +{ + const unsigned char *npa; + unsigned int npalen; + int ret; + int npn_seen = s->s3.npn_seen; + + s->s3.npn_seen = 0; + if (!npn_seen || s->ctx->ext.npn_advertised_cb == NULL) + return EXT_RETURN_NOT_SENT; + + ret = s->ctx->ext.npn_advertised_cb(s, &npa, &npalen, + s->ctx->ext.npn_advertised_cb_arg); + if (ret == SSL_TLSEXT_ERR_OK) { + if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_next_proto_neg) + || !WPACKET_sub_memcpy_u16(pkt, npa, npalen)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return EXT_RETURN_FAIL; + } + s->s3.npn_seen = 1; + } + + return EXT_RETURN_SENT; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-5535-tls_parse_stoc_npn/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2024-5535-tls_parse_stoc_npn/fixed.c new file mode 100644 index 0000000..e9eeaa9 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-5535-tls_parse_stoc_npn/fixed.c @@ -0,0 +1,62 @@ +/* Provenance: openssl/openssl tls_parse_stoc_npn (fixed). + * repo: openssl/openssl + * commit: 159921152fd4aa91e4c849fd281ad93ac0d0d0ba + * parent: cf6f91f6121f4db167405db2f0de410a456f260c + * commit_url: https://github.com/openssl/openssl/commit/159921152fd4aa91e4c849fd281ad93ac0d0d0ba + * cve: CVE-2024-5535 + * license: Apache-2.0 + * function: tls_parse_stoc_npn + * relpath: ssl/statem/extensions_clnt.c + */ + +int tls_parse_stoc_npn(SSL *s, PACKET *pkt, unsigned int context, X509 *x, + size_t chainidx) +{ + unsigned char *selected; + unsigned char selected_len; + PACKET tmppkt; + + /* Check if we are in a renegotiation. If so ignore this extension */ + if (!SSL_IS_FIRST_HANDSHAKE(s)) + return 1; + + /* We must have requested it. */ + if (s->ctx->ext.npn_select_cb == NULL) { + SSLfatal(s, SSL_AD_UNSUPPORTED_EXTENSION, SSL_R_BAD_EXTENSION); + return 0; + } + + /* The data must be valid */ + tmppkt = *pkt; + if (!ssl_next_proto_validate(s, &tmppkt)) { + /* SSLfatal() already called */ + return 0; + } + if (s->ctx->ext.npn_select_cb(s, &selected, &selected_len, + PACKET_data(pkt), + PACKET_remaining(pkt), + s->ctx->ext.npn_select_cb_arg) != + SSL_TLSEXT_ERR_OK + || selected_len == 0) { + SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_R_BAD_EXTENSION); + return 0; + } + + /* + * Could be non-NULL if server has sent multiple NPN extensions in + * a single Serverhello + */ + OPENSSL_free(s->ext.npn); + s->ext.npn = OPENSSL_malloc(selected_len); + if (s->ext.npn == NULL) { + s->ext.npn_len = 0; + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + + memcpy(s->ext.npn, selected, selected_len); + s->ext.npn_len = selected_len; + s->s3.npn_seen = 1; + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-5535-tls_parse_stoc_npn/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2024-5535-tls_parse_stoc_npn/vuln.c new file mode 100644 index 0000000..690cc27 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-5535-tls_parse_stoc_npn/vuln.c @@ -0,0 +1,61 @@ +/* Provenance: openssl/openssl tls_parse_stoc_npn (vuln). + * repo: openssl/openssl + * commit: cf6f91f6121f4db167405db2f0de410a456f260c + * parent: cf6f91f6121f4db167405db2f0de410a456f260c + * commit_url: https://github.com/openssl/openssl/commit/159921152fd4aa91e4c849fd281ad93ac0d0d0ba + * cve: CVE-2024-5535 + * license: Apache-2.0 + * function: tls_parse_stoc_npn + * relpath: ssl/statem/extensions_clnt.c + */ + +int tls_parse_stoc_npn(SSL *s, PACKET *pkt, unsigned int context, X509 *x, + size_t chainidx) +{ + unsigned char *selected; + unsigned char selected_len; + PACKET tmppkt; + + /* Check if we are in a renegotiation. If so ignore this extension */ + if (!SSL_IS_FIRST_HANDSHAKE(s)) + return 1; + + /* We must have requested it. */ + if (s->ctx->ext.npn_select_cb == NULL) { + SSLfatal(s, SSL_AD_UNSUPPORTED_EXTENSION, SSL_R_BAD_EXTENSION); + return 0; + } + + /* The data must be valid */ + tmppkt = *pkt; + if (!ssl_next_proto_validate(s, &tmppkt)) { + /* SSLfatal() already called */ + return 0; + } + if (s->ctx->ext.npn_select_cb(s, &selected, &selected_len, + PACKET_data(pkt), + PACKET_remaining(pkt), + s->ctx->ext.npn_select_cb_arg) != + SSL_TLSEXT_ERR_OK) { + SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_R_BAD_EXTENSION); + return 0; + } + + /* + * Could be non-NULL if server has sent multiple NPN extensions in + * a single Serverhello + */ + OPENSSL_free(s->ext.npn); + s->ext.npn = OPENSSL_malloc(selected_len); + if (s->ext.npn == NULL) { + s->ext.npn_len = 0; + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + + memcpy(s->ext.npn, selected, selected_len); + s->ext.npn_len = selected_len; + s->s3.npn_seen = 1; + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-5535/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2024-5535/fixed.c new file mode 100644 index 0000000..81bfe43 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-5535/fixed.c @@ -0,0 +1,98 @@ +/* Provenance: openssl/openssl tls_parse_stoc_alpn (fixed). + * repo: openssl/openssl + * commit: 4b375b998798dd516d367036773073e1b88e6433 + * parent: 189a7ed3e380e34ea38fe4190a7c9396bace0fb7 + * commit_url: https://github.com/openssl/openssl/commit/4b375b998798dd516d367036773073e1b88e6433 + * cve: CVE-2024-5535 + * license: Apache-2.0 + * function: tls_parse_stoc_alpn + * relpath: ssl/statem/extensions_clnt.c + */ + +int tls_parse_stoc_alpn(SSL *s, PACKET *pkt, unsigned int context, X509 *x, + size_t chainidx) +{ + size_t len; + PACKET confpkt, protpkt; + int valid = 0; + + /* We must have requested it. */ + if (!s->s3.alpn_sent) { + SSLfatal(s, SSL_AD_UNSUPPORTED_EXTENSION, SSL_R_BAD_EXTENSION); + return 0; + } + /*- + * The extension data consists of: + * uint16 list_length + * uint8 proto_length; + * uint8 proto[proto_length]; + */ + if (!PACKET_get_net_2_len(pkt, &len) + || PACKET_remaining(pkt) != len || !PACKET_get_1_len(pkt, &len) + || PACKET_remaining(pkt) != len) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION); + return 0; + } + + /* It must be a protocol that we sent */ + if (!PACKET_buf_init(&confpkt, s->ext.alpn, s->ext.alpn_len)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + while (PACKET_get_length_prefixed_1(&confpkt, &protpkt)) { + if (PACKET_remaining(&protpkt) != len) + continue; + if (memcmp(PACKET_data(pkt), PACKET_data(&protpkt), len) == 0) { + /* Valid protocol found */ + valid = 1; + break; + } + } + + if (!valid) { + /* The protocol sent from the server does not match one we advertised */ + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION); + return 0; + } + + OPENSSL_free(s->s3.alpn_selected); + s->s3.alpn_selected = OPENSSL_malloc(len); + if (s->s3.alpn_selected == NULL) { + s->s3.alpn_selected_len = 0; + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + if (!PACKET_copy_bytes(pkt, s->s3.alpn_selected, len)) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION); + return 0; + } + s->s3.alpn_selected_len = len; + + if (s->session->ext.alpn_selected == NULL + || s->session->ext.alpn_selected_len != len + || memcmp(s->session->ext.alpn_selected, s->s3.alpn_selected, len) + != 0) { + /* ALPN not consistent with the old session so cannot use early_data */ + s->ext.early_data_ok = 0; + } + if (!s->hit) { + /* + * This is a new session and so alpn_selected should have been + * initialised to NULL. We should update it with the selected ALPN. + */ + if (!ossl_assert(s->session->ext.alpn_selected == NULL)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + s->session->ext.alpn_selected = + OPENSSL_memdup(s->s3.alpn_selected, s->s3.alpn_selected_len); + if (s->session->ext.alpn_selected == NULL) { + s->session->ext.alpn_selected_len = 0; + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + s->session->ext.alpn_selected_len = s->s3.alpn_selected_len; + } + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-5535/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2024-5535/vuln.c new file mode 100644 index 0000000..64526c1 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-5535/vuln.c @@ -0,0 +1,74 @@ +/* Provenance: openssl/openssl tls_parse_stoc_alpn (vuln). + * repo: openssl/openssl + * commit: 189a7ed3e380e34ea38fe4190a7c9396bace0fb7 + * parent: 189a7ed3e380e34ea38fe4190a7c9396bace0fb7 + * commit_url: https://github.com/openssl/openssl/commit/4b375b998798dd516d367036773073e1b88e6433 + * cve: CVE-2024-5535 + * license: Apache-2.0 + * function: tls_parse_stoc_alpn + * relpath: ssl/statem/extensions_clnt.c + */ + +int tls_parse_stoc_alpn(SSL *s, PACKET *pkt, unsigned int context, X509 *x, + size_t chainidx) +{ + size_t len; + + /* We must have requested it. */ + if (!s->s3.alpn_sent) { + SSLfatal(s, SSL_AD_UNSUPPORTED_EXTENSION, SSL_R_BAD_EXTENSION); + return 0; + } + /*- + * The extension data consists of: + * uint16 list_length + * uint8 proto_length; + * uint8 proto[proto_length]; + */ + if (!PACKET_get_net_2_len(pkt, &len) + || PACKET_remaining(pkt) != len || !PACKET_get_1_len(pkt, &len) + || PACKET_remaining(pkt) != len) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION); + return 0; + } + OPENSSL_free(s->s3.alpn_selected); + s->s3.alpn_selected = OPENSSL_malloc(len); + if (s->s3.alpn_selected == NULL) { + s->s3.alpn_selected_len = 0; + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + if (!PACKET_copy_bytes(pkt, s->s3.alpn_selected, len)) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION); + return 0; + } + s->s3.alpn_selected_len = len; + + if (s->session->ext.alpn_selected == NULL + || s->session->ext.alpn_selected_len != len + || memcmp(s->session->ext.alpn_selected, s->s3.alpn_selected, len) + != 0) { + /* ALPN not consistent with the old session so cannot use early_data */ + s->ext.early_data_ok = 0; + } + if (!s->hit) { + /* + * This is a new session and so alpn_selected should have been + * initialised to NULL. We should update it with the selected ALPN. + */ + if (!ossl_assert(s->session->ext.alpn_selected == NULL)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + s->session->ext.alpn_selected = + OPENSSL_memdup(s->s3.alpn_selected, s->s3.alpn_selected_len); + if (s->session->ext.alpn_selected == NULL) { + s->session->ext.alpn_selected_len = 0; + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + s->session->ext.alpn_selected_len = s->s3.alpn_selected_len; + } + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-6119/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2024-6119/fixed.c new file mode 100644 index 0000000..5c57f81 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-6119/fixed.c @@ -0,0 +1,141 @@ +/* Provenance: openssl/openssl do_x509_check (fixed). + * repo: openssl/openssl + * commit: 06d1dc3fa96a2ba5a3e22735a033012aadc9f0d6 + * parent: 9aae56395aa8e77c44a9df83fd395a644d016635 + * commit_url: https://github.com/openssl/openssl/commit/06d1dc3fa96a2ba5a3e22735a033012aadc9f0d6 + * cve: CVE-2024-6119 + * license: Apache-2.0 + * function: do_x509_check + * relpath: crypto/x509/v3_utl.c + */ + +static int do_x509_check(X509 *x, const char *chk, size_t chklen, + unsigned int flags, int check_type, char **peername) +{ + GENERAL_NAMES *gens = NULL; + const X509_NAME *name = NULL; + int i; + int cnid = NID_undef; + int alt_type; + int san_present = 0; + int rv = 0; + equal_fn equal; + + /* See below, this flag is internal-only */ + flags &= ~_X509_CHECK_FLAG_DOT_SUBDOMAINS; + if (check_type == GEN_EMAIL) { + cnid = NID_pkcs9_emailAddress; + alt_type = V_ASN1_IA5STRING; + equal = equal_email; + } else if (check_type == GEN_DNS) { + cnid = NID_commonName; + /* Implicit client-side DNS sub-domain pattern */ + if (chklen > 1 && chk[0] == '.') + flags |= _X509_CHECK_FLAG_DOT_SUBDOMAINS; + alt_type = V_ASN1_IA5STRING; + if (flags & X509_CHECK_FLAG_NO_WILDCARDS) + equal = equal_nocase; + else + equal = equal_wildcard; + } else { + alt_type = V_ASN1_OCTET_STRING; + equal = equal_case; + } + + if (chklen == 0) + chklen = strlen(chk); + + gens = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL); + if (gens) { + for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) { + GENERAL_NAME *gen; + ASN1_STRING *cstr; + + gen = sk_GENERAL_NAME_value(gens, i); + switch (gen->type) { + default: + continue; + case GEN_OTHERNAME: + switch (OBJ_obj2nid(gen->d.otherName->type_id)) { + default: + continue; + case NID_id_on_SmtpUTF8Mailbox: + /*- + * https://datatracker.ietf.org/doc/html/rfc8398#section-3 + * + * Due to name constraint compatibility reasons described + * in Section 6, SmtpUTF8Mailbox subjectAltName MUST NOT + * be used unless the local-part of the email address + * contains non-ASCII characters. When the local-part is + * ASCII, rfc822Name subjectAltName MUST be used instead + * of SmtpUTF8Mailbox. This is compatible with legacy + * software that supports only rfc822Name (and not + * SmtpUTF8Mailbox). [...] + * + * SmtpUTF8Mailbox is encoded as UTF8String. + * + * If it is not a UTF8String then that is unexpected, and + * we ignore the invalid SAN (neither set san_present nor + * consider it a candidate for equality). This does mean + * that the subject CN may be considered, as would be the + * case when the malformed SmtpUtf8Mailbox SAN is instead + * simply absent. + * + * When CN-ID matching is not desirable, applications can + * choose to turn it off, doing so is at this time a best + * practice. + */ + if (check_type != GEN_EMAIL + || gen->d.otherName->value->type != V_ASN1_UTF8STRING) + continue; + alt_type = 0; + cstr = gen->d.otherName->value->value.utf8string; + break; + } + break; + case GEN_EMAIL: + if (check_type != GEN_EMAIL) + continue; + cstr = gen->d.rfc822Name; + break; + case GEN_DNS: + if (check_type != GEN_DNS) + continue; + cstr = gen->d.dNSName; + break; + case GEN_IPADD: + if (check_type != GEN_IPADD) + continue; + cstr = gen->d.iPAddress; + break; + } + san_present = 1; + /* Positive on success, negative on error! */ + if ((rv = do_check_string(cstr, alt_type, equal, flags, + chk, chklen, peername)) != 0) + break; + } + GENERAL_NAMES_free(gens); + if (rv != 0) + return rv; + if (san_present && !(flags & X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT)) + return 0; + } + + /* We're done if CN-ID is not pertinent */ + if (cnid == NID_undef || (flags & X509_CHECK_FLAG_NEVER_CHECK_SUBJECT)) + return 0; + + i = -1; + name = X509_get_subject_name(x); + while ((i = X509_NAME_get_index_by_NID(name, cnid, i)) >= 0) { + const X509_NAME_ENTRY *ne = X509_NAME_get_entry(name, i); + const ASN1_STRING *str = X509_NAME_ENTRY_get_data(ne); + + /* Positive on success, negative on error! */ + if ((rv = do_check_string(str, -1, equal, flags, + chk, chklen, peername)) != 0) + return rv; + } + return 0; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2024-6119/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2024-6119/vuln.c new file mode 100644 index 0000000..98aea68 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2024-6119/vuln.c @@ -0,0 +1,113 @@ +/* Provenance: openssl/openssl do_x509_check (vuln). + * repo: openssl/openssl + * commit: 9aae56395aa8e77c44a9df83fd395a644d016635 + * parent: 9aae56395aa8e77c44a9df83fd395a644d016635 + * commit_url: https://github.com/openssl/openssl/commit/06d1dc3fa96a2ba5a3e22735a033012aadc9f0d6 + * cve: CVE-2024-6119 + * license: Apache-2.0 + * function: do_x509_check + * relpath: crypto/x509/v3_utl.c + */ + +static int do_x509_check(X509 *x, const char *chk, size_t chklen, + unsigned int flags, int check_type, char **peername) +{ + GENERAL_NAMES *gens = NULL; + const X509_NAME *name = NULL; + int i; + int cnid = NID_undef; + int alt_type; + int san_present = 0; + int rv = 0; + equal_fn equal; + + /* See below, this flag is internal-only */ + flags &= ~_X509_CHECK_FLAG_DOT_SUBDOMAINS; + if (check_type == GEN_EMAIL) { + cnid = NID_pkcs9_emailAddress; + alt_type = V_ASN1_IA5STRING; + equal = equal_email; + } else if (check_type == GEN_DNS) { + cnid = NID_commonName; + /* Implicit client-side DNS sub-domain pattern */ + if (chklen > 1 && chk[0] == '.') + flags |= _X509_CHECK_FLAG_DOT_SUBDOMAINS; + alt_type = V_ASN1_IA5STRING; + if (flags & X509_CHECK_FLAG_NO_WILDCARDS) + equal = equal_nocase; + else + equal = equal_wildcard; + } else { + alt_type = V_ASN1_OCTET_STRING; + equal = equal_case; + } + + if (chklen == 0) + chklen = strlen(chk); + + gens = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL); + if (gens) { + for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) { + GENERAL_NAME *gen; + ASN1_STRING *cstr; + + gen = sk_GENERAL_NAME_value(gens, i); + if ((gen->type == GEN_OTHERNAME) && (check_type == GEN_EMAIL)) { + if (OBJ_obj2nid(gen->d.otherName->type_id) == + NID_id_on_SmtpUTF8Mailbox) { + san_present = 1; + + /* + * If it is not a UTF8String then that is unexpected and we + * treat it as no match + */ + if (gen->d.otherName->value->type == V_ASN1_UTF8STRING) { + cstr = gen->d.otherName->value->value.utf8string; + + /* Positive on success, negative on error! */ + if ((rv = do_check_string(cstr, 0, equal, flags, + chk, chklen, peername)) != 0) + break; + } + } else + continue; + } else { + if ((gen->type != check_type) && (gen->type != GEN_OTHERNAME)) + continue; + } + san_present = 1; + if (check_type == GEN_EMAIL) + cstr = gen->d.rfc822Name; + else if (check_type == GEN_DNS) + cstr = gen->d.dNSName; + else + cstr = gen->d.iPAddress; + /* Positive on success, negative on error! */ + if ((rv = do_check_string(cstr, alt_type, equal, flags, + chk, chklen, peername)) != 0) + break; + } + GENERAL_NAMES_free(gens); + if (rv != 0) + return rv; + if (san_present && !(flags & X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT)) + return 0; + } + + /* We're done if CN-ID is not pertinent */ + if (cnid == NID_undef || (flags & X509_CHECK_FLAG_NEVER_CHECK_SUBJECT)) + return 0; + + i = -1; + name = X509_get_subject_name(x); + while ((i = X509_NAME_get_index_by_NID(name, cnid, i)) >= 0) { + const X509_NAME_ENTRY *ne = X509_NAME_get_entry(name, i); + const ASN1_STRING *str = X509_NAME_ENTRY_get_data(ne); + + /* Positive on success, negative on error! */ + if ((rv = do_check_string(str, -1, equal, flags, + chk, chklen, peername)) != 0) + return rv; + } + return 0; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2025-11187/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2025-11187/fixed.c new file mode 100644 index 0000000..1df1d23 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2025-11187/fixed.c @@ -0,0 +1,72 @@ +/* Provenance: openssl/openssl PBMAC1_PBKDF2_HMAC (fixed). + * repo: openssl/openssl + * commit: 205e3a55e16e4bd08c12fdbd3416ab829c0f6206 + * parent: b8654779e3b3b4eb0bda7623c0891d394e068187 + * commit_url: https://github.com/openssl/openssl/commit/205e3a55e16e4bd08c12fdbd3416ab829c0f6206 + * cve: CVE-2025-11187 + * license: Apache-2.0 + * function: PBMAC1_PBKDF2_HMAC + * relpath: crypto/pkcs12/p12_mutl.c + */ + +static int PBMAC1_PBKDF2_HMAC(OSSL_LIB_CTX *ctx, const char *propq, + const char *pass, int passlen, + const X509_ALGOR *macalg, unsigned char *key) +{ + PBKDF2PARAM *pbkdf2_param = NULL; + const ASN1_OBJECT *kdf_hmac_oid; + int kdf_hmac_nid; + int ret = -1; + int keylen = 0; + EVP_MD *kdf_md = NULL; + const ASN1_OCTET_STRING *pbkdf2_salt = NULL; + + pbkdf2_param = PBMAC1_get1_pbkdf2_param(macalg); + if (pbkdf2_param == NULL) { + ERR_raise(ERR_LIB_PKCS12, ERR_R_UNSUPPORTED); + goto err; + } + + if (pbkdf2_param->prf == NULL) { + kdf_hmac_nid = NID_hmacWithSHA1; + } else { + X509_ALGOR_get0(&kdf_hmac_oid, NULL, NULL, pbkdf2_param->prf); + kdf_hmac_nid = OBJ_obj2nid(kdf_hmac_oid); + } + + kdf_md = EVP_MD_fetch(ctx, OBJ_nid2sn(ossl_hmac2mdnid(kdf_hmac_nid)), propq); + if (kdf_md == NULL) { + ERR_raise(ERR_LIB_PKCS12, ERR_R_FETCH_FAILED); + goto err; + } + + /* Validate salt is an OCTET STRING choice */ + if (pbkdf2_param->salt == NULL + || pbkdf2_param->salt->type != V_ASN1_OCTET_STRING) { + ERR_raise(ERR_LIB_PKCS12, PKCS12_R_PARSE_ERROR); + goto err; + } + pbkdf2_salt = pbkdf2_param->salt->value.octet_string; + + /* RFC 9579 specifies missing key length as invalid */ + if (pbkdf2_param->keylength != NULL) + keylen = ASN1_INTEGER_get(pbkdf2_param->keylength); + if (keylen <= 0 || keylen > EVP_MAX_MD_SIZE) { + ERR_raise(ERR_LIB_PKCS12, PKCS12_R_PARSE_ERROR); + goto err; + } + + if (PKCS5_PBKDF2_HMAC(pass, passlen, pbkdf2_salt->data, pbkdf2_salt->length, + ASN1_INTEGER_get(pbkdf2_param->iter), kdf_md, keylen, key) + <= 0) { + ERR_raise(ERR_LIB_PKCS12, ERR_R_INTERNAL_ERROR); + goto err; + } + ret = keylen; + +err: + EVP_MD_free(kdf_md); + PBKDF2PARAM_free(pbkdf2_param); + + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2025-11187/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2025-11187/vuln.c new file mode 100644 index 0000000..ad5696e --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2025-11187/vuln.c @@ -0,0 +1,58 @@ +/* Provenance: openssl/openssl PBMAC1_PBKDF2_HMAC (vuln). + * repo: openssl/openssl + * commit: b8654779e3b3b4eb0bda7623c0891d394e068187 + * parent: b8654779e3b3b4eb0bda7623c0891d394e068187 + * commit_url: https://github.com/openssl/openssl/commit/205e3a55e16e4bd08c12fdbd3416ab829c0f6206 + * cve: CVE-2025-11187 + * license: Apache-2.0 + * function: PBMAC1_PBKDF2_HMAC + * relpath: crypto/pkcs12/p12_mutl.c + */ + +static int PBMAC1_PBKDF2_HMAC(OSSL_LIB_CTX *ctx, const char *propq, + const char *pass, int passlen, + const X509_ALGOR *macalg, unsigned char *key) +{ + PBKDF2PARAM *pbkdf2_param = NULL; + const ASN1_OBJECT *kdf_hmac_oid; + int kdf_hmac_nid; + int ret = -1; + int keylen = 0; + EVP_MD *kdf_md = NULL; + const ASN1_OCTET_STRING *pbkdf2_salt = NULL; + + pbkdf2_param = PBMAC1_get1_pbkdf2_param(macalg); + if (pbkdf2_param == NULL) { + ERR_raise(ERR_LIB_PKCS12, ERR_R_UNSUPPORTED); + goto err; + } + keylen = ASN1_INTEGER_get(pbkdf2_param->keylength); + pbkdf2_salt = pbkdf2_param->salt->value.octet_string; + + if (pbkdf2_param->prf == NULL) { + kdf_hmac_nid = NID_hmacWithSHA1; + } else { + X509_ALGOR_get0(&kdf_hmac_oid, NULL, NULL, pbkdf2_param->prf); + kdf_hmac_nid = OBJ_obj2nid(kdf_hmac_oid); + } + + kdf_md = EVP_MD_fetch(ctx, OBJ_nid2sn(ossl_hmac2mdnid(kdf_hmac_nid)), propq); + if (kdf_md == NULL) { + ERR_raise(ERR_LIB_PKCS12, ERR_R_FETCH_FAILED); + goto err; + } + + if (PKCS5_PBKDF2_HMAC(pass, passlen, pbkdf2_salt->data, pbkdf2_salt->length, + ASN1_INTEGER_get(pbkdf2_param->iter), kdf_md, keylen, key) + <= 0) { + ERR_raise(ERR_LIB_PKCS12, ERR_R_INTERNAL_ERROR); + goto err; + } + ret = keylen; + +err: + EVP_MD_free(kdf_md); + PBKDF2PARAM_free(pbkdf2_param); + + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2025-15467/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2025-15467/fixed.c new file mode 100644 index 0000000..9d8e409 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2025-15467/fixed.c @@ -0,0 +1,30 @@ +/* Provenance: openssl/openssl evp_cipher_get_asn1_aead_params (fixed). + * repo: openssl/openssl + * commit: ce39170276daec87f55c39dad1f629b56344429e + * parent: 3250efdfe99d2d7fe4fb05231add7fba864b7653 + * commit_url: https://github.com/openssl/openssl/commit/ce39170276daec87f55c39dad1f629b56344429e + * cve: CVE-2025-15467 + * license: Apache-2.0 + * function: evp_cipher_get_asn1_aead_params + * relpath: crypto/evp/evp_lib.c + */ + +int evp_cipher_get_asn1_aead_params(EVP_CIPHER_CTX *c, ASN1_TYPE *type, + evp_cipher_aead_asn1_params *asn1_params) +{ + int i = 0; + long tl; + unsigned char iv[EVP_MAX_IV_LENGTH]; + + if (type == NULL || asn1_params == NULL) + return 0; + + i = ossl_asn1_type_get_octetstring_int(type, &tl, iv, EVP_MAX_IV_LENGTH); + if (i <= 0 || i > EVP_MAX_IV_LENGTH) + return -1; + + memcpy(asn1_params->iv, iv, i); + asn1_params->iv_len = i; + + return i; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2025-15467/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2025-15467/vuln.c new file mode 100644 index 0000000..d46854b --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2025-15467/vuln.c @@ -0,0 +1,31 @@ +/* Provenance: openssl/openssl evp_cipher_get_asn1_aead_params (vuln). + * repo: openssl/openssl + * commit: 3250efdfe99d2d7fe4fb05231add7fba864b7653 + * parent: 3250efdfe99d2d7fe4fb05231add7fba864b7653 + * commit_url: https://github.com/openssl/openssl/commit/ce39170276daec87f55c39dad1f629b56344429e + * cve: CVE-2025-15467 + * license: Apache-2.0 + * function: evp_cipher_get_asn1_aead_params + * relpath: crypto/evp/evp_lib.c + */ + +int evp_cipher_get_asn1_aead_params(EVP_CIPHER_CTX *c, ASN1_TYPE *type, + evp_cipher_aead_asn1_params *asn1_params) +{ + int i = 0; + long tl; + unsigned char iv[EVP_MAX_IV_LENGTH]; + + if (type == NULL || asn1_params == NULL) + return 0; + + i = ossl_asn1_type_get_octetstring_int(type, &tl, NULL, EVP_MAX_IV_LENGTH); + if (i <= 0) + return -1; + ossl_asn1_type_get_octetstring_int(type, &tl, iv, i); + + memcpy(asn1_params->iv, iv, i); + asn1_params->iv_len = i; + + return i; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2025-15469/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2025-15469/fixed.c new file mode 100644 index 0000000..95fdd36 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2025-15469/fixed.c @@ -0,0 +1,55 @@ +/* Provenance: openssl/openssl do_fp_oneshot_sign (fixed). + * repo: openssl/openssl + * commit: a7936fa4bd23c906e1955a16a0a0ab39a4953a61 + * parent: 1f08e54bad32843044fe8a675948d65e3b4ece65 + * commit_url: https://github.com/openssl/openssl/commit/a7936fa4bd23c906e1955a16a0a0ab39a4953a61 + * cve: CVE-2025-15469 + * license: Apache-2.0 + * function: do_fp_oneshot_sign + * relpath: apps/dgst.c + */ + +static int do_fp_oneshot_sign(BIO *out, EVP_MD_CTX *ctx, BIO *in, int sep, int binout, + EVP_PKEY *key, unsigned char *sigin, int siglen, + const char *sig_name, const char *file) +{ + int res, ret = EXIT_FAILURE; + size_t len = 0; + size_t buflen = 0; + size_t maxlen = 16 * 1024 * 1024; + uint8_t *buf = NULL, *sig = NULL; + + if (!bio_to_mem(&buf, &buflen, maxlen, in)) { + BIO_printf(bio_err, "Read error in %s\n", file); + return ret; + } + if (sigin != NULL) { + res = EVP_DigestVerify(ctx, sigin, siglen, buf, buflen); + print_verify_result(out, res); + if (res > 0) + ret = EXIT_SUCCESS; + goto end; + } + if (key != NULL) { + if (EVP_DigestSign(ctx, NULL, &len, buf, buflen) != 1) { + BIO_printf(bio_err, "Error getting maximum length of signed data\n"); + goto end; + } + sig = app_malloc(len, "Signature buffer"); + if (EVP_DigestSign(ctx, sig, &len, buf, buflen) != 1) { + BIO_printf(bio_err, "Error signing data\n"); + goto end; + } + print_out(out, sig, len, sep, binout, sig_name, NULL, file); + ret = EXIT_SUCCESS; + } else { + BIO_printf(bio_err, "key must be set for one-shot algorithms\n"); + goto end; + } + +end: + OPENSSL_free(sig); + OPENSSL_clear_free(buf, buflen); + + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2025-15469/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2025-15469/vuln.c new file mode 100644 index 0000000..ceb0bc5 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2025-15469/vuln.c @@ -0,0 +1,56 @@ +/* Provenance: openssl/openssl do_fp_oneshot_sign (vuln). + * repo: openssl/openssl + * commit: 1f08e54bad32843044fe8a675948d65e3b4ece65 + * parent: 1f08e54bad32843044fe8a675948d65e3b4ece65 + * commit_url: https://github.com/openssl/openssl/commit/a7936fa4bd23c906e1955a16a0a0ab39a4953a61 + * cve: CVE-2025-15469 + * license: Apache-2.0 + * function: do_fp_oneshot_sign + * relpath: apps/dgst.c + */ + +static int do_fp_oneshot_sign(BIO *out, EVP_MD_CTX *ctx, BIO *in, int sep, int binout, + EVP_PKEY *key, unsigned char *sigin, int siglen, + const char *sig_name, const char *file) +{ + int res, ret = EXIT_FAILURE; + size_t len = 0; + int buflen = 0; + int maxlen = 16 * 1024 * 1024; + uint8_t *buf = NULL, *sig = NULL; + + buflen = bio_to_mem(&buf, maxlen, in); + if (buflen <= 0) { + BIO_printf(bio_err, "Read error in %s\n", file); + return ret; + } + if (sigin != NULL) { + res = EVP_DigestVerify(ctx, sigin, siglen, buf, buflen); + print_verify_result(out, res); + if (res > 0) + ret = EXIT_SUCCESS; + goto end; + } + if (key != NULL) { + if (EVP_DigestSign(ctx, NULL, &len, buf, buflen) != 1) { + BIO_printf(bio_err, "Error getting maximum length of signed data\n"); + goto end; + } + sig = app_malloc(len, "Signature buffer"); + if (EVP_DigestSign(ctx, sig, &len, buf, buflen) != 1) { + BIO_printf(bio_err, "Error signing data\n"); + goto end; + } + print_out(out, sig, len, sep, binout, sig_name, NULL, file); + ret = EXIT_SUCCESS; + } else { + BIO_printf(bio_err, "key must be set for one-shot algorithms\n"); + goto end; + } + +end: + OPENSSL_free(sig); + OPENSSL_clear_free(buf, buflen); + + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2025-66199-tls13_process_compressed/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2025-66199-tls13_process_compressed/fixed.c new file mode 100644 index 0000000..51009b5 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2025-66199-tls13_process_compressed/fixed.c @@ -0,0 +1,96 @@ +/* Provenance: openssl/openssl tls13_process_compressed_certificate (fixed). + * repo: openssl/openssl + * commit: 3ed1f75249932b155eef993a8e66a99cb98bfef4 + * parent: 384011202af92605d926fafe4a0bcd6b65d162ad + * commit_url: https://github.com/openssl/openssl/commit/3ed1f75249932b155eef993a8e66a99cb98bfef4 + * cve: CVE-2025-66199 + * license: Apache-2.0 + * function: tls13_process_compressed_certificate + * relpath: ssl/statem/statem_lib.c + */ + +MSG_PROCESS_RETURN tls13_process_compressed_certificate(SSL_CONNECTION *sc, + PACKET *pkt, + PACKET *tmppkt, + BUF_MEM *buf) +{ + MSG_PROCESS_RETURN ret = MSG_PROCESS_ERROR; + int comp_alg; + COMP_METHOD *method = NULL; + COMP_CTX *comp = NULL; + size_t expected_length; + size_t comp_length; + int i; + int found = 0; + + if (buf == NULL) { + SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + goto err; + } + if (!PACKET_get_net_2(pkt, (unsigned int *)&comp_alg)) { + SSLfatal(sc, SSL_AD_BAD_CERTIFICATE, ERR_R_INTERNAL_ERROR); + goto err; + } + /* If we have a prefs list, make sure the algorithm is in it */ + if (sc->cert_comp_prefs[0] != TLSEXT_comp_cert_none) { + for (i = 0; sc->cert_comp_prefs[i] != TLSEXT_comp_cert_none; i++) { + if (sc->cert_comp_prefs[i] == comp_alg) { + found = 1; + break; + } + } + if (!found) { + SSLfatal(sc, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BAD_COMPRESSION_ALGORITHM); + goto err; + } + } + if (!ossl_comp_has_alg(comp_alg)) { + SSLfatal(sc, SSL_AD_BAD_CERTIFICATE, SSL_R_BAD_COMPRESSION_ALGORITHM); + goto err; + } + switch (comp_alg) { + case TLSEXT_comp_cert_zlib: + method = COMP_zlib_oneshot(); + break; + case TLSEXT_comp_cert_brotli: + method = COMP_brotli_oneshot(); + break; + case TLSEXT_comp_cert_zstd: + method = COMP_zstd_oneshot(); + break; + default: + SSLfatal(sc, SSL_AD_BAD_CERTIFICATE, SSL_R_BAD_COMPRESSION_ALGORITHM); + goto err; + } + + if ((comp = COMP_CTX_new(method)) == NULL + || !PACKET_get_net_3_len(pkt, &expected_length) + || !PACKET_get_net_3_len(pkt, &comp_length)) { + SSLfatal(sc, SSL_AD_BAD_CERTIFICATE, SSL_R_BAD_DECOMPRESSION); + goto err; + } + + /* Prevent excessive pre-decompression allocation */ + if (expected_length > sc->max_cert_list) { + SSLfatal(sc, SSL_AD_BAD_CERTIFICATE, SSL_R_EXCESSIVE_MESSAGE_SIZE); + goto err; + } + + if (PACKET_remaining(pkt) != comp_length || comp_length == 0) { + SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_DECOMPRESSION); + goto err; + } + + if (!BUF_MEM_grow(buf, expected_length) + || !PACKET_buf_init(tmppkt, (unsigned char *)buf->data, expected_length) + || COMP_expand_block(comp, (unsigned char *)buf->data, expected_length, + (unsigned char *)PACKET_data(pkt), comp_length) + != (int)expected_length) { + SSLfatal(sc, SSL_AD_BAD_CERTIFICATE, SSL_R_BAD_DECOMPRESSION); + goto err; + } + ret = MSG_PROCESS_CONTINUE_PROCESSING; +err: + COMP_CTX_free(comp); + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2025-66199-tls13_process_compressed/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2025-66199-tls13_process_compressed/vuln.c new file mode 100644 index 0000000..2d96825 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2025-66199-tls13_process_compressed/vuln.c @@ -0,0 +1,90 @@ +/* Provenance: openssl/openssl tls13_process_compressed_certificate (vuln). + * repo: openssl/openssl + * commit: 384011202af92605d926fafe4a0bcd6b65d162ad + * parent: 384011202af92605d926fafe4a0bcd6b65d162ad + * commit_url: https://github.com/openssl/openssl/commit/3ed1f75249932b155eef993a8e66a99cb98bfef4 + * cve: CVE-2025-66199 + * license: Apache-2.0 + * function: tls13_process_compressed_certificate + * relpath: ssl/statem/statem_lib.c + */ + +MSG_PROCESS_RETURN tls13_process_compressed_certificate(SSL_CONNECTION *sc, + PACKET *pkt, + PACKET *tmppkt, + BUF_MEM *buf) +{ + MSG_PROCESS_RETURN ret = MSG_PROCESS_ERROR; + int comp_alg; + COMP_METHOD *method = NULL; + COMP_CTX *comp = NULL; + size_t expected_length; + size_t comp_length; + int i; + int found = 0; + + if (buf == NULL) { + SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + goto err; + } + if (!PACKET_get_net_2(pkt, (unsigned int *)&comp_alg)) { + SSLfatal(sc, SSL_AD_BAD_CERTIFICATE, ERR_R_INTERNAL_ERROR); + goto err; + } + /* If we have a prefs list, make sure the algorithm is in it */ + if (sc->cert_comp_prefs[0] != TLSEXT_comp_cert_none) { + for (i = 0; sc->cert_comp_prefs[i] != TLSEXT_comp_cert_none; i++) { + if (sc->cert_comp_prefs[i] == comp_alg) { + found = 1; + break; + } + } + if (!found) { + SSLfatal(sc, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BAD_COMPRESSION_ALGORITHM); + goto err; + } + } + if (!ossl_comp_has_alg(comp_alg)) { + SSLfatal(sc, SSL_AD_BAD_CERTIFICATE, SSL_R_BAD_COMPRESSION_ALGORITHM); + goto err; + } + switch (comp_alg) { + case TLSEXT_comp_cert_zlib: + method = COMP_zlib_oneshot(); + break; + case TLSEXT_comp_cert_brotli: + method = COMP_brotli_oneshot(); + break; + case TLSEXT_comp_cert_zstd: + method = COMP_zstd_oneshot(); + break; + default: + SSLfatal(sc, SSL_AD_BAD_CERTIFICATE, SSL_R_BAD_COMPRESSION_ALGORITHM); + goto err; + } + + if ((comp = COMP_CTX_new(method)) == NULL + || !PACKET_get_net_3_len(pkt, &expected_length) + || !PACKET_get_net_3_len(pkt, &comp_length)) { + SSLfatal(sc, SSL_AD_BAD_CERTIFICATE, SSL_R_BAD_DECOMPRESSION); + goto err; + } + + if (PACKET_remaining(pkt) != comp_length || comp_length == 0) { + SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_DECOMPRESSION); + goto err; + } + + if (!BUF_MEM_grow(buf, expected_length) + || !PACKET_buf_init(tmppkt, (unsigned char *)buf->data, expected_length) + || COMP_expand_block(comp, (unsigned char *)buf->data, expected_length, + (unsigned char *)PACKET_data(pkt), comp_length) + != (int)expected_length) { + SSLfatal(sc, SSL_AD_BAD_CERTIFICATE, SSL_R_BAD_DECOMPRESSION); + goto err; + } + ret = MSG_PROCESS_CONTINUE_PROCESSING; +err: + COMP_CTX_free(comp); + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2025-66199/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2025-66199/fixed.c new file mode 100644 index 0000000..02c6a4a --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2025-66199/fixed.c @@ -0,0 +1,97 @@ +/* Provenance: openssl/openssl tls13_process_compressed_certificate (fixed). + * repo: openssl/openssl + * commit: 84f73f79af9f69c1527a9a372b7a9e771a394c2a + * parent: b21663c35a6f0ed4c8de06855bdc7a6a21f00c2f + * commit_url: https://github.com/openssl/openssl/commit/84f73f79af9f69c1527a9a372b7a9e771a394c2a + * cve: CVE-2025-66199 + * license: Apache-2.0 + * function: tls13_process_compressed_certificate + * relpath: ssl/statem/statem_lib.c + */ + +MSG_PROCESS_RETURN tls13_process_compressed_certificate(SSL_CONNECTION *sc, + PACKET *pkt, + PACKET *tmppkt, + BUF_MEM *buf) +{ + MSG_PROCESS_RETURN ret = MSG_PROCESS_ERROR; + int comp_alg; + COMP_METHOD *method = NULL; + COMP_CTX *comp = NULL; + size_t expected_length; + size_t comp_length; + int i; + int found = 0; + + if (buf == NULL) { + SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + goto err; + } + if (!PACKET_get_net_2(pkt, (unsigned int *)&comp_alg)) { + SSLfatal(sc, SSL_AD_BAD_CERTIFICATE, ERR_R_INTERNAL_ERROR); + goto err; + } + /* If we have a prefs list, make sure the algorithm is in it */ + if (sc->cert_comp_prefs[0] != TLSEXT_comp_cert_none) { + for (i = 0; sc->cert_comp_prefs[i] != TLSEXT_comp_cert_none; i++) { + if (sc->cert_comp_prefs[i] == comp_alg) { + found = 1; + break; + } + } + if (!found) { + SSLfatal(sc, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BAD_COMPRESSION_ALGORITHM); + goto err; + } + } + if (!ossl_comp_has_alg(comp_alg)) { + SSLfatal(sc, SSL_AD_BAD_CERTIFICATE, SSL_R_BAD_COMPRESSION_ALGORITHM); + goto err; + } + switch (comp_alg) { + case TLSEXT_comp_cert_zlib: + method = COMP_zlib_oneshot(); + break; + case TLSEXT_comp_cert_brotli: + method = COMP_brotli_oneshot(); + break; + case TLSEXT_comp_cert_zstd: + method = COMP_zstd_oneshot(); + break; + default: + SSLfatal(sc, SSL_AD_BAD_CERTIFICATE, SSL_R_BAD_COMPRESSION_ALGORITHM); + goto err; + } + + if ((comp = COMP_CTX_new(method)) == NULL + || !PACKET_get_net_3_len(pkt, &expected_length) + || !PACKET_get_net_3_len(pkt, &comp_length)) { + SSLfatal(sc, SSL_AD_BAD_CERTIFICATE, SSL_R_BAD_DECOMPRESSION); + goto err; + } + + /* Prevent excessive pre-decompression allocation */ + if (expected_length > sc->max_cert_list) { + SSLfatal(sc, SSL_AD_BAD_CERTIFICATE, SSL_R_EXCESSIVE_MESSAGE_SIZE); + goto err; + } + + if (PACKET_remaining(pkt) != comp_length || comp_length == 0) { + SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_DECOMPRESSION); + goto err; + } + + if (!BUF_MEM_grow(buf, expected_length) + || !PACKET_buf_init(tmppkt, (unsigned char *)buf->data, expected_length) + || COMP_expand_block(comp, (unsigned char *)buf->data, (int)expected_length, + (unsigned char *)PACKET_data(pkt), + (int)comp_length) + != (int)expected_length) { + SSLfatal(sc, SSL_AD_BAD_CERTIFICATE, SSL_R_BAD_DECOMPRESSION); + goto err; + } + ret = MSG_PROCESS_CONTINUE_PROCESSING; +err: + COMP_CTX_free(comp); + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2025-66199/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2025-66199/vuln.c new file mode 100644 index 0000000..6025234 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2025-66199/vuln.c @@ -0,0 +1,91 @@ +/* Provenance: openssl/openssl tls13_process_compressed_certificate (vuln). + * repo: openssl/openssl + * commit: b21663c35a6f0ed4c8de06855bdc7a6a21f00c2f + * parent: b21663c35a6f0ed4c8de06855bdc7a6a21f00c2f + * commit_url: https://github.com/openssl/openssl/commit/84f73f79af9f69c1527a9a372b7a9e771a394c2a + * cve: CVE-2025-66199 + * license: Apache-2.0 + * function: tls13_process_compressed_certificate + * relpath: ssl/statem/statem_lib.c + */ + +MSG_PROCESS_RETURN tls13_process_compressed_certificate(SSL_CONNECTION *sc, + PACKET *pkt, + PACKET *tmppkt, + BUF_MEM *buf) +{ + MSG_PROCESS_RETURN ret = MSG_PROCESS_ERROR; + int comp_alg; + COMP_METHOD *method = NULL; + COMP_CTX *comp = NULL; + size_t expected_length; + size_t comp_length; + int i; + int found = 0; + + if (buf == NULL) { + SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + goto err; + } + if (!PACKET_get_net_2(pkt, (unsigned int *)&comp_alg)) { + SSLfatal(sc, SSL_AD_BAD_CERTIFICATE, ERR_R_INTERNAL_ERROR); + goto err; + } + /* If we have a prefs list, make sure the algorithm is in it */ + if (sc->cert_comp_prefs[0] != TLSEXT_comp_cert_none) { + for (i = 0; sc->cert_comp_prefs[i] != TLSEXT_comp_cert_none; i++) { + if (sc->cert_comp_prefs[i] == comp_alg) { + found = 1; + break; + } + } + if (!found) { + SSLfatal(sc, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BAD_COMPRESSION_ALGORITHM); + goto err; + } + } + if (!ossl_comp_has_alg(comp_alg)) { + SSLfatal(sc, SSL_AD_BAD_CERTIFICATE, SSL_R_BAD_COMPRESSION_ALGORITHM); + goto err; + } + switch (comp_alg) { + case TLSEXT_comp_cert_zlib: + method = COMP_zlib_oneshot(); + break; + case TLSEXT_comp_cert_brotli: + method = COMP_brotli_oneshot(); + break; + case TLSEXT_comp_cert_zstd: + method = COMP_zstd_oneshot(); + break; + default: + SSLfatal(sc, SSL_AD_BAD_CERTIFICATE, SSL_R_BAD_COMPRESSION_ALGORITHM); + goto err; + } + + if ((comp = COMP_CTX_new(method)) == NULL + || !PACKET_get_net_3_len(pkt, &expected_length) + || !PACKET_get_net_3_len(pkt, &comp_length)) { + SSLfatal(sc, SSL_AD_BAD_CERTIFICATE, SSL_R_BAD_DECOMPRESSION); + goto err; + } + + if (PACKET_remaining(pkt) != comp_length || comp_length == 0) { + SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_DECOMPRESSION); + goto err; + } + + if (!BUF_MEM_grow(buf, expected_length) + || !PACKET_buf_init(tmppkt, (unsigned char *)buf->data, expected_length) + || COMP_expand_block(comp, (unsigned char *)buf->data, (int)expected_length, + (unsigned char *)PACKET_data(pkt), + (int)comp_length) + != (int)expected_length) { + SSLfatal(sc, SSL_AD_BAD_CERTIFICATE, SSL_R_BAD_DECOMPRESSION); + goto err; + } + ret = MSG_PROCESS_CONTINUE_PROCESSING; +err: + COMP_CTX_free(comp); + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2025-68160/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2025-68160/fixed.c new file mode 100644 index 0000000..5ebd7ad --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2025-68160/fixed.c @@ -0,0 +1,125 @@ +/* Provenance: openssl/openssl linebuffer_write (fixed). + * repo: openssl/openssl + * commit: 475c466ef2fbd8fc1df6fae1c3eed9c813fc8ff6 + * parent: e0666f72294691a808443970b654412a6d92fa0f + * commit_url: https://github.com/openssl/openssl/commit/475c466ef2fbd8fc1df6fae1c3eed9c813fc8ff6 + * cve: CVE-2025-68160 + * license: Apache-2.0 + * function: linebuffer_write + * relpath: crypto/bio/bf_lbuf.c + */ + +static int linebuffer_write(BIO *b, const char *in, int inl) +{ + int i, num = 0, foundnl; + BIO_LINEBUFFER_CTX *ctx; + + if ((in == NULL) || (inl <= 0)) + return 0; + ctx = (BIO_LINEBUFFER_CTX *)b->ptr; + if ((ctx == NULL) || (b->next_bio == NULL)) + return 0; + + BIO_clear_retry_flags(b); + + do { + const char *p; + char c; + + for (p = in, c = '\0'; p < in + inl && (c = *p) != '\n'; p++) + ; + if (c == '\n') { + p++; + foundnl = 1; + } else + foundnl = 0; + + /* + * If a NL was found and we already have text in the save buffer, + * concatenate them and write + */ + while ((foundnl || p - in > ctx->obuf_size - ctx->obuf_len) + && ctx->obuf_len > 0) { + int orig_olen = ctx->obuf_len; + + i = ctx->obuf_size - ctx->obuf_len; + if (p - in > 0) { + if (i >= p - in) { + memcpy(&(ctx->obuf[ctx->obuf_len]), in, p - in); + ctx->obuf_len += p - in; + inl -= p - in; + num += p - in; + in = p; + } else { + memcpy(&(ctx->obuf[ctx->obuf_len]), in, i); + ctx->obuf_len += i; + inl -= i; + in += i; + num += i; + } + } + i = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); + if (i <= 0) { + ctx->obuf_len = orig_olen; + BIO_copy_next_retry(b); + + if (i < 0) + return ((num > 0) ? num : i); + if (i == 0) + return num; + } + if (i < ctx->obuf_len) + memmove(ctx->obuf, ctx->obuf + i, ctx->obuf_len - i); + ctx->obuf_len -= i; + } + + /* + * Now that the save buffer is emptied, let's write the input buffer + * if a NL was found and there is anything to write. + */ + if ((foundnl || p - in > ctx->obuf_size) && p - in > 0) { + i = BIO_write(b->next_bio, in, p - in); + if (i <= 0) { + BIO_copy_next_retry(b); + if (i < 0) + return ((num > 0) ? num : i); + if (i == 0) + return num; + } + num += i; + in += i; + inl -= i; + } + } while (foundnl && inl > 0); + /* + * We've written as much as we can. The rest of the input buffer, if + * any, is text that doesn't end with a NL and therefore we need to try + * free up some space in our obuf so we can make forward progress. + */ + while (inl > 0) { + size_t avail = (size_t)ctx->obuf_size - (size_t)ctx->obuf_len; + size_t to_copy; + + if (avail == 0) { + /* Flush buffered data to make room */ + i = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); + if (i <= 0) { + BIO_copy_next_retry(b); + return num > 0 ? num : i; + } + if (i < ctx->obuf_len) + memmove(ctx->obuf, ctx->obuf + i, ctx->obuf_len - i); + ctx->obuf_len -= i; + continue; + } + + to_copy = inl > (int)avail ? avail : (size_t)inl; + memcpy(&(ctx->obuf[ctx->obuf_len]), in, to_copy); + ctx->obuf_len += (int)to_copy; + in += to_copy; + inl -= (int)to_copy; + num += (int)to_copy; + } + + return num; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2025-68160/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2025-68160/vuln.c new file mode 100644 index 0000000..697005b --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2025-68160/vuln.c @@ -0,0 +1,105 @@ +/* Provenance: openssl/openssl linebuffer_write (vuln). + * repo: openssl/openssl + * commit: e0666f72294691a808443970b654412a6d92fa0f + * parent: e0666f72294691a808443970b654412a6d92fa0f + * commit_url: https://github.com/openssl/openssl/commit/475c466ef2fbd8fc1df6fae1c3eed9c813fc8ff6 + * cve: CVE-2025-68160 + * license: Apache-2.0 + * function: linebuffer_write + * relpath: crypto/bio/bf_lbuf.c + */ + +static int linebuffer_write(BIO *b, const char *in, int inl) +{ + int i, num = 0, foundnl; + BIO_LINEBUFFER_CTX *ctx; + + if ((in == NULL) || (inl <= 0)) + return 0; + ctx = (BIO_LINEBUFFER_CTX *)b->ptr; + if ((ctx == NULL) || (b->next_bio == NULL)) + return 0; + + BIO_clear_retry_flags(b); + + do { + const char *p; + char c; + + for (p = in, c = '\0'; p < in + inl && (c = *p) != '\n'; p++) + ; + if (c == '\n') { + p++; + foundnl = 1; + } else + foundnl = 0; + + /* + * If a NL was found and we already have text in the save buffer, + * concatenate them and write + */ + while ((foundnl || p - in > ctx->obuf_size - ctx->obuf_len) + && ctx->obuf_len > 0) { + int orig_olen = ctx->obuf_len; + + i = ctx->obuf_size - ctx->obuf_len; + if (p - in > 0) { + if (i >= p - in) { + memcpy(&(ctx->obuf[ctx->obuf_len]), in, p - in); + ctx->obuf_len += p - in; + inl -= p - in; + num += p - in; + in = p; + } else { + memcpy(&(ctx->obuf[ctx->obuf_len]), in, i); + ctx->obuf_len += i; + inl -= i; + in += i; + num += i; + } + } + i = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); + if (i <= 0) { + ctx->obuf_len = orig_olen; + BIO_copy_next_retry(b); + + if (i < 0) + return ((num > 0) ? num : i); + if (i == 0) + return num; + } + if (i < ctx->obuf_len) + memmove(ctx->obuf, ctx->obuf + i, ctx->obuf_len - i); + ctx->obuf_len -= i; + } + + /* + * Now that the save buffer is emptied, let's write the input buffer + * if a NL was found and there is anything to write. + */ + if ((foundnl || p - in > ctx->obuf_size) && p - in > 0) { + i = BIO_write(b->next_bio, in, p - in); + if (i <= 0) { + BIO_copy_next_retry(b); + if (i < 0) + return ((num > 0) ? num : i); + if (i == 0) + return num; + } + num += i; + in += i; + inl -= i; + } + } while (foundnl && inl > 0); + /* + * We've written as much as we can. The rest of the input buffer, if + * any, is text that doesn't and with a NL and therefore needs to be + * saved for the next trip. + */ + if (inl > 0) { + memcpy(&(ctx->obuf[ctx->obuf_len]), in, inl); + ctx->obuf_len += inl; + num += inl; + } + return num; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2025-69418/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2025-69418/fixed.c new file mode 100644 index 0000000..970048b --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2025-69418/fixed.c @@ -0,0 +1,101 @@ +/* Provenance: openssl/openssl CRYPTO_ocb128_encrypt (fixed). + * repo: openssl/openssl + * commit: 52d23c86a54adab5ee9f80e48b242b52c4cc2347 + * parent: 475c466ef2fbd8fc1df6fae1c3eed9c813fc8ff6 + * commit_url: https://github.com/openssl/openssl/commit/52d23c86a54adab5ee9f80e48b242b52c4cc2347 + * cve: CVE-2025-69418 + * license: Apache-2.0 + * function: CRYPTO_ocb128_encrypt + * relpath: crypto/modes/ocb128.c + */ + +int CRYPTO_ocb128_encrypt(OCB128_CONTEXT *ctx, + const unsigned char *in, unsigned char *out, + size_t len) +{ + u64 i, all_num_blocks; + size_t num_blocks, last_len; + + /* + * Calculate the number of blocks of data to be encrypted provided now, and + * so far + */ + num_blocks = len / 16; + all_num_blocks = num_blocks + ctx->sess.blocks_processed; + + if (num_blocks && all_num_blocks == (size_t)all_num_blocks + && ctx->stream != NULL) { + size_t max_idx = 0, top = (size_t)all_num_blocks, processed_bytes = 0; + + /* + * See how many L_{i} entries we need to process data at hand + * and pre-compute missing entries in the table [if any]... + */ + while (top >>= 1) + max_idx++; + if (ocb_lookup_l(ctx, max_idx) == NULL) + return 0; + + ctx->stream(in, out, num_blocks, ctx->keyenc, + (size_t)ctx->sess.blocks_processed + 1, ctx->sess.offset.c, + (const unsigned char (*)[16])ctx->l, ctx->sess.checksum.c); + processed_bytes = num_blocks * 16; + in += processed_bytes; + out += processed_bytes; + } else { + /* Loop through all full blocks to be encrypted */ + for (i = ctx->sess.blocks_processed + 1; i <= all_num_blocks; i++) { + OCB_BLOCK *lookup; + OCB_BLOCK tmp; + + /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ + lookup = ocb_lookup_l(ctx, ocb_ntz(i)); + if (lookup == NULL) + return 0; + ocb_block16_xor(&ctx->sess.offset, lookup, &ctx->sess.offset); + + memcpy(tmp.c, in, 16); + in += 16; + + /* Checksum_i = Checksum_{i-1} xor P_i */ + ocb_block16_xor(&tmp, &ctx->sess.checksum, &ctx->sess.checksum); + + /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i) */ + ocb_block16_xor(&ctx->sess.offset, &tmp, &tmp); + ctx->encrypt(tmp.c, tmp.c, ctx->keyenc); + ocb_block16_xor(&ctx->sess.offset, &tmp, &tmp); + + memcpy(out, tmp.c, 16); + out += 16; + } + } + + /* + * Check if we have any partial blocks left over. This is only valid in the + * last call to this function + */ + last_len = len % 16; + + if (last_len > 0) { + OCB_BLOCK pad; + + /* Offset_* = Offset_m xor L_* */ + ocb_block16_xor(&ctx->sess.offset, &ctx->l_star, &ctx->sess.offset); + + /* Pad = ENCIPHER(K, Offset_*) */ + ctx->encrypt(ctx->sess.offset.c, pad.c, ctx->keyenc); + + /* C_* = P_* xor Pad[1..bitlen(P_*)] */ + ocb_block_xor(in, pad.c, last_len, out); + + /* Checksum_* = Checksum_m xor (P_* || 1 || zeros(127-bitlen(P_*))) */ + memset(pad.c, 0, 16); /* borrow pad */ + memcpy(pad.c, in, last_len); + pad.c[last_len] = 0x80; + ocb_block16_xor(&pad, &ctx->sess.checksum, &ctx->sess.checksum); + } + + ctx->sess.blocks_processed = all_num_blocks; + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2025-69418/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2025-69418/vuln.c new file mode 100644 index 0000000..e2b6fbd --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2025-69418/vuln.c @@ -0,0 +1,98 @@ +/* Provenance: openssl/openssl CRYPTO_ocb128_encrypt (vuln). + * repo: openssl/openssl + * commit: 475c466ef2fbd8fc1df6fae1c3eed9c813fc8ff6 + * parent: 475c466ef2fbd8fc1df6fae1c3eed9c813fc8ff6 + * commit_url: https://github.com/openssl/openssl/commit/52d23c86a54adab5ee9f80e48b242b52c4cc2347 + * cve: CVE-2025-69418 + * license: Apache-2.0 + * function: CRYPTO_ocb128_encrypt + * relpath: crypto/modes/ocb128.c + */ + +int CRYPTO_ocb128_encrypt(OCB128_CONTEXT *ctx, + const unsigned char *in, unsigned char *out, + size_t len) +{ + u64 i, all_num_blocks; + size_t num_blocks, last_len; + + /* + * Calculate the number of blocks of data to be encrypted provided now, and + * so far + */ + num_blocks = len / 16; + all_num_blocks = num_blocks + ctx->sess.blocks_processed; + + if (num_blocks && all_num_blocks == (size_t)all_num_blocks + && ctx->stream != NULL) { + size_t max_idx = 0, top = (size_t)all_num_blocks; + + /* + * See how many L_{i} entries we need to process data at hand + * and pre-compute missing entries in the table [if any]... + */ + while (top >>= 1) + max_idx++; + if (ocb_lookup_l(ctx, max_idx) == NULL) + return 0; + + ctx->stream(in, out, num_blocks, ctx->keyenc, + (size_t)ctx->sess.blocks_processed + 1, ctx->sess.offset.c, + (const unsigned char (*)[16])ctx->l, ctx->sess.checksum.c); + } else { + /* Loop through all full blocks to be encrypted */ + for (i = ctx->sess.blocks_processed + 1; i <= all_num_blocks; i++) { + OCB_BLOCK *lookup; + OCB_BLOCK tmp; + + /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ + lookup = ocb_lookup_l(ctx, ocb_ntz(i)); + if (lookup == NULL) + return 0; + ocb_block16_xor(&ctx->sess.offset, lookup, &ctx->sess.offset); + + memcpy(tmp.c, in, 16); + in += 16; + + /* Checksum_i = Checksum_{i-1} xor P_i */ + ocb_block16_xor(&tmp, &ctx->sess.checksum, &ctx->sess.checksum); + + /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i) */ + ocb_block16_xor(&ctx->sess.offset, &tmp, &tmp); + ctx->encrypt(tmp.c, tmp.c, ctx->keyenc); + ocb_block16_xor(&ctx->sess.offset, &tmp, &tmp); + + memcpy(out, tmp.c, 16); + out += 16; + } + } + + /* + * Check if we have any partial blocks left over. This is only valid in the + * last call to this function + */ + last_len = len % 16; + + if (last_len > 0) { + OCB_BLOCK pad; + + /* Offset_* = Offset_m xor L_* */ + ocb_block16_xor(&ctx->sess.offset, &ctx->l_star, &ctx->sess.offset); + + /* Pad = ENCIPHER(K, Offset_*) */ + ctx->encrypt(ctx->sess.offset.c, pad.c, ctx->keyenc); + + /* C_* = P_* xor Pad[1..bitlen(P_*)] */ + ocb_block_xor(in, pad.c, last_len, out); + + /* Checksum_* = Checksum_m xor (P_* || 1 || zeros(127-bitlen(P_*))) */ + memset(pad.c, 0, 16); /* borrow pad */ + memcpy(pad.c, in, last_len); + pad.c[last_len] = 0x80; + ocb_block16_xor(&pad, &ctx->sess.checksum, &ctx->sess.checksum); + } + + ctx->sess.blocks_processed = all_num_blocks; + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2025-69419/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2025-69419/fixed.c new file mode 100644 index 0000000..e8e8fbc --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2025-69419/fixed.c @@ -0,0 +1,41 @@ +/* Provenance: openssl/openssl bmp_to_utf8 (fixed). + * repo: openssl/openssl + * commit: 4191043c36f1a50c717a2d0075fc6f3b9bc0afc5 + * parent: 7565bb46fa2979511cb27aad1c2bd6b80adf7352 + * commit_url: https://github.com/openssl/openssl/commit/4191043c36f1a50c717a2d0075fc6f3b9bc0afc5 + * cve: CVE-2025-69419 + * license: Apache-2.0 + * function: bmp_to_utf8 + * relpath: crypto/pkcs12/p12_utl.c + */ + +static int bmp_to_utf8(char *str, const unsigned char *utf16, int len) +{ + unsigned long utf32chr; + + if (len == 0) + return 0; + + if (len < 2) + return -1; + + /* pull UTF-16 character in big-endian order */ + utf32chr = (utf16[0] << 8) | utf16[1]; + + if (utf32chr >= 0xD800 && utf32chr < 0xE000) { /* two chars */ + unsigned int lo; + + if (len < 4) + return -1; + + utf32chr -= 0xD800; + utf32chr <<= 10; + lo = (utf16[2] << 8) | utf16[3]; + if (lo < 0xDC00 || lo >= 0xE000) + return -1; + utf32chr |= lo - 0xDC00; + utf32chr += 0x10000; + } + + return UTF8_putc((unsigned char *)str, 4, utf32chr); +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2025-69419/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2025-69419/vuln.c new file mode 100644 index 0000000..d704c47 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2025-69419/vuln.c @@ -0,0 +1,41 @@ +/* Provenance: openssl/openssl bmp_to_utf8 (vuln). + * repo: openssl/openssl + * commit: 7565bb46fa2979511cb27aad1c2bd6b80adf7352 + * parent: 7565bb46fa2979511cb27aad1c2bd6b80adf7352 + * commit_url: https://github.com/openssl/openssl/commit/4191043c36f1a50c717a2d0075fc6f3b9bc0afc5 + * cve: CVE-2025-69419 + * license: Apache-2.0 + * function: bmp_to_utf8 + * relpath: crypto/pkcs12/p12_utl.c + */ + +static int bmp_to_utf8(char *str, const unsigned char *utf16, int len) +{ + unsigned long utf32chr; + + if (len == 0) + return 0; + + if (len < 2) + return -1; + + /* pull UTF-16 character in big-endian order */ + utf32chr = (utf16[0] << 8) | utf16[1]; + + if (utf32chr >= 0xD800 && utf32chr < 0xE000) { /* two chars */ + unsigned int lo; + + if (len < 4) + return -1; + + utf32chr -= 0xD800; + utf32chr <<= 10; + lo = (utf16[2] << 8) | utf16[3]; + if (lo < 0xDC00 || lo >= 0xE000) + return -1; + utf32chr |= lo - 0xDC00; + utf32chr += 0x10000; + } + + return UTF8_putc((unsigned char *)str, len > 4 ? 4 : len, utf32chr); +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2025-69421/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2025-69421/fixed.c new file mode 100644 index 0000000..451a769 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2025-69421/fixed.c @@ -0,0 +1,46 @@ +/* Provenance: openssl/openssl PKCS12_item_decrypt_d2i_ex (fixed). + * repo: openssl/openssl + * commit: 2c13bf15286328641a805eb3b7c97e27d42881fb + * parent: ea8fc4c345fbd749048809c9f7c881ea656b0b94 + * commit_url: https://github.com/openssl/openssl/commit/2c13bf15286328641a805eb3b7c97e27d42881fb + * cve: CVE-2025-69421 + * license: Apache-2.0 + * function: PKCS12_item_decrypt_d2i_ex + * relpath: crypto/pkcs12/p12_decr.c + */ + +void *PKCS12_item_decrypt_d2i_ex(const X509_ALGOR *algor, const ASN1_ITEM *it, + const char *pass, int passlen, + const ASN1_OCTET_STRING *oct, int zbuf, + OSSL_LIB_CTX *libctx, + const char *propq) +{ + unsigned char *out = NULL; + const unsigned char *p; + void *ret; + int outlen = 0; + + if (oct == NULL) { + ERR_raise(ERR_LIB_PKCS12, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + + if (!PKCS12_pbe_crypt_ex(algor, pass, passlen, oct->data, oct->length, + &out, &outlen, 0, libctx, propq)) + return NULL; + p = out; + OSSL_TRACE_BEGIN(PKCS12_DECRYPT) + { + BIO_printf(trc_out, "\n"); + BIO_dump(trc_out, out, outlen); + BIO_printf(trc_out, "\n"); + } + OSSL_TRACE_END(PKCS12_DECRYPT); + ret = ASN1_item_d2i(NULL, &p, outlen, it); + if (zbuf) + OPENSSL_cleanse(out, outlen); + if (!ret) + ERR_raise(ERR_LIB_PKCS12, PKCS12_R_DECODE_ERROR); + OPENSSL_free(out); + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2025-69421/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2025-69421/vuln.c new file mode 100644 index 0000000..17fe781 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2025-69421/vuln.c @@ -0,0 +1,41 @@ +/* Provenance: openssl/openssl PKCS12_item_decrypt_d2i_ex (vuln). + * repo: openssl/openssl + * commit: ea8fc4c345fbd749048809c9f7c881ea656b0b94 + * parent: ea8fc4c345fbd749048809c9f7c881ea656b0b94 + * commit_url: https://github.com/openssl/openssl/commit/2c13bf15286328641a805eb3b7c97e27d42881fb + * cve: CVE-2025-69421 + * license: Apache-2.0 + * function: PKCS12_item_decrypt_d2i_ex + * relpath: crypto/pkcs12/p12_decr.c + */ + +void *PKCS12_item_decrypt_d2i_ex(const X509_ALGOR *algor, const ASN1_ITEM *it, + const char *pass, int passlen, + const ASN1_OCTET_STRING *oct, int zbuf, + OSSL_LIB_CTX *libctx, + const char *propq) +{ + unsigned char *out = NULL; + const unsigned char *p; + void *ret; + int outlen = 0; + + if (!PKCS12_pbe_crypt_ex(algor, pass, passlen, oct->data, oct->length, + &out, &outlen, 0, libctx, propq)) + return NULL; + p = out; + OSSL_TRACE_BEGIN(PKCS12_DECRYPT) + { + BIO_printf(trc_out, "\n"); + BIO_dump(trc_out, out, outlen); + BIO_printf(trc_out, "\n"); + } + OSSL_TRACE_END(PKCS12_DECRYPT); + ret = ASN1_item_d2i(NULL, &p, outlen, it); + if (zbuf) + OPENSSL_cleanse(out, outlen); + if (!ret) + ERR_raise(ERR_LIB_PKCS12, PKCS12_R_DECODE_ERROR); + OPENSSL_free(out); + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2025-9230/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2025-9230/fixed.c new file mode 100644 index 0000000..f19c598 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2025-9230/fixed.c @@ -0,0 +1,65 @@ +/* Provenance: openssl/openssl kek_unwrap_key (fixed). + * repo: openssl/openssl + * commit: a79c4ce559c6a3a8fd4109e9f33c1185d5bf2def + * parent: 7e0fc054a08706d194d3355aba4a06003cadfb29 + * commit_url: https://github.com/openssl/openssl/commit/a79c4ce559c6a3a8fd4109e9f33c1185d5bf2def + * cve: CVE-2025-9230 + * license: Apache-2.0 + * function: kek_unwrap_key + * relpath: crypto/cms/cms_pwri.c + */ + +static int kek_unwrap_key(unsigned char *out, size_t *outlen, + const unsigned char *in, size_t inlen, + EVP_CIPHER_CTX *ctx) +{ + size_t blocklen = EVP_CIPHER_CTX_get_block_size(ctx); + unsigned char *tmp; + int outl, rv = 0; + if (inlen < 2 * blocklen) { + /* too small */ + return 0; + } + if (inlen % blocklen) { + /* Invalid size */ + return 0; + } + if ((tmp = OPENSSL_malloc(inlen)) == NULL) { + ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE); + return 0; + } + /* setup IV by decrypting last two blocks */ + if (!EVP_DecryptUpdate(ctx, tmp + inlen - 2 * blocklen, &outl, + in + inlen - 2 * blocklen, blocklen * 2) + /* + * Do a decrypt of last decrypted block to set IV to correct value + * output it to start of buffer so we don't corrupt decrypted block + * this works because buffer is at least two block lengths long. + */ + || !EVP_DecryptUpdate(ctx, tmp, &outl, + tmp + inlen - blocklen, blocklen) + /* Can now decrypt first n - 1 blocks */ + || !EVP_DecryptUpdate(ctx, tmp, &outl, in, inlen - blocklen) + + /* Reset IV to original value */ + || !EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, NULL) + /* Decrypt again */ + || !EVP_DecryptUpdate(ctx, tmp, &outl, tmp, inlen)) + goto err; + /* Check check bytes */ + if (((tmp[1] ^ tmp[4]) & (tmp[2] ^ tmp[5]) & (tmp[3] ^ tmp[6])) != 0xff) { + /* Check byte failure */ + goto err; + } + if (inlen < 4 + (size_t)tmp[0]) { + /* Invalid length value */ + goto err; + } + *outlen = (size_t)tmp[0]; + memcpy(out, tmp + 4, *outlen); + rv = 1; + err: + OPENSSL_clear_free(tmp, inlen); + return rv; + +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2025-9230/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2025-9230/vuln.c new file mode 100644 index 0000000..404a6c7 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2025-9230/vuln.c @@ -0,0 +1,65 @@ +/* Provenance: openssl/openssl kek_unwrap_key (vuln). + * repo: openssl/openssl + * commit: 7e0fc054a08706d194d3355aba4a06003cadfb29 + * parent: 7e0fc054a08706d194d3355aba4a06003cadfb29 + * commit_url: https://github.com/openssl/openssl/commit/a79c4ce559c6a3a8fd4109e9f33c1185d5bf2def + * cve: CVE-2025-9230 + * license: Apache-2.0 + * function: kek_unwrap_key + * relpath: crypto/cms/cms_pwri.c + */ + +static int kek_unwrap_key(unsigned char *out, size_t *outlen, + const unsigned char *in, size_t inlen, + EVP_CIPHER_CTX *ctx) +{ + size_t blocklen = EVP_CIPHER_CTX_get_block_size(ctx); + unsigned char *tmp; + int outl, rv = 0; + if (inlen < 2 * blocklen) { + /* too small */ + return 0; + } + if (inlen % blocklen) { + /* Invalid size */ + return 0; + } + if ((tmp = OPENSSL_malloc(inlen)) == NULL) { + ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE); + return 0; + } + /* setup IV by decrypting last two blocks */ + if (!EVP_DecryptUpdate(ctx, tmp + inlen - 2 * blocklen, &outl, + in + inlen - 2 * blocklen, blocklen * 2) + /* + * Do a decrypt of last decrypted block to set IV to correct value + * output it to start of buffer so we don't corrupt decrypted block + * this works because buffer is at least two block lengths long. + */ + || !EVP_DecryptUpdate(ctx, tmp, &outl, + tmp + inlen - blocklen, blocklen) + /* Can now decrypt first n - 1 blocks */ + || !EVP_DecryptUpdate(ctx, tmp, &outl, in, inlen - blocklen) + + /* Reset IV to original value */ + || !EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, NULL) + /* Decrypt again */ + || !EVP_DecryptUpdate(ctx, tmp, &outl, tmp, inlen)) + goto err; + /* Check check bytes */ + if (((tmp[1] ^ tmp[4]) & (tmp[2] ^ tmp[5]) & (tmp[3] ^ tmp[6])) != 0xff) { + /* Check byte failure */ + goto err; + } + if (inlen < (size_t)(tmp[0] - 4)) { + /* Invalid length value */ + goto err; + } + *outlen = (size_t)tmp[0]; + memcpy(out, tmp + 4, *outlen); + rv = 1; + err: + OPENSSL_clear_free(tmp, inlen); + return rv; + +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2025-9232/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2025-9232/fixed.c new file mode 100644 index 0000000..a7253d4 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2025-9232/fixed.c @@ -0,0 +1,45 @@ +/* Provenance: openssl/openssl use_proxy (fixed). + * repo: openssl/openssl + * commit: 654dc11d23468a74fc8ea4672b702dd3feb7be4b + * parent: a79c4ce559c6a3a8fd4109e9f33c1185d5bf2def + * commit_url: https://github.com/openssl/openssl/commit/654dc11d23468a74fc8ea4672b702dd3feb7be4b + * cve: CVE-2025-9232 + * license: Apache-2.0 + * function: use_proxy + * relpath: crypto/http/http_lib.c + */ + +static int use_proxy(const char *no_proxy, const char *server) +{ + size_t sl; + const char *found = NULL; + char host[NI_MAXHOST]; + + if (!ossl_assert(server != NULL)) + return 0; + sl = strlen(server); + if (sl >= 2 && sl < sizeof(host) + 2 && server[0] == '[' && server[sl - 1] == ']') { + /* strip leading '[' and trailing ']' from escaped IPv6 address */ + sl -= 2; + strncpy(host, server + 1, sl); + host[sl] = '\0'; + server = host; + } + + /* + * using environment variable names, both lowercase and uppercase variants, + * compatible with other HTTP client implementations like wget, curl and git + */ + if (no_proxy == NULL) + no_proxy = ossl_safe_getenv("no_proxy"); + if (no_proxy == NULL) + no_proxy = ossl_safe_getenv(OPENSSL_NO_PROXY); + + if (no_proxy != NULL) + found = strstr(no_proxy, server); + while (found != NULL + && ((found != no_proxy && !ossl_isspace(found[-1]) && found[-1] != ',') + || (found[sl] != '\0' && !ossl_isspace(found[sl]) && found[sl] != ','))) + found = strstr(found + 1, server); + return found == NULL; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2025-9232/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2025-9232/vuln.c new file mode 100644 index 0000000..3ff6ac3 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2025-9232/vuln.c @@ -0,0 +1,44 @@ +/* Provenance: openssl/openssl use_proxy (vuln). + * repo: openssl/openssl + * commit: a79c4ce559c6a3a8fd4109e9f33c1185d5bf2def + * parent: a79c4ce559c6a3a8fd4109e9f33c1185d5bf2def + * commit_url: https://github.com/openssl/openssl/commit/654dc11d23468a74fc8ea4672b702dd3feb7be4b + * cve: CVE-2025-9232 + * license: Apache-2.0 + * function: use_proxy + * relpath: crypto/http/http_lib.c + */ + +static int use_proxy(const char *no_proxy, const char *server) +{ + size_t sl; + const char *found = NULL; + char host[NI_MAXHOST]; + + if (!ossl_assert(server != NULL)) + return 0; + sl = strlen(server); + if (sl >= 2 && sl < sizeof(host) + 2 && server[0] == '[' && server[sl - 1] == ']') { + /* strip leading '[' and trailing ']' from escaped IPv6 address */ + sl -= 2; + strncpy(host, server + 1, sl); + server = host; + } + + /* + * using environment variable names, both lowercase and uppercase variants, + * compatible with other HTTP client implementations like wget, curl and git + */ + if (no_proxy == NULL) + no_proxy = ossl_safe_getenv("no_proxy"); + if (no_proxy == NULL) + no_proxy = ossl_safe_getenv(OPENSSL_NO_PROXY); + + if (no_proxy != NULL) + found = strstr(no_proxy, server); + while (found != NULL + && ((found != no_proxy && !ossl_isspace(found[-1]) && found[-1] != ',') + || (found[sl] != '\0' && !ossl_isspace(found[sl]) && found[sl] != ','))) + found = strstr(found + 1, server); + return found == NULL; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-14456-expect_quic_for_value/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-14456-expect_quic_for_value/fixed.c new file mode 100644 index 0000000..0d0313a --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-14456-expect_quic_for_value/fixed.c @@ -0,0 +1,33 @@ +/* Provenance: openssl/openssl expect_quic_for_value (fixed). + * repo: openssl/openssl + * commit: 9416706d408bb84deb7cee4647bff3045d2dc7ba + * parent: 2c9a078b6030444ed868a3943991f42b35cd49dc + * commit_url: https://github.com/openssl/openssl/commit/9416706d408bb84deb7cee4647bff3045d2dc7ba + * cve: CVE-2026-14456 + * license: Apache-2.0 + * function: expect_quic_for_value + * relpath: ssl/quic/quic_impl.c + */ + +QUIC_NEEDS_LOCK +static int expect_quic_for_value(SSL *s, QCTX *ctx, uint32_t id) +{ + switch (id) { + case SSL_VALUE_EVENT_HANDLING_MODE: + case SSL_VALUE_STREAM_WRITE_BUF_SIZE: + case SSL_VALUE_STREAM_WRITE_BUF_USED: + case SSL_VALUE_STREAM_WRITE_BUF_AVAIL: + return expect_quic_cs(s, ctx); + case SSL_VALUE_QUIC_IDLE_TIMEOUT: + case SSL_VALUE_QUIC_UDP_PAYLOAD_SIZE_MAX: + case SSL_VALUE_QUIC_WINDOWCON: + case SSL_VALUE_QUIC_WINDOWBSTR: + case SSL_VALUE_QUIC_WINDOWUSTR: + case SSL_VALUE_QUIC_ACK_DELAY_EXPONENT: + case SSL_VALUE_QUIC_ACK_DELAY_MAX: + case SSL_VALUE_QUIC_MAX_PENDING_CONNS: + return expect_quic_cl(s, ctx); + default: + return expect_quic_conn_only(s, ctx); + } +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-14456-expect_quic_for_value/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-14456-expect_quic_for_value/vuln.c new file mode 100644 index 0000000..49c21cd --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-14456-expect_quic_for_value/vuln.c @@ -0,0 +1,32 @@ +/* Provenance: openssl/openssl expect_quic_for_value (vuln). + * repo: openssl/openssl + * commit: 2c9a078b6030444ed868a3943991f42b35cd49dc + * parent: 2c9a078b6030444ed868a3943991f42b35cd49dc + * commit_url: https://github.com/openssl/openssl/commit/9416706d408bb84deb7cee4647bff3045d2dc7ba + * cve: CVE-2026-14456 + * license: Apache-2.0 + * function: expect_quic_for_value + * relpath: ssl/quic/quic_impl.c + */ + +QUIC_NEEDS_LOCK +static int expect_quic_for_value(SSL *s, QCTX *ctx, uint32_t id) +{ + switch (id) { + case SSL_VALUE_EVENT_HANDLING_MODE: + case SSL_VALUE_STREAM_WRITE_BUF_SIZE: + case SSL_VALUE_STREAM_WRITE_BUF_USED: + case SSL_VALUE_STREAM_WRITE_BUF_AVAIL: + return expect_quic_cs(s, ctx); + case SSL_VALUE_QUIC_IDLE_TIMEOUT: + case SSL_VALUE_QUIC_UDP_PAYLOAD_SIZE_MAX: + case SSL_VALUE_QUIC_WINDOWCON: + case SSL_VALUE_QUIC_WINDOWBSTR: + case SSL_VALUE_QUIC_WINDOWUSTR: + case SSL_VALUE_QUIC_ACK_DELAY_EXPONENT: + case SSL_VALUE_QUIC_ACK_DELAY_MAX: + return expect_quic_cl(s, ctx); + default: + return expect_quic_conn_only(s, ctx); + } +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-14456-port_default_packet_hand/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-14456-port_default_packet_hand/fixed.c new file mode 100644 index 0000000..6bc5314 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-14456-port_default_packet_hand/fixed.c @@ -0,0 +1,262 @@ +/* Provenance: openssl/openssl port_default_packet_handler (fixed). + * repo: openssl/openssl + * commit: 08e7756c3900bcfd77a720e7b74e27d6e4ed01a9 + * parent: 2dacccc943b47b8dc1ce8f7109c9852391b5a0d8 + * commit_url: https://github.com/openssl/openssl/commit/08e7756c3900bcfd77a720e7b74e27d6e4ed01a9 + * cve: CVE-2026-14456 + * license: Apache-2.0 + * function: port_default_packet_handler + * relpath: ssl/quic/quic_port.c + */ + +static void port_default_packet_handler(QUIC_URXE *e, void *arg, + const QUIC_CONN_ID *dcid) +{ + QUIC_PORT *port = arg; + PACKET pkt; + QUIC_PKT_HDR hdr; + QUIC_CHANNEL *ch = NULL, *new_ch = NULL; + QUIC_CONN_ID odcid; + uint8_t gen_new_token = 0; + OSSL_QRX *qrx = NULL; + OSSL_QRX *qrx_src = NULL; + OSSL_QRX_ARGS qrx_args = { 0 }; + uint64_t cause_flags = 0; + OSSL_QRX_PKT *qrx_pkt = NULL; + + /* Don't handle anything if we are no longer running. */ + if (!ossl_quic_port_is_running(port)) + goto undesirable; + + if (port_try_handle_stateless_reset(port, e)) + goto undesirable; + + if (dcid != NULL + && ossl_quic_lcidm_lookup(port->lcidm, dcid, NULL, + (void **)&ch)) { + assert(ch != NULL); + ossl_quic_channel_inject(ch, e); + return; + } + + /* + * If we have an incoming packet which doesn't match any existing connection + * we assume this is an attempt to make a new connection. + */ + if (!port->allow_incoming) + goto undesirable; + + /* + * packet without destination connection id is invalid/corrupted here. + * stop wasting CPU cycles now. + */ + if (dcid == NULL) + goto undesirable; + + /* + * We have got a packet for an unknown DCID. This might be an attempt to + * open a new connection. + */ + if (e->data_len < QUIC_MIN_INITIAL_DGRAM_LEN) + goto undesirable; + + if (!PACKET_buf_init(&pkt, ossl_quic_urxe_data(e), e->data_len)) + goto undesirable; + + /* + * We set short_conn_id_len to SIZE_MAX here which will cause the decode + * operation to fail if we get a 1-RTT packet. This is fine since we only + * care about Initial packets. + */ + if (!ossl_quic_wire_decode_pkt_hdr(&pkt, SIZE_MAX, 1, 0, &hdr, NULL, + &cause_flags)) { + /* + * If we fail due to a bad version, we know the packet up to the version + * number was decoded, and we use it below to send a version + * negotiation packet + */ + if ((cause_flags & QUIC_PKT_HDR_DECODE_BAD_VERSION) == 0) + goto undesirable; + } + + switch (hdr.version) { + case QUIC_VERSION_1: + break; + + case QUIC_VERSION_NONE: + default: + + /* + * If we get here, then we have a bogus version, and might need + * to send a version negotiation packet. According to + * RFC 9000 s. 6 and 14.1, we only do so however, if the UDP datagram + * is a minimum of 1200 bytes in size + */ + if (e->data_len < 1200) + goto undesirable; + + /* + * If we don't get a supported version, respond with a ver + * negotiation packet, and discard + * TODO(QUIC FUTURE): Rate limit the reception of these + */ + port_send_version_negotiation(port, &e->peer, &hdr); + goto undesirable; + } + + /* + * We only care about Initial packets which might be trying to establish a + * connection. + */ + if (hdr.type != QUIC_PKT_TYPE_INITIAL) + goto undesirable; + + if (port->max_pending_channels > 0 && ossl_list_incoming_ch_num(&port->incoming_channel_list) >= port->max_pending_channels) + goto undesirable; + + odcid.id_len = 0; + + /* + * Create qrx now so we can check integrity of packet + * which does not belong to any channel. + */ + qrx_args.libctx = port->engine->libctx; + qrx_args.demux = port->demux; + qrx_args.short_conn_id_len = dcid->id_len; + qrx_args.max_deferred = 32; + qrx = ossl_qrx_new(&qrx_args); + if (qrx == NULL) + goto undesirable; + + /* + * Derive secrets for qrx only. + */ + if (!ossl_quic_provide_initial_secret(port->engine->libctx, + port->engine->propq, + &hdr.dst_conn_id, + /* is_server */ 1, + qrx, NULL)) + goto undesirable; + + if (ossl_qrx_validate_initial_packet(qrx, e, (const QUIC_CONN_ID *)dcid) == 0) + goto undesirable; + + if (port->validate_addr == 0) { + /* + * Forget qrx, because it becomes (almost) useless here. We must let + * channel to create a new QRX for connection ID server chooses. The + * validation keys for new DCID will be derived by + * ossl_quic_channel_on_new_conn() when we will be creating channel. + * See RFC 9000 section 7.2 negotiating connection id to better + * understand what's going on here. + * + * Did we say qrx is almost useless? Why? Because qrx remembers packets + * we just validated. Those packets must be injected to channel we are + * going to create. We use qrx_src alias so we can read packets from + * qrx and inject them to channel. + */ + qrx_src = qrx; + qrx = NULL; + } + /* + * TODO(QUIC FUTURE): there should be some logic similar to accounting half-open + * states in TCP. If we reach certain threshold, then we want to + * validate clients. + */ + if (port->validate_addr == 1 && hdr.token == NULL) { + port_send_retry(port, &e->peer, &hdr); + goto undesirable; + } + + /* + * Note, even if we don't enforce the sending of retry frames for + * server address validation, we may still get a token if we sent + * a NEW_TOKEN frame during a prior connection, which we should still + * validate here + */ + if (hdr.token != NULL + && port_validate_token(&hdr, port, &e->peer, + &odcid, &gen_new_token) + == 0) { + /* + * RFC 9000 s 8.1.3 + * When a server receives an Initial packet with an address + * validation token, it MUST attempt to validate the token, + * unless it has already completed address validation. + * If the token is invalid, then the server SHOULD proceed as + * if the client did not have a validated address, + * including potentially sending a Retry packet + * Note: If address validation is disabled, just act like + * the request is valid + */ + if (port->validate_addr == 1) { + /* + * Again: we should consider saving initial encryption level + * secrets to token here to save some CPU cycles. + */ + port_send_retry(port, &e->peer, &hdr); + goto undesirable; + } + + /* + * client is under amplification limit, until it completes + * handshake. + * + * forget qrx so channel can create a new one + * with valid initial encryption level keys. + */ + if (qrx != NULL) { + qrx_src = qrx; + qrx = NULL; + } + } + + port_bind_channel(port, &e->peer, &hdr.dst_conn_id, + &odcid, qrx, &new_ch); + + /* + * if packet validates it gets moved to channel, we've just bound + * to port. + */ + if (new_ch == NULL) + goto undesirable; + + /* + * Generate a token for sending in a later NEW_TOKEN frame + */ + if (gen_new_token == 1) + generate_new_token(new_ch, &e->peer); + + if (qrx != NULL) { + /* + * The qrx belongs to channel now, so don't free it. + */ + qrx = NULL; + } else { + /* + * We still need to salvage packets from almost forgotten qrx + * and pass them to channel. + */ + while (ossl_qrx_read_pkt(qrx_src, &qrx_pkt) == 1) + ossl_quic_channel_inject_pkt(new_ch, qrx_pkt); + ossl_qrx_update_pn_space(qrx_src, new_ch->qrx); + } + + /* + * If function reaches this place, then packet got validated in + * ossl_qrx_validate_initial_packet(). Keep in mind the function + * ossl_qrx_validate_initial_packet() decrypts the packet to validate it. + * If packet validation was successful (and it was because we are here), + * then the function puts the packet to qrx->rx_pending. We must not call + * ossl_qrx_inject_urxe() here now, because we don't want to insert + * the packet to qrx->urx_pending which keeps packet waiting for decryption. + * + * We are going to call ossl_quic_demux_release_urxe() to dispose buffer + * which still holds encrypted data. + */ + +undesirable: + ossl_qrx_free(qrx); + ossl_qrx_free(qrx_src); + ossl_quic_demux_release_urxe(port->demux, e); +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-14456-port_default_packet_hand/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-14456-port_default_packet_hand/vuln.c new file mode 100644 index 0000000..569bbf4 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-14456-port_default_packet_hand/vuln.c @@ -0,0 +1,259 @@ +/* Provenance: openssl/openssl port_default_packet_handler (vuln). + * repo: openssl/openssl + * commit: 2dacccc943b47b8dc1ce8f7109c9852391b5a0d8 + * parent: 2dacccc943b47b8dc1ce8f7109c9852391b5a0d8 + * commit_url: https://github.com/openssl/openssl/commit/08e7756c3900bcfd77a720e7b74e27d6e4ed01a9 + * cve: CVE-2026-14456 + * license: Apache-2.0 + * function: port_default_packet_handler + * relpath: ssl/quic/quic_port.c + */ + +static void port_default_packet_handler(QUIC_URXE *e, void *arg, + const QUIC_CONN_ID *dcid) +{ + QUIC_PORT *port = arg; + PACKET pkt; + QUIC_PKT_HDR hdr; + QUIC_CHANNEL *ch = NULL, *new_ch = NULL; + QUIC_CONN_ID odcid; + uint8_t gen_new_token = 0; + OSSL_QRX *qrx = NULL; + OSSL_QRX *qrx_src = NULL; + OSSL_QRX_ARGS qrx_args = { 0 }; + uint64_t cause_flags = 0; + OSSL_QRX_PKT *qrx_pkt = NULL; + + /* Don't handle anything if we are no longer running. */ + if (!ossl_quic_port_is_running(port)) + goto undesirable; + + if (port_try_handle_stateless_reset(port, e)) + goto undesirable; + + if (dcid != NULL + && ossl_quic_lcidm_lookup(port->lcidm, dcid, NULL, + (void **)&ch)) { + assert(ch != NULL); + ossl_quic_channel_inject(ch, e); + return; + } + + /* + * If we have an incoming packet which doesn't match any existing connection + * we assume this is an attempt to make a new connection. + */ + if (!port->allow_incoming) + goto undesirable; + + /* + * packet without destination connection id is invalid/corrupted here. + * stop wasting CPU cycles now. + */ + if (dcid == NULL) + goto undesirable; + + /* + * We have got a packet for an unknown DCID. This might be an attempt to + * open a new connection. + */ + if (e->data_len < QUIC_MIN_INITIAL_DGRAM_LEN) + goto undesirable; + + if (!PACKET_buf_init(&pkt, ossl_quic_urxe_data(e), e->data_len)) + goto undesirable; + + /* + * We set short_conn_id_len to SIZE_MAX here which will cause the decode + * operation to fail if we get a 1-RTT packet. This is fine since we only + * care about Initial packets. + */ + if (!ossl_quic_wire_decode_pkt_hdr(&pkt, SIZE_MAX, 1, 0, &hdr, NULL, + &cause_flags)) { + /* + * If we fail due to a bad version, we know the packet up to the version + * number was decoded, and we use it below to send a version + * negotiation packet + */ + if ((cause_flags & QUIC_PKT_HDR_DECODE_BAD_VERSION) == 0) + goto undesirable; + } + + switch (hdr.version) { + case QUIC_VERSION_1: + break; + + case QUIC_VERSION_NONE: + default: + + /* + * If we get here, then we have a bogus version, and might need + * to send a version negotiation packet. According to + * RFC 9000 s. 6 and 14.1, we only do so however, if the UDP datagram + * is a minimum of 1200 bytes in size + */ + if (e->data_len < 1200) + goto undesirable; + + /* + * If we don't get a supported version, respond with a ver + * negotiation packet, and discard + * TODO(QUIC FUTURE): Rate limit the reception of these + */ + port_send_version_negotiation(port, &e->peer, &hdr); + goto undesirable; + } + + /* + * We only care about Initial packets which might be trying to establish a + * connection. + */ + if (hdr.type != QUIC_PKT_TYPE_INITIAL) + goto undesirable; + + odcid.id_len = 0; + + /* + * Create qrx now so we can check integrity of packet + * which does not belong to any channel. + */ + qrx_args.libctx = port->engine->libctx; + qrx_args.demux = port->demux; + qrx_args.short_conn_id_len = dcid->id_len; + qrx_args.max_deferred = 32; + qrx = ossl_qrx_new(&qrx_args); + if (qrx == NULL) + goto undesirable; + + /* + * Derive secrets for qrx only. + */ + if (!ossl_quic_provide_initial_secret(port->engine->libctx, + port->engine->propq, + &hdr.dst_conn_id, + /* is_server */ 1, + qrx, NULL)) + goto undesirable; + + if (ossl_qrx_validate_initial_packet(qrx, e, (const QUIC_CONN_ID *)dcid) == 0) + goto undesirable; + + if (port->validate_addr == 0) { + /* + * Forget qrx, because it becomes (almost) useless here. We must let + * channel to create a new QRX for connection ID server chooses. The + * validation keys for new DCID will be derived by + * ossl_quic_channel_on_new_conn() when we will be creating channel. + * See RFC 9000 section 7.2 negotiating connection id to better + * understand what's going on here. + * + * Did we say qrx is almost useless? Why? Because qrx remembers packets + * we just validated. Those packets must be injected to channel we are + * going to create. We use qrx_src alias so we can read packets from + * qrx and inject them to channel. + */ + qrx_src = qrx; + qrx = NULL; + } + /* + * TODO(QUIC FUTURE): there should be some logic similar to accounting half-open + * states in TCP. If we reach certain threshold, then we want to + * validate clients. + */ + if (port->validate_addr == 1 && hdr.token == NULL) { + port_send_retry(port, &e->peer, &hdr); + goto undesirable; + } + + /* + * Note, even if we don't enforce the sending of retry frames for + * server address validation, we may still get a token if we sent + * a NEW_TOKEN frame during a prior connection, which we should still + * validate here + */ + if (hdr.token != NULL + && port_validate_token(&hdr, port, &e->peer, + &odcid, &gen_new_token) + == 0) { + /* + * RFC 9000 s 8.1.3 + * When a server receives an Initial packet with an address + * validation token, it MUST attempt to validate the token, + * unless it has already completed address validation. + * If the token is invalid, then the server SHOULD proceed as + * if the client did not have a validated address, + * including potentially sending a Retry packet + * Note: If address validation is disabled, just act like + * the request is valid + */ + if (port->validate_addr == 1) { + /* + * Again: we should consider saving initial encryption level + * secrets to token here to save some CPU cycles. + */ + port_send_retry(port, &e->peer, &hdr); + goto undesirable; + } + + /* + * client is under amplification limit, until it completes + * handshake. + * + * forget qrx so channel can create a new one + * with valid initial encryption level keys. + */ + if (qrx != NULL) { + qrx_src = qrx; + qrx = NULL; + } + } + + port_bind_channel(port, &e->peer, &hdr.dst_conn_id, + &odcid, qrx, &new_ch); + + /* + * if packet validates it gets moved to channel, we've just bound + * to port. + */ + if (new_ch == NULL) + goto undesirable; + + /* + * Generate a token for sending in a later NEW_TOKEN frame + */ + if (gen_new_token == 1) + generate_new_token(new_ch, &e->peer); + + if (qrx != NULL) { + /* + * The qrx belongs to channel now, so don't free it. + */ + qrx = NULL; + } else { + /* + * We still need to salvage packets from almost forgotten qrx + * and pass them to channel. + */ + while (ossl_qrx_read_pkt(qrx_src, &qrx_pkt) == 1) + ossl_quic_channel_inject_pkt(new_ch, qrx_pkt); + ossl_qrx_update_pn_space(qrx_src, new_ch->qrx); + } + + /* + * If function reaches this place, then packet got validated in + * ossl_qrx_validate_initial_packet(). Keep in mind the function + * ossl_qrx_validate_initial_packet() decrypts the packet to validate it. + * If packet validation was successful (and it was because we are here), + * then the function puts the packet to qrx->rx_pending. We must not call + * ossl_qrx_inject_urxe() here now, because we don't want to insert + * the packet to qrx->urx_pending which keeps packet waiting for decryption. + * + * We are going to call ossl_quic_demux_release_urxe() to dispose buffer + * which still holds encrypted data. + */ + +undesirable: + ossl_qrx_free(qrx); + ossl_qrx_free(qrx_src); + ossl_quic_demux_release_urxe(port->demux, e); +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-14457/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-14457/fixed.c new file mode 100644 index 0000000..ef61f60 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-14457/fixed.c @@ -0,0 +1,76 @@ +/* Provenance: openssl/openssl check_cert_usable (fixed). + * repo: openssl/openssl + * commit: 1e8c398db67404babd3e5af999bb6bd86f720c76 + * parent: f636f9ca0fa1bae5b42f9e787f025c96fb09c43a + * commit_url: https://github.com/openssl/openssl/commit/1e8c398db67404babd3e5af999bb6bd86f720c76 + * cve: CVE-2026-14457 + * license: Apache-2.0 + * function: check_cert_usable + * relpath: ssl/t1_lib.c + */ + +static int check_cert_usable(SSL_CONNECTION *s, const SIGALG_LOOKUP *sig, + X509 *x, EVP_PKEY *pkey) +{ + const SIGALG_LOOKUP *lu; + int mdnid, pknid, supported; + size_t i; + const char *mdname = NULL; + SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s); + + /* + * If the given EVP_PKEY cannot support signing with this digest, + * the answer is simply 'no'. + */ + if (sig->hash != NID_undef) + mdname = OBJ_nid2sn(sig->hash); + supported = EVP_PKEY_digestsign_supports_digest(pkey, sctx->libctx, + mdname, + sctx->propq); + if (supported <= 0) + return 0; + + /* + * When RPK is negotiated there are no certificate signatures to + * constrain, and there may not even be a certificate configured. + */ + if (TLSEXT_cert_type_rpk == (s->server ? s->ext.server_cert_type : s->ext.client_cert_type)) + return 1; + + /* + * RPK was enabled, adding candidate private-key-only slots, but was not + * negotiated, so the key-only slot is not usable. + */ + if (x == NULL) + return 0; + + /* + * The TLS 1.3 signature_algorithms_cert extension places restrictions + * on the sigalg with which the certificate was signed (by its issuer). + */ + if (s->s3.tmp.peer_cert_sigalgs != NULL) { + if (!X509_get_signature_info(x, &mdnid, &pknid, NULL, NULL)) + return 0; + for (i = 0; i < s->s3.tmp.peer_cert_sigalgslen; i++) { + lu = tls1_lookup_sigalg(s, s->s3.tmp.peer_cert_sigalgs[i]); + if (lu == NULL) + continue; + + /* + * This does not differentiate between the + * rsa_pss_pss_* and rsa_pss_rsae_* schemes since we do not + * have a chain here that lets us look at the key OID in the + * signing certificate. + */ + if (mdnid == lu->hash && pknid == lu->sig) + return 1; + } + return 0; + } + + /* + * Without signat_algorithms_cert, any certificate for which we have + * a viable public key is permitted. + */ + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-14457/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-14457/vuln.c new file mode 100644 index 0000000..d184058 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-14457/vuln.c @@ -0,0 +1,62 @@ +/* Provenance: openssl/openssl check_cert_usable (vuln). + * repo: openssl/openssl + * commit: f636f9ca0fa1bae5b42f9e787f025c96fb09c43a + * parent: f636f9ca0fa1bae5b42f9e787f025c96fb09c43a + * commit_url: https://github.com/openssl/openssl/commit/1e8c398db67404babd3e5af999bb6bd86f720c76 + * cve: CVE-2026-14457 + * license: Apache-2.0 + * function: check_cert_usable + * relpath: ssl/t1_lib.c + */ + +static int check_cert_usable(SSL_CONNECTION *s, const SIGALG_LOOKUP *sig, + X509 *x, EVP_PKEY *pkey) +{ + const SIGALG_LOOKUP *lu; + int mdnid, pknid, supported; + size_t i; + const char *mdname = NULL; + SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s); + + /* + * If the given EVP_PKEY cannot support signing with this digest, + * the answer is simply 'no'. + */ + if (sig->hash != NID_undef) + mdname = OBJ_nid2sn(sig->hash); + supported = EVP_PKEY_digestsign_supports_digest(pkey, sctx->libctx, + mdname, + sctx->propq); + if (supported <= 0) + return 0; + + /* + * The TLS 1.3 signature_algorithms_cert extension places restrictions + * on the sigalg with which the certificate was signed (by its issuer). + */ + if (s->s3.tmp.peer_cert_sigalgs != NULL) { + if (!X509_get_signature_info(x, &mdnid, &pknid, NULL, NULL)) + return 0; + for (i = 0; i < s->s3.tmp.peer_cert_sigalgslen; i++) { + lu = tls1_lookup_sigalg(s, s->s3.tmp.peer_cert_sigalgs[i]); + if (lu == NULL) + continue; + + /* + * This does not differentiate between the + * rsa_pss_pss_* and rsa_pss_rsae_* schemes since we do not + * have a chain here that lets us look at the key OID in the + * signing certificate. + */ + if (mdnid == lu->hash && pknid == lu->sig) + return 1; + } + return 0; + } + + /* + * Without signat_algorithms_cert, any certificate for which we have + * a viable public key is permitted. + */ + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-18798/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-18798/fixed.c new file mode 100644 index 0000000..44466ba --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-18798/fixed.c @@ -0,0 +1,276 @@ +/* Provenance: openssl/openssl port_default_packet_handler (fixed). + * repo: openssl/openssl + * commit: 70cebd74d3592f5272945501b58a60374c4e13af + * parent: 48f5785425ee6b5316f8e5f921978397ba632cc6 + * commit_url: https://github.com/openssl/openssl/commit/70cebd74d3592f5272945501b58a60374c4e13af + * cve: CVE-2026-18798 + * license: Apache-2.0 + * function: port_default_packet_handler + * relpath: ssl/quic/quic_port.c + */ + +static void port_default_packet_handler(QUIC_URXE *e, void *arg, + const QUIC_CONN_ID *dcid) +{ + QUIC_PORT *port = arg; + PACKET pkt; + QUIC_PKT_HDR hdr; + QUIC_CHANNEL *ch = NULL, *new_ch = NULL; + QUIC_CONN_ID odcid; + uint8_t gen_new_token = 0; + OSSL_QRX *qrx = NULL, *qrx_ref; + OSSL_QRX *qrx_src = NULL; + OSSL_QRX_ARGS qrx_args = { 0 }; + uint64_t cause_flags = 0; + OSSL_QRX_PKT *qrx_pkt = NULL; + + /* Don't handle anything if we are no longer running. */ + if (!ossl_quic_port_is_running(port)) + goto undesirable; + + if (port_try_handle_stateless_reset(port, e)) + goto undesirable; + + if (dcid != NULL + && ossl_quic_lcidm_lookup(port->lcidm, dcid, NULL, + (void **)&ch)) { + assert(ch != NULL); + ossl_quic_channel_inject(ch, e); + return; + } + + /* + * If we have an incoming packet which doesn't match any existing connection + * we assume this is an attempt to make a new connection. + */ + if (!port->allow_incoming) + goto undesirable; + + /* + * packet without destination connection id is invalid/corrupted here. + * stop wasting CPU cycles now. + */ + if (dcid == NULL) + goto undesirable; + + /* + * We have got a packet for an unknown DCID. This might be an attempt to + * open a new connection. + */ + if (e->data_len < QUIC_MIN_INITIAL_DGRAM_LEN) + goto undesirable; + + if (!PACKET_buf_init(&pkt, ossl_quic_urxe_data(e), e->data_len)) + goto undesirable; + + /* + * We set short_conn_id_len to SIZE_MAX here which will cause the decode + * operation to fail if we get a 1-RTT packet. This is fine since we only + * care about Initial packets. + */ + if (!ossl_quic_wire_decode_pkt_hdr(&pkt, SIZE_MAX, 1, 0, &hdr, NULL, + &cause_flags)) { + /* + * If we fail due to a bad version, we know the packet up to the version + * number was decoded, and we use it below to send a version + * negotiation packet + */ + if ((cause_flags & QUIC_PKT_HDR_DECODE_BAD_VERSION) == 0) + goto undesirable; + } + + switch (hdr.version) { + case QUIC_VERSION_1: + break; + + case QUIC_VERSION_NONE: + default: + + /* + * If we get here, then we have a bogus version, and might need + * to send a version negotiation packet. According to + * RFC 9000 s. 6 and 14.1, we only do so however, if the UDP datagram + * is a minimum of 1200 bytes in size + */ + if (e->data_len < 1200) + goto undesirable; + + /* + * If we don't get a supported version, respond with a ver + * negotiation packet, and discard + * TODO(QUIC FUTURE): Rate limit the reception of these + */ + port_send_version_negotiation(port, &e->peer, &hdr); + goto undesirable; + } + + /* + * We only care about Initial packets which might be trying to establish a + * connection. + */ + if (hdr.type != QUIC_PKT_TYPE_INITIAL) + goto undesirable; + + if (port->max_pending_channels > 0 && ossl_list_incoming_ch_num(&port->incoming_channel_list) >= port->max_pending_channels) + goto undesirable; + + odcid.id_len = 0; + + /* + * Create qrx now so we can check integrity of packet + * which does not belong to any channel. + */ + qrx_args.libctx = port->engine->libctx; + qrx_args.demux = port->demux; + qrx_args.short_conn_id_len = dcid->id_len; + qrx_args.max_deferred = 32; + qrx = ossl_qrx_new(&qrx_args); + if (qrx == NULL) + goto undesirable; + + /* + * Derive secrets for qrx only. + */ + if (!ossl_quic_provide_initial_secret(port->engine->libctx, + port->engine->propq, + &hdr.dst_conn_id, + /* is_server */ 1, + qrx, NULL)) + goto undesirable; + + if (ossl_qrx_validate_initial_packet(qrx, e, (const QUIC_CONN_ID *)dcid) == 0) + goto undesirable; + + if (port->validate_addr == 0) { + /* + * Forget qrx, because it becomes (almost) useless here. We must let + * channel to create a new QRX for connection ID server chooses. The + * validation keys for new DCID will be derived by + * ossl_quic_channel_on_new_conn() when we will be creating channel. + * See RFC 9000 section 7.2 negotiating connection id to better + * understand what's going on here. + * + * Did we say qrx is almost useless? Why? Because qrx remembers packets + * we just validated. Those packets must be injected to channel we are + * going to create. We use qrx_src alias so we can read packets from + * qrx and inject them to channel. + */ + qrx_src = qrx; + qrx = NULL; + } + /* + * TODO(QUIC FUTURE): there should be some logic similar to accounting half-open + * states in TCP. If we reach certain threshold, then we want to + * validate clients. + */ + if (port->validate_addr == 1 && hdr.token == NULL) { + port_send_retry(port, &e->peer, &hdr); + goto undesirable; + } + + /* + * Note, even if we don't enforce the sending of retry frames for + * server address validation, we may still get a token if we sent + * a NEW_TOKEN frame during a prior connection, which we should still + * validate here + */ + if (hdr.token != NULL + && port_validate_token(&hdr, port, &e->peer, + &odcid, &gen_new_token) + == 0) { + /* + * RFC 9000 s 8.1.3 + * When a server receives an Initial packet with an address + * validation token, it MUST attempt to validate the token, + * unless it has already completed address validation. + * If the token is invalid, then the server SHOULD proceed as + * if the client did not have a validated address, + * including potentially sending a Retry packet + * Note: If address validation is disabled, just act like + * the request is valid + */ + if (port->validate_addr == 1) { + /* + * Again: we should consider saving initial encryption level + * secrets to token here to save some CPU cycles. + */ + port_send_retry(port, &e->peer, &hdr); + goto undesirable; + } + + /* + * client is under amplification limit, until it completes + * handshake. + * + * forget qrx so channel can create a new one + * with valid initial encryption level keys. + */ + if (qrx != NULL) { + qrx_src = qrx; + qrx = NULL; + } + } + + qrx_ref = NULL; + if (qrx != NULL) { + /* + * if we are here, then client is validated via retry packet + * (client sent a valid token). In this case the qrx has valid + * secrets set for QUIC initial level encryption. We can pass + * reference to qrx to newly created channel. + * + * Note: port_bind_channel()/channel becomes owner of qrx_ref. + */ + qrx_ref = ossl_qrx_newref(qrx); + if (qrx_ref == NULL) + goto undesirable; + } + port_bind_channel(port, &e->peer, &hdr.dst_conn_id, + &odcid, qrx_ref, &new_ch); + + /* + * if packet validates it gets moved to channel, we've just bound + * to port. + */ + if (new_ch == NULL) + goto undesirable; + + /* + * Generate a token for sending in a later NEW_TOKEN frame + */ + if (gen_new_token == 1) + generate_new_token(new_ch, &e->peer); + + if (qrx_src != NULL) { + /* + * Time to reinject packets from qrx to channel before + * qrx will be destroyed here. + */ + while (ossl_qrx_read_pkt(qrx_src, &qrx_pkt) == 1) + ossl_quic_channel_inject_pkt(new_ch, qrx_pkt); + ossl_qrx_update_pn_space(qrx_src, new_ch->qrx); + /* + * transfer ownership back to qrx; + */ + qrx = qrx_src; + qrx_src = NULL; + } + + /* + * If function reaches this place, then packet got validated in + * ossl_qrx_validate_initial_packet(). Keep in mind the function + * ossl_qrx_validate_initial_packet() decrypts the packet to validate it. + * If packet validation was successful (and it was because we are here), + * then the function puts the packet to qrx->rx_pending. We must not call + * ossl_qrx_inject_urxe() here now, because we don't want to insert + * the packet to qrx->urx_pending which keeps packet waiting for decryption. + * + * We are going to call ossl_quic_demux_release_urxe() to dispose buffer + * which still holds encrypted data. + */ + +undesirable: + ossl_qrx_free(qrx); /* releases reference */ + ossl_qrx_free(qrx_src); + ossl_quic_demux_release_urxe(port->demux, e); +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-18798/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-18798/vuln.c new file mode 100644 index 0000000..9000007 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-18798/vuln.c @@ -0,0 +1,262 @@ +/* Provenance: openssl/openssl port_default_packet_handler (vuln). + * repo: openssl/openssl + * commit: 48f5785425ee6b5316f8e5f921978397ba632cc6 + * parent: 48f5785425ee6b5316f8e5f921978397ba632cc6 + * commit_url: https://github.com/openssl/openssl/commit/70cebd74d3592f5272945501b58a60374c4e13af + * cve: CVE-2026-18798 + * license: Apache-2.0 + * function: port_default_packet_handler + * relpath: ssl/quic/quic_port.c + */ + +static void port_default_packet_handler(QUIC_URXE *e, void *arg, + const QUIC_CONN_ID *dcid) +{ + QUIC_PORT *port = arg; + PACKET pkt; + QUIC_PKT_HDR hdr; + QUIC_CHANNEL *ch = NULL, *new_ch = NULL; + QUIC_CONN_ID odcid; + uint8_t gen_new_token = 0; + OSSL_QRX *qrx = NULL; + OSSL_QRX *qrx_src = NULL; + OSSL_QRX_ARGS qrx_args = { 0 }; + uint64_t cause_flags = 0; + OSSL_QRX_PKT *qrx_pkt = NULL; + + /* Don't handle anything if we are no longer running. */ + if (!ossl_quic_port_is_running(port)) + goto undesirable; + + if (port_try_handle_stateless_reset(port, e)) + goto undesirable; + + if (dcid != NULL + && ossl_quic_lcidm_lookup(port->lcidm, dcid, NULL, + (void **)&ch)) { + assert(ch != NULL); + ossl_quic_channel_inject(ch, e); + return; + } + + /* + * If we have an incoming packet which doesn't match any existing connection + * we assume this is an attempt to make a new connection. + */ + if (!port->allow_incoming) + goto undesirable; + + /* + * packet without destination connection id is invalid/corrupted here. + * stop wasting CPU cycles now. + */ + if (dcid == NULL) + goto undesirable; + + /* + * We have got a packet for an unknown DCID. This might be an attempt to + * open a new connection. + */ + if (e->data_len < QUIC_MIN_INITIAL_DGRAM_LEN) + goto undesirable; + + if (!PACKET_buf_init(&pkt, ossl_quic_urxe_data(e), e->data_len)) + goto undesirable; + + /* + * We set short_conn_id_len to SIZE_MAX here which will cause the decode + * operation to fail if we get a 1-RTT packet. This is fine since we only + * care about Initial packets. + */ + if (!ossl_quic_wire_decode_pkt_hdr(&pkt, SIZE_MAX, 1, 0, &hdr, NULL, + &cause_flags)) { + /* + * If we fail due to a bad version, we know the packet up to the version + * number was decoded, and we use it below to send a version + * negotiation packet + */ + if ((cause_flags & QUIC_PKT_HDR_DECODE_BAD_VERSION) == 0) + goto undesirable; + } + + switch (hdr.version) { + case QUIC_VERSION_1: + break; + + case QUIC_VERSION_NONE: + default: + + /* + * If we get here, then we have a bogus version, and might need + * to send a version negotiation packet. According to + * RFC 9000 s. 6 and 14.1, we only do so however, if the UDP datagram + * is a minimum of 1200 bytes in size + */ + if (e->data_len < 1200) + goto undesirable; + + /* + * If we don't get a supported version, respond with a ver + * negotiation packet, and discard + * TODO(QUIC FUTURE): Rate limit the reception of these + */ + port_send_version_negotiation(port, &e->peer, &hdr); + goto undesirable; + } + + /* + * We only care about Initial packets which might be trying to establish a + * connection. + */ + if (hdr.type != QUIC_PKT_TYPE_INITIAL) + goto undesirable; + + if (port->max_pending_channels > 0 && ossl_list_incoming_ch_num(&port->incoming_channel_list) >= port->max_pending_channels) + goto undesirable; + + odcid.id_len = 0; + + /* + * Create qrx now so we can check integrity of packet + * which does not belong to any channel. + */ + qrx_args.libctx = port->engine->libctx; + qrx_args.demux = port->demux; + qrx_args.short_conn_id_len = dcid->id_len; + qrx_args.max_deferred = 32; + qrx = ossl_qrx_new(&qrx_args); + if (qrx == NULL) + goto undesirable; + + /* + * Derive secrets for qrx only. + */ + if (!ossl_quic_provide_initial_secret(port->engine->libctx, + port->engine->propq, + &hdr.dst_conn_id, + /* is_server */ 1, + qrx, NULL)) + goto undesirable; + + if (ossl_qrx_validate_initial_packet(qrx, e, (const QUIC_CONN_ID *)dcid) == 0) + goto undesirable; + + if (port->validate_addr == 0) { + /* + * Forget qrx, because it becomes (almost) useless here. We must let + * channel to create a new QRX for connection ID server chooses. The + * validation keys for new DCID will be derived by + * ossl_quic_channel_on_new_conn() when we will be creating channel. + * See RFC 9000 section 7.2 negotiating connection id to better + * understand what's going on here. + * + * Did we say qrx is almost useless? Why? Because qrx remembers packets + * we just validated. Those packets must be injected to channel we are + * going to create. We use qrx_src alias so we can read packets from + * qrx and inject them to channel. + */ + qrx_src = qrx; + qrx = NULL; + } + /* + * TODO(QUIC FUTURE): there should be some logic similar to accounting half-open + * states in TCP. If we reach certain threshold, then we want to + * validate clients. + */ + if (port->validate_addr == 1 && hdr.token == NULL) { + port_send_retry(port, &e->peer, &hdr); + goto undesirable; + } + + /* + * Note, even if we don't enforce the sending of retry frames for + * server address validation, we may still get a token if we sent + * a NEW_TOKEN frame during a prior connection, which we should still + * validate here + */ + if (hdr.token != NULL + && port_validate_token(&hdr, port, &e->peer, + &odcid, &gen_new_token) + == 0) { + /* + * RFC 9000 s 8.1.3 + * When a server receives an Initial packet with an address + * validation token, it MUST attempt to validate the token, + * unless it has already completed address validation. + * If the token is invalid, then the server SHOULD proceed as + * if the client did not have a validated address, + * including potentially sending a Retry packet + * Note: If address validation is disabled, just act like + * the request is valid + */ + if (port->validate_addr == 1) { + /* + * Again: we should consider saving initial encryption level + * secrets to token here to save some CPU cycles. + */ + port_send_retry(port, &e->peer, &hdr); + goto undesirable; + } + + /* + * client is under amplification limit, until it completes + * handshake. + * + * forget qrx so channel can create a new one + * with valid initial encryption level keys. + */ + if (qrx != NULL) { + qrx_src = qrx; + qrx = NULL; + } + } + + port_bind_channel(port, &e->peer, &hdr.dst_conn_id, + &odcid, qrx, &new_ch); + + /* + * if packet validates it gets moved to channel, we've just bound + * to port. + */ + if (new_ch == NULL) + goto undesirable; + + /* + * Generate a token for sending in a later NEW_TOKEN frame + */ + if (gen_new_token == 1) + generate_new_token(new_ch, &e->peer); + + if (qrx != NULL) { + /* + * The qrx belongs to channel now, so don't free it. + */ + qrx = NULL; + } else { + /* + * We still need to salvage packets from almost forgotten qrx + * and pass them to channel. + */ + while (ossl_qrx_read_pkt(qrx_src, &qrx_pkt) == 1) + ossl_quic_channel_inject_pkt(new_ch, qrx_pkt); + ossl_qrx_update_pn_space(qrx_src, new_ch->qrx); + } + + /* + * If function reaches this place, then packet got validated in + * ossl_qrx_validate_initial_packet(). Keep in mind the function + * ossl_qrx_validate_initial_packet() decrypts the packet to validate it. + * If packet validation was successful (and it was because we are here), + * then the function puts the packet to qrx->rx_pending. We must not call + * ossl_qrx_inject_urxe() here now, because we don't want to insert + * the packet to qrx->urx_pending which keeps packet waiting for decryption. + * + * We are going to call ossl_quic_demux_release_urxe() to dispose buffer + * which still holds encrypted data. + */ + +undesirable: + ossl_qrx_free(qrx); + ossl_qrx_free(qrx_src); + ossl_quic_demux_release_urxe(port->demux, e); +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-2673/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-2673/fixed.c new file mode 100644 index 0000000..96de026 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-2673/fixed.c @@ -0,0 +1,276 @@ +/* Provenance: openssl/openssl gid_cb (fixed). + * repo: openssl/openssl + * commit: 85977e013f32ceb96aa034c0e741adddc1a05e34 + * parent: 21d525dc846aed171fc886f3da614a6645948f13 + * commit_url: https://github.com/openssl/openssl/commit/85977e013f32ceb96aa034c0e741adddc1a05e34 + * cve: CVE-2026-2673 + * license: Apache-2.0 + * function: gid_cb + * relpath: ssl/t1_lib.c + */ + +static int gid_cb(const char *elem, int len, void *arg) +{ + gid_cb_st *garg = arg; + size_t i, j, k; + uint16_t gid = 0; + int found_group = 0; + char etmp[GROUP_NAME_BUFFER_LENGTH]; + int retval = 1; /* We assume success */ + const char *current_prefix; + int ignore_unknown = 0; + int add_keyshare = 0; + int remove_group = 0; + size_t restored_prefix_index = 0; + char *restored_default_group_string; + int continue_while_loop = 1; + + /* Sanity checks */ + if (garg == NULL || elem == NULL || len <= 0) { + ERR_raise(ERR_LIB_SSL, SSL_R_UNSUPPORTED_CONFIG_VALUE); + return 0; + } + + /* Check the possible prefixes (remark: Leading and trailing spaces already cleared) */ + while (continue_while_loop && len > 0 + && ((current_prefix = strchr(prefixes, elem[0])) != NULL + || OPENSSL_strncasecmp(current_prefix = (char *)DEFAULT_GROUPNAME_FIRST_CHARACTER, elem, 1) == 0)) { + + switch (*current_prefix) { + case TUPLE_DELIMITER_CHARACTER: + /* tuple delimiter not allowed here -> syntax error */ + return -1; + break; + case GROUP_DELIMITER_CHARACTER: + return -1; /* Not a valid prefix for a single group name-> syntax error */ + break; + case KEY_SHARE_INDICATOR_CHARACTER: + if (add_keyshare) + return -1; /* Only single key share prefix allowed -> syntax error */ + add_keyshare = 1; + ++elem; + --len; + break; + case REMOVE_GROUP_INDICATOR_CHARACTER: + if (remove_group) + return -1; /* Only single remove group prefix allowed -> syntax error */ + remove_group = 1; + ++elem; + --len; + break; + case IGNORE_UNKNOWN_GROUP_CHARACTER: + if (ignore_unknown) + return -1; /* Only single ? allowed -> syntax error */ + ignore_unknown = 1; + ++elem; + --len; + break; + default: + /* + * Check whether a DEFAULT[_XYZ] 'pseudo group' (= a built-in + * list of groups) should be added + */ + for (i = 0; i < OSSL_NELEM(default_group_strings); i++) { + if ((size_t)len == (strlen(default_group_strings[i].list_name)) + && OPENSSL_strncasecmp(default_group_strings[i].list_name, elem, len) == 0) { + int saved_first; + + /* + * We're asked to insert an entire list of groups from a + * DEFAULT[_XYZ] 'pseudo group' which we do by + * recursively calling this function (indirectly via + * CONF_parse_list and tuple_cb); essentially, we treat a DEFAULT + * group string like a tuple which is appended to the current tuple + * rather then starting a new tuple. + */ + if (ignore_unknown || remove_group) + return -1; /* removal or ignore not allowed here -> syntax error */ + + /* + * First, we restore any keyshare prefix in a new zero-terminated string + * (if not already present) + */ + restored_default_group_string = OPENSSL_malloc((1 /* max prefix length */ + strlen(default_group_strings[i].group_string) + 1 /* \0 */) * sizeof(char)); + if (restored_default_group_string == NULL) + return 0; + if (add_keyshare + /* Remark: we tolerate a duplicated keyshare indicator here */ + && default_group_strings[i].group_string[0] + != KEY_SHARE_INDICATOR_CHARACTER) + restored_default_group_string[restored_prefix_index++] = KEY_SHARE_INDICATOR_CHARACTER; + + memcpy(restored_default_group_string + restored_prefix_index, + default_group_strings[i].group_string, + strlen(default_group_strings[i].group_string)); + restored_default_group_string[strlen(default_group_strings[i].group_string) + restored_prefix_index] = '\0'; + /* + * Append first tuple of result to current tuple, and don't + * terminate the last tuple until we return to a top-level + * tuple_cb. + */ + saved_first = garg->first; + garg->inner = garg->first = 1; + retval = CONF_parse_list(restored_default_group_string, + TUPLE_DELIMITER_CHARACTER, 1, tuple_cb, garg); + garg->inner = 0; + garg->first = saved_first; + /* We don't need the \0-terminated string anymore */ + OPENSSL_free(restored_default_group_string); + + return retval; + } + } + /* + * If we reached this point, a group name started with a 'd' or 'D', but no request + * for a DEFAULT[_XYZ] 'pseudo group' was detected, hence processing of the group + * name can continue as usual (= the while loop checking prefixes can end) + */ + continue_while_loop = 0; + break; + } + } + + if (len == 0) + return -1; /* Seems we have prefxes without a group name -> syntax error */ + + /* Memory management in case more groups are present compared to initial allocation */ + if (garg->gidcnt == garg->gidmax) { + uint16_t *tmp = OPENSSL_realloc(garg->gid_arr, + (garg->gidmax + GROUPLIST_INCREMENT) * sizeof(*garg->gid_arr)); + + if (tmp == NULL) + return 0; + + garg->gidmax += GROUPLIST_INCREMENT; + garg->gid_arr = tmp; + } + /* Memory management for key share groups */ + if (garg->ksidcnt == garg->ksidmax) { + uint16_t *tmp = OPENSSL_realloc(garg->ksid_arr, + (garg->ksidmax + GROUPLIST_INCREMENT) * sizeof(*garg->ksid_arr)); + + if (tmp == NULL) + return 0; + garg->ksidmax += GROUPLIST_INCREMENT; + garg->ksid_arr = tmp; + } + + if (len > (int)(sizeof(etmp) - 1)) + return -1; /* group name to long -> syntax error */ + + /* + * Prepare addition or removal of a single group by converting + * a group name into its groupID equivalent + */ + + /* Create a \0-terminated string and get the gid for this group if possible */ + memcpy(etmp, elem, len); + etmp[len] = 0; + + /* Get the groupID */ + gid = tls1_group_name2id(garg->ctx, etmp); + /* + * Handle the case where no valid groupID was returned + * e.g. for an unknown group, which we'd ignore (only) if relevant prefix was set + */ + if (gid == 0) { + /* Is it one of the GOST groups ? */ + for (i = 0; i < OSSL_NELEM(name2id_arr); i++) { + if (OPENSSL_strcasecmp(etmp, name2id_arr[i].group_name) == 0) { + gid = name2id_arr[i].groupID; + break; + } + } + if (gid == 0) { /* still not found */ + /* Unknown group - ignore if ignore_unknown; trigger error otherwise */ + retval = ignore_unknown; + goto done; + } + } + + /* Make sure that at least one provider is supporting this groupID */ + found_group = 0; + for (j = 0; j < garg->ctx->group_list_len; j++) + if (garg->ctx->group_list[j].group_id == gid) { + found_group = 1; + break; + } + + /* + * No provider supports this group - ignore if + * ignore_unknown; trigger error otherwise + */ + if (found_group == 0) { + retval = ignore_unknown; + goto done; + } + /* Remove group (and keyshare) from anywhere in the list if present, ignore if not present */ + if (remove_group) { + /* Is the current group specified anywhere in the entire list so far? */ + found_group = 0; + for (i = 0; i < garg->gidcnt; i++) + if (garg->gid_arr[i] == gid) { + found_group = 1; + break; + } + /* The group to remove is at position i in the list of (zero indexed) groups */ + if (found_group) { + /* We remove that group from its position (which is at i)... */ + for (j = i; j < (garg->gidcnt - 1); j++) + garg->gid_arr[j] = garg->gid_arr[j + 1]; /* ...shift remaining groups left ... */ + garg->gidcnt--; /* ..and update the book keeping for the number of groups */ + + /* + * We also must update the number of groups either in a previous tuple (which we + * must identify and check whether it becomes empty due to the deletion) or in + * the current tuple, pending where the deleted group resides + */ + k = 0; + for (j = 0; j < garg->tplcnt; j++) { + k += garg->tuplcnt_arr[j]; + /* Remark: i is zero-indexed, k is one-indexed */ + if (k > i) { /* remove from one of the previous tuples */ + garg->tuplcnt_arr[j]--; + break; /* We took care not to have group duplicates, hence we can stop here */ + } + } + if (k <= i) /* remove from current tuple */ + garg->tuplcnt_arr[j]--; + + /* We also remove the group from the list of keyshares (if present) */ + found_group = 0; + for (i = 0; i < garg->ksidcnt; i++) + if (garg->ksid_arr[i] == gid) { + found_group = 1; + break; + } + if (found_group) { + /* Found, hence we remove that keyshare from its position (which is at i)... */ + for (j = i; j < (garg->ksidcnt - 1); j++) + garg->ksid_arr[j] = garg->ksid_arr[j + 1]; /* shift remaining key shares */ + /* ... and update the book keeping */ + garg->ksidcnt--; + } + } + } else { /* Processing addition of a single new group */ + + /* Check for duplicates */ + for (i = 0; i < garg->gidcnt; i++) + if (garg->gid_arr[i] == gid) { + /* Duplicate group anywhere in the list of groups - ignore */ + goto done; + } + + /* Add the current group to the 'flat' list of groups */ + garg->gid_arr[garg->gidcnt++] = gid; + /* and update the book keeping for the number of groups in current tuple */ + garg->tuplcnt_arr[garg->tplcnt]++; + + /* We want to add a key share for the current group */ + if (add_keyshare) + garg->ksid_arr[garg->ksidcnt++] = gid; + } + +done: + return retval; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-2673/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-2673/vuln.c new file mode 100644 index 0000000..59a6ba9 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-2673/vuln.c @@ -0,0 +1,277 @@ +/* Provenance: openssl/openssl gid_cb (vuln). + * repo: openssl/openssl + * commit: 21d525dc846aed171fc886f3da614a6645948f13 + * parent: 21d525dc846aed171fc886f3da614a6645948f13 + * commit_url: https://github.com/openssl/openssl/commit/85977e013f32ceb96aa034c0e741adddc1a05e34 + * cve: CVE-2026-2673 + * license: Apache-2.0 + * function: gid_cb + * relpath: ssl/t1_lib.c + */ + +static int gid_cb(const char *elem, int len, void *arg) +{ + gid_cb_st *garg = arg; + size_t i, j, k; + uint16_t gid = 0; + int found_group = 0; + char etmp[GROUP_NAME_BUFFER_LENGTH]; + int retval = 1; /* We assume success */ + const char *current_prefix; + int ignore_unknown = 0; + int add_keyshare = 0; + int remove_group = 0; + size_t restored_prefix_index = 0; + char *restored_default_group_string; + int continue_while_loop = 1; + + /* Sanity checks */ + if (garg == NULL || elem == NULL || len <= 0) { + ERR_raise(ERR_LIB_SSL, SSL_R_UNSUPPORTED_CONFIG_VALUE); + return 0; + } + + /* Check the possible prefixes (remark: Leading and trailing spaces already cleared) */ + while (continue_while_loop && len > 0 + && ((current_prefix = strchr(prefixes, elem[0])) != NULL + || OPENSSL_strncasecmp(current_prefix = (char *)DEFAULT_GROUPNAME_FIRST_CHARACTER, elem, 1) == 0)) { + + switch (*current_prefix) { + case TUPLE_DELIMITER_CHARACTER: + /* tuple delimiter not allowed here -> syntax error */ + return -1; + break; + case GROUP_DELIMITER_CHARACTER: + return -1; /* Not a valid prefix for a single group name-> syntax error */ + break; + case KEY_SHARE_INDICATOR_CHARACTER: + if (add_keyshare) + return -1; /* Only single key share prefix allowed -> syntax error */ + add_keyshare = 1; + ++elem; + --len; + break; + case REMOVE_GROUP_INDICATOR_CHARACTER: + if (remove_group) + return -1; /* Only single remove group prefix allowed -> syntax error */ + remove_group = 1; + ++elem; + --len; + break; + case IGNORE_UNKNOWN_GROUP_CHARACTER: + if (ignore_unknown) + return -1; /* Only single ? allowed -> syntax error */ + ignore_unknown = 1; + ++elem; + --len; + break; + default: + /* + * Check whether a DEFAULT[_XYZ] 'pseudo group' (= a built-in + * list of groups) should be added + */ + for (i = 0; i < OSSL_NELEM(default_group_strings); i++) { + if ((size_t)len == (strlen(default_group_strings[i].list_name)) + && OPENSSL_strncasecmp(default_group_strings[i].list_name, elem, len) == 0) { + /* + * We're asked to insert an entire list of groups from a + * DEFAULT[_XYZ] 'pseudo group' which we do by + * recursively calling this function (indirectly via + * CONF_parse_list and tuple_cb); essentially, we treat a DEFAULT + * group string like a tuple which is appended to the current tuple + * rather then starting a new tuple. Variable tuple_mode is the flag which + * controls append tuple vs start new tuple. + */ + + if (ignore_unknown || remove_group) + return -1; /* removal or ignore not allowed here -> syntax error */ + + /* + * First, we restore any keyshare prefix in a new zero-terminated string + * (if not already present) + */ + restored_default_group_string = OPENSSL_malloc((1 /* max prefix length */ + strlen(default_group_strings[i].group_string) + 1 /* \0 */) * sizeof(char)); + if (restored_default_group_string == NULL) + return 0; + if (add_keyshare + /* Remark: we tolerate a duplicated keyshare indicator here */ + && default_group_strings[i].group_string[0] + != KEY_SHARE_INDICATOR_CHARACTER) + restored_default_group_string[restored_prefix_index++] = KEY_SHARE_INDICATOR_CHARACTER; + + memcpy(restored_default_group_string + restored_prefix_index, + default_group_strings[i].group_string, + strlen(default_group_strings[i].group_string)); + restored_default_group_string[strlen(default_group_strings[i].group_string) + restored_prefix_index] = '\0'; + /* We execute the recursive call */ + garg->ignore_unknown_default = 1; /* We ignore unknown groups for DEFAULT_XYZ */ + /* we enforce group mode (= append tuple) for DEFAULT_XYZ group lists */ + garg->tuple_mode = 0; + /* We use the tuple_cb callback to process the pseudo group tuple */ + retval = CONF_parse_list(restored_default_group_string, + TUPLE_DELIMITER_CHARACTER, 1, tuple_cb, garg); + garg->tuple_mode = 1; /* next call to tuple_cb will again start new tuple */ + garg->ignore_unknown_default = 0; /* reset to original value */ + /* We don't need the \0-terminated string anymore */ + OPENSSL_free(restored_default_group_string); + + return retval; + } + } + /* + * If we reached this point, a group name started with a 'd' or 'D', but no request + * for a DEFAULT[_XYZ] 'pseudo group' was detected, hence processing of the group + * name can continue as usual (= the while loop checking prefixes can end) + */ + continue_while_loop = 0; + break; + } + } + + if (len == 0) + return -1; /* Seems we have prefxes without a group name -> syntax error */ + + if (garg->ignore_unknown_default == 1) /* Always ignore unknown groups for DEFAULT[_XYZ] */ + ignore_unknown = 1; + + /* Memory management in case more groups are present compared to initial allocation */ + if (garg->gidcnt == garg->gidmax) { + uint16_t *tmp = OPENSSL_realloc(garg->gid_arr, + (garg->gidmax + GROUPLIST_INCREMENT) * sizeof(*garg->gid_arr)); + + if (tmp == NULL) + return 0; + + garg->gidmax += GROUPLIST_INCREMENT; + garg->gid_arr = tmp; + } + /* Memory management for key share groups */ + if (garg->ksidcnt == garg->ksidmax) { + uint16_t *tmp = OPENSSL_realloc(garg->ksid_arr, + (garg->ksidmax + GROUPLIST_INCREMENT) * sizeof(*garg->ksid_arr)); + + if (tmp == NULL) + return 0; + garg->ksidmax += GROUPLIST_INCREMENT; + garg->ksid_arr = tmp; + } + + if (len > (int)(sizeof(etmp) - 1)) + return -1; /* group name to long -> syntax error */ + + /* + * Prepare addition or removal of a single group by converting + * a group name into its groupID equivalent + */ + + /* Create a \0-terminated string and get the gid for this group if possible */ + memcpy(etmp, elem, len); + etmp[len] = 0; + + /* Get the groupID */ + gid = tls1_group_name2id(garg->ctx, etmp); + /* + * Handle the case where no valid groupID was returned + * e.g. for an unknown group, which we'd ignore (only) if relevant prefix was set + */ + if (gid == 0) { + /* Is it one of the GOST groups ? */ + for (i = 0; i < OSSL_NELEM(name2id_arr); i++) { + if (OPENSSL_strcasecmp(etmp, name2id_arr[i].group_name) == 0) { + gid = name2id_arr[i].groupID; + break; + } + } + if (gid == 0) { /* still not found */ + /* Unknown group - ignore if ignore_unknown; trigger error otherwise */ + retval = ignore_unknown; + goto done; + } + } + + /* Make sure that at least one provider is supporting this groupID */ + found_group = 0; + for (j = 0; j < garg->ctx->group_list_len; j++) + if (garg->ctx->group_list[j].group_id == gid) { + found_group = 1; + break; + } + + /* + * No provider supports this group - ignore if + * ignore_unknown; trigger error otherwise + */ + if (found_group == 0) { + retval = ignore_unknown; + goto done; + } + /* Remove group (and keyshare) from anywhere in the list if present, ignore if not present */ + if (remove_group) { + /* Is the current group specified anywhere in the entire list so far? */ + found_group = 0; + for (i = 0; i < garg->gidcnt; i++) + if (garg->gid_arr[i] == gid) { + found_group = 1; + break; + } + /* The group to remove is at position i in the list of (zero indexed) groups */ + if (found_group) { + /* We remove that group from its position (which is at i)... */ + for (j = i; j < (garg->gidcnt - 1); j++) + garg->gid_arr[j] = garg->gid_arr[j + 1]; /* ...shift remaining groups left ... */ + garg->gidcnt--; /* ..and update the book keeping for the number of groups */ + + /* + * We also must update the number of groups either in a previous tuple (which we + * must identify and check whether it becomes empty due to the deletion) or in + * the current tuple, pending where the deleted group resides + */ + k = 0; + for (j = 0; j < garg->tplcnt; j++) { + k += garg->tuplcnt_arr[j]; + /* Remark: i is zero-indexed, k is one-indexed */ + if (k > i) { /* remove from one of the previous tuples */ + garg->tuplcnt_arr[j]--; + break; /* We took care not to have group duplicates, hence we can stop here */ + } + } + if (k <= i) /* remove from current tuple */ + garg->tuplcnt_arr[j]--; + + /* We also remove the group from the list of keyshares (if present) */ + found_group = 0; + for (i = 0; i < garg->ksidcnt; i++) + if (garg->ksid_arr[i] == gid) { + found_group = 1; + break; + } + if (found_group) { + /* Found, hence we remove that keyshare from its position (which is at i)... */ + for (j = i; j < (garg->ksidcnt - 1); j++) + garg->ksid_arr[j] = garg->ksid_arr[j + 1]; /* shift remaining key shares */ + /* ... and update the book keeping */ + garg->ksidcnt--; + } + } + } else { /* Processing addition of a single new group */ + + /* Check for duplicates */ + for (i = 0; i < garg->gidcnt; i++) + if (garg->gid_arr[i] == gid) { + /* Duplicate group anywhere in the list of groups - ignore */ + goto done; + } + + /* Add the current group to the 'flat' list of groups */ + garg->gid_arr[garg->gidcnt++] = gid; + /* and update the book keeping for the number of groups in current tuple */ + garg->tuplcnt_arr[garg->tplcnt]++; + + /* We memorize if needed that we want to add a key share for the current group */ + if (add_keyshare) + garg->ksid_arr[garg->ksidcnt++] = gid; + } + +done: + return retval; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-28388/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-28388/fixed.c new file mode 100644 index 0000000..6beae78 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-28388/fixed.c @@ -0,0 +1,37 @@ +/* Provenance: openssl/openssl check_delta_base (fixed). + * repo: openssl/openssl + * commit: 59c3b3158553ab53275bbbccca5cb305d591cf2e + * parent: d044f9252fe9a54001986fb4eb4e32076a056527 + * commit_url: https://github.com/openssl/openssl/commit/59c3b3158553ab53275bbbccca5cb305d591cf2e + * cve: CVE-2026-28388 + * license: Apache-2.0 + * function: check_delta_base + * relpath: crypto/x509/x509_vfy.c + */ + +static int check_delta_base(X509_CRL *delta, X509_CRL *base) +{ + /* Delta CRL must be a delta */ + if (delta->base_crl_number == NULL) + return 0; + /* Base must have a CRL number */ + if (base->crl_number == NULL) + return 0; + /* Issuer names must match */ + if (X509_NAME_cmp(X509_CRL_get_issuer(base), + X509_CRL_get_issuer(delta)) + != 0) + return 0; + /* AKID and IDP must match */ + if (!crl_extension_match(delta, base, NID_authority_key_identifier)) + return 0; + if (!crl_extension_match(delta, base, NID_issuing_distribution_point)) + return 0; + /* Delta CRL base number must not exceed Full CRL number. */ + if (ASN1_INTEGER_cmp(delta->base_crl_number, base->crl_number) > 0) + return 0; + /* Delta CRL number must exceed full CRL number */ + if (delta->crl_number == NULL) + return 0; + return ASN1_INTEGER_cmp(delta->crl_number, base->crl_number) > 0; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-28388/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-28388/vuln.c new file mode 100644 index 0000000..84b65c6 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-28388/vuln.c @@ -0,0 +1,35 @@ +/* Provenance: openssl/openssl check_delta_base (vuln). + * repo: openssl/openssl + * commit: d044f9252fe9a54001986fb4eb4e32076a056527 + * parent: d044f9252fe9a54001986fb4eb4e32076a056527 + * commit_url: https://github.com/openssl/openssl/commit/59c3b3158553ab53275bbbccca5cb305d591cf2e + * cve: CVE-2026-28388 + * license: Apache-2.0 + * function: check_delta_base + * relpath: crypto/x509/x509_vfy.c + */ + +static int check_delta_base(X509_CRL *delta, X509_CRL *base) +{ + /* Delta CRL must be a delta */ + if (delta->base_crl_number == NULL) + return 0; + /* Base must have a CRL number */ + if (base->crl_number == NULL) + return 0; + /* Issuer names must match */ + if (X509_NAME_cmp(X509_CRL_get_issuer(base), + X509_CRL_get_issuer(delta)) + != 0) + return 0; + /* AKID and IDP must match */ + if (!crl_extension_match(delta, base, NID_authority_key_identifier)) + return 0; + if (!crl_extension_match(delta, base, NID_issuing_distribution_point)) + return 0; + /* Delta CRL base number must not exceed Full CRL number. */ + if (ASN1_INTEGER_cmp(delta->base_crl_number, base->crl_number) > 0) + return 0; + /* Delta CRL number must exceed full CRL number */ + return ASN1_INTEGER_cmp(delta->crl_number, base->crl_number) > 0; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-28389-dh_cms_set_shared_info/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-28389-dh_cms_set_shared_info/fixed.c new file mode 100644 index 0000000..24b644e --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-28389-dh_cms_set_shared_info/fixed.c @@ -0,0 +1,96 @@ +/* Provenance: openssl/openssl dh_cms_set_shared_info (fixed). + * repo: openssl/openssl + * commit: 7b5274e812400cacb6f3be4c2df5340923fa807f + * parent: 72ec3e38c87f71f5c50ae3b16cc34d8371c71bb9 + * commit_url: https://github.com/openssl/openssl/commit/7b5274e812400cacb6f3be4c2df5340923fa807f + * cve: CVE-2026-28389 + * license: Apache-2.0 + * function: dh_cms_set_shared_info + * relpath: crypto/cms/cms_dh.c + */ + +static int dh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri) +{ + int rv = 0; + X509_ALGOR *alg, *kekalg = NULL; + ASN1_OCTET_STRING *ukm; + const unsigned char *p; + unsigned char *dukm = NULL; + size_t dukmlen = 0; + int keylen, plen; + EVP_CIPHER *kekcipher = NULL; + EVP_CIPHER_CTX *kekctx; + const ASN1_OBJECT *aoid; + const void *parameter = NULL; + int ptype = 0; + char name[OSSL_MAX_NAME_SIZE]; + + if (!CMS_RecipientInfo_kari_get0_alg(ri, &alg, &ukm)) + goto err; + + X509_ALGOR_get0(&aoid, &ptype, ¶meter, alg); + + /* + * For DH we only have one OID permissible. If ever any more get defined + * we will need something cleverer. + */ + if (OBJ_obj2nid(aoid) != NID_id_smime_alg_ESDH) { + ERR_raise(ERR_LIB_CMS, CMS_R_KDF_PARAMETER_ERROR); + goto err; + } + + if (EVP_PKEY_CTX_set_dh_kdf_type(pctx, EVP_PKEY_DH_KDF_X9_42) <= 0 + || EVP_PKEY_CTX_set_dh_kdf_md(pctx, EVP_sha1()) <= 0) + goto err; + + if (ptype != V_ASN1_SEQUENCE) + goto err; + + p = ASN1_STRING_get0_data(parameter); + plen = ASN1_STRING_length(parameter); + kekalg = d2i_X509_ALGOR(NULL, &p, plen); + if (kekalg == NULL) + goto err; + kekctx = CMS_RecipientInfo_kari_get0_ctx(ri); + if (kekctx == NULL) + goto err; + + if (OBJ_obj2txt(name, sizeof(name), kekalg->algorithm, 0) <= 0) + goto err; + + kekcipher = EVP_CIPHER_fetch(pctx->libctx, name, pctx->propquery); + if (kekcipher == NULL + || EVP_CIPHER_get_mode(kekcipher) != EVP_CIPH_WRAP_MODE) + goto err; + if (!EVP_EncryptInit_ex(kekctx, kekcipher, NULL, NULL, NULL)) + goto err; + if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0) + goto err; + + keylen = EVP_CIPHER_CTX_get_key_length(kekctx); + if (EVP_PKEY_CTX_set_dh_kdf_outlen(pctx, keylen) <= 0) + goto err; + /* Use OBJ_nid2obj to ensure we use built in OID that isn't freed */ + if (EVP_PKEY_CTX_set0_dh_kdf_oid(pctx, + OBJ_nid2obj(EVP_CIPHER_get_type(kekcipher))) + <= 0) + goto err; + + if (ukm != NULL) { + dukmlen = ASN1_STRING_length(ukm); + dukm = OPENSSL_memdup(ASN1_STRING_get0_data(ukm), dukmlen); + if (dukm == NULL) + goto err; + } + + if (EVP_PKEY_CTX_set0_dh_kdf_ukm(pctx, dukm, dukmlen) <= 0) + goto err; + dukm = NULL; + + rv = 1; +err: + X509_ALGOR_free(kekalg); + EVP_CIPHER_free(kekcipher); + OPENSSL_free(dukm); + return rv; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-28389-dh_cms_set_shared_info/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-28389-dh_cms_set_shared_info/vuln.c new file mode 100644 index 0000000..1558e3c --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-28389-dh_cms_set_shared_info/vuln.c @@ -0,0 +1,91 @@ +/* Provenance: openssl/openssl dh_cms_set_shared_info (vuln). + * repo: openssl/openssl + * commit: 72ec3e38c87f71f5c50ae3b16cc34d8371c71bb9 + * parent: 72ec3e38c87f71f5c50ae3b16cc34d8371c71bb9 + * commit_url: https://github.com/openssl/openssl/commit/7b5274e812400cacb6f3be4c2df5340923fa807f + * cve: CVE-2026-28389 + * license: Apache-2.0 + * function: dh_cms_set_shared_info + * relpath: crypto/cms/cms_dh.c + */ + +static int dh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri) +{ + int rv = 0; + X509_ALGOR *alg, *kekalg = NULL; + ASN1_OCTET_STRING *ukm; + const unsigned char *p; + unsigned char *dukm = NULL; + size_t dukmlen = 0; + int keylen, plen; + EVP_CIPHER *kekcipher = NULL; + EVP_CIPHER_CTX *kekctx; + char name[OSSL_MAX_NAME_SIZE]; + + if (!CMS_RecipientInfo_kari_get0_alg(ri, &alg, &ukm)) + goto err; + + /* + * For DH we only have one OID permissible. If ever any more get defined + * we will need something cleverer. + */ + if (OBJ_obj2nid(alg->algorithm) != NID_id_smime_alg_ESDH) { + ERR_raise(ERR_LIB_CMS, CMS_R_KDF_PARAMETER_ERROR); + goto err; + } + + if (EVP_PKEY_CTX_set_dh_kdf_type(pctx, EVP_PKEY_DH_KDF_X9_42) <= 0 + || EVP_PKEY_CTX_set_dh_kdf_md(pctx, EVP_sha1()) <= 0) + goto err; + + if (alg->parameter->type != V_ASN1_SEQUENCE) + goto err; + + p = alg->parameter->value.sequence->data; + plen = alg->parameter->value.sequence->length; + kekalg = d2i_X509_ALGOR(NULL, &p, plen); + if (kekalg == NULL) + goto err; + kekctx = CMS_RecipientInfo_kari_get0_ctx(ri); + if (kekctx == NULL) + goto err; + + if (OBJ_obj2txt(name, sizeof(name), kekalg->algorithm, 0) <= 0) + goto err; + + kekcipher = EVP_CIPHER_fetch(pctx->libctx, name, pctx->propquery); + if (kekcipher == NULL + || EVP_CIPHER_get_mode(kekcipher) != EVP_CIPH_WRAP_MODE) + goto err; + if (!EVP_EncryptInit_ex(kekctx, kekcipher, NULL, NULL, NULL)) + goto err; + if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0) + goto err; + + keylen = EVP_CIPHER_CTX_get_key_length(kekctx); + if (EVP_PKEY_CTX_set_dh_kdf_outlen(pctx, keylen) <= 0) + goto err; + /* Use OBJ_nid2obj to ensure we use built in OID that isn't freed */ + if (EVP_PKEY_CTX_set0_dh_kdf_oid(pctx, + OBJ_nid2obj(EVP_CIPHER_get_type(kekcipher))) + <= 0) + goto err; + + if (ukm != NULL) { + dukmlen = ASN1_STRING_length(ukm); + dukm = OPENSSL_memdup(ASN1_STRING_get0_data(ukm), dukmlen); + if (dukm == NULL) + goto err; + } + + if (EVP_PKEY_CTX_set0_dh_kdf_ukm(pctx, dukm, dukmlen) <= 0) + goto err; + dukm = NULL; + + rv = 1; +err: + X509_ALGOR_free(kekalg); + EVP_CIPHER_free(kekcipher); + OPENSSL_free(dukm); + return rv; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-28389-ecdh_cms_set_shared_info/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-28389-ecdh_cms_set_shared_info/fixed.c new file mode 100644 index 0000000..8382afc --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-28389-ecdh_cms_set_shared_info/fixed.c @@ -0,0 +1,77 @@ +/* Provenance: openssl/openssl ecdh_cms_set_shared_info (fixed). + * repo: openssl/openssl + * commit: 7b5274e812400cacb6f3be4c2df5340923fa807f + * parent: 72ec3e38c87f71f5c50ae3b16cc34d8371c71bb9 + * commit_url: https://github.com/openssl/openssl/commit/7b5274e812400cacb6f3be4c2df5340923fa807f + * cve: CVE-2026-28389 + * license: Apache-2.0 + * function: ecdh_cms_set_shared_info + * relpath: crypto/cms/cms_ec.c + */ + +static int ecdh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri) +{ + int rv = 0; + X509_ALGOR *alg, *kekalg = NULL; + ASN1_OCTET_STRING *ukm; + const unsigned char *p; + unsigned char *der = NULL; + int plen, keylen; + EVP_CIPHER *kekcipher = NULL; + EVP_CIPHER_CTX *kekctx; + const ASN1_OBJECT *aoid = NULL; + int ptype = 0; + const void *parameter = NULL; + + char name[OSSL_MAX_NAME_SIZE]; + + if (!CMS_RecipientInfo_kari_get0_alg(ri, &alg, &ukm)) + return 0; + + X509_ALGOR_get0(&aoid, &ptype, ¶meter, alg); + + if (!ecdh_cms_set_kdf_param(pctx, OBJ_obj2nid(aoid))) { + ERR_raise(ERR_LIB_CMS, CMS_R_KDF_PARAMETER_ERROR); + return 0; + } + + if (ptype != V_ASN1_SEQUENCE) + return 0; + + p = ASN1_STRING_get0_data(parameter); + plen = ASN1_STRING_length(parameter); + kekalg = d2i_X509_ALGOR(NULL, &p, plen); + if (kekalg == NULL) + goto err; + kekctx = CMS_RecipientInfo_kari_get0_ctx(ri); + if (kekctx == NULL) + goto err; + OBJ_obj2txt(name, sizeof(name), kekalg->algorithm, 0); + kekcipher = EVP_CIPHER_fetch(pctx->libctx, name, pctx->propquery); + if (kekcipher == NULL || EVP_CIPHER_get_mode(kekcipher) != EVP_CIPH_WRAP_MODE) + goto err; + if (!EVP_EncryptInit_ex(kekctx, kekcipher, NULL, NULL, NULL)) + goto err; + if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0) + goto err; + + keylen = EVP_CIPHER_CTX_get_key_length(kekctx); + if (EVP_PKEY_CTX_set_ecdh_kdf_outlen(pctx, keylen) <= 0) + goto err; + + plen = CMS_SharedInfo_encode(&der, kekalg, ukm, keylen); + + if (plen <= 0) + goto err; + + if (EVP_PKEY_CTX_set0_ecdh_kdf_ukm(pctx, der, plen) <= 0) + goto err; + der = NULL; + + rv = 1; +err: + EVP_CIPHER_free(kekcipher); + X509_ALGOR_free(kekalg); + OPENSSL_free(der); + return rv; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-28389-ecdh_cms_set_shared_info/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-28389-ecdh_cms_set_shared_info/vuln.c new file mode 100644 index 0000000..d6e7627 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-28389-ecdh_cms_set_shared_info/vuln.c @@ -0,0 +1,71 @@ +/* Provenance: openssl/openssl ecdh_cms_set_shared_info (vuln). + * repo: openssl/openssl + * commit: 72ec3e38c87f71f5c50ae3b16cc34d8371c71bb9 + * parent: 72ec3e38c87f71f5c50ae3b16cc34d8371c71bb9 + * commit_url: https://github.com/openssl/openssl/commit/7b5274e812400cacb6f3be4c2df5340923fa807f + * cve: CVE-2026-28389 + * license: Apache-2.0 + * function: ecdh_cms_set_shared_info + * relpath: crypto/cms/cms_ec.c + */ + +static int ecdh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri) +{ + int rv = 0; + X509_ALGOR *alg, *kekalg = NULL; + ASN1_OCTET_STRING *ukm; + const unsigned char *p; + unsigned char *der = NULL; + int plen, keylen; + EVP_CIPHER *kekcipher = NULL; + EVP_CIPHER_CTX *kekctx; + char name[OSSL_MAX_NAME_SIZE]; + + if (!CMS_RecipientInfo_kari_get0_alg(ri, &alg, &ukm)) + return 0; + + if (!ecdh_cms_set_kdf_param(pctx, OBJ_obj2nid(alg->algorithm))) { + ERR_raise(ERR_LIB_CMS, CMS_R_KDF_PARAMETER_ERROR); + return 0; + } + + if (alg->parameter->type != V_ASN1_SEQUENCE) + return 0; + + p = alg->parameter->value.sequence->data; + plen = alg->parameter->value.sequence->length; + kekalg = d2i_X509_ALGOR(NULL, &p, plen); + if (kekalg == NULL) + goto err; + kekctx = CMS_RecipientInfo_kari_get0_ctx(ri); + if (kekctx == NULL) + goto err; + OBJ_obj2txt(name, sizeof(name), kekalg->algorithm, 0); + kekcipher = EVP_CIPHER_fetch(pctx->libctx, name, pctx->propquery); + if (kekcipher == NULL || EVP_CIPHER_get_mode(kekcipher) != EVP_CIPH_WRAP_MODE) + goto err; + if (!EVP_EncryptInit_ex(kekctx, kekcipher, NULL, NULL, NULL)) + goto err; + if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0) + goto err; + + keylen = EVP_CIPHER_CTX_get_key_length(kekctx); + if (EVP_PKEY_CTX_set_ecdh_kdf_outlen(pctx, keylen) <= 0) + goto err; + + plen = CMS_SharedInfo_encode(&der, kekalg, ukm, keylen); + + if (plen <= 0) + goto err; + + if (EVP_PKEY_CTX_set0_ecdh_kdf_ukm(pctx, der, plen) <= 0) + goto err; + der = NULL; + + rv = 1; +err: + EVP_CIPHER_free(kekcipher); + X509_ALGOR_free(kekalg); + OPENSSL_free(der); + return rv; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-28389/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-28389/fixed.c new file mode 100644 index 0000000..304f801 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-28389/fixed.c @@ -0,0 +1,92 @@ +/* Provenance: openssl/openssl rsa_cms_decrypt (fixed). + * repo: openssl/openssl + * commit: af2a5fecd3e71a29e7568f9c1453dec5cebbaff4 + * parent: 6e74b1275cbc1fd1cf7ba32f662602d68501f6ca + * commit_url: https://github.com/openssl/openssl/commit/af2a5fecd3e71a29e7568f9c1453dec5cebbaff4 + * cve: CVE-2026-28389 + * license: Apache-2.0 + * function: rsa_cms_decrypt + * relpath: crypto/cms/cms_rsa.c + */ + +static int rsa_cms_decrypt(CMS_RecipientInfo *ri) +{ + EVP_PKEY_CTX *pkctx; + X509_ALGOR *cmsalg; + int nid; + int rv = -1; + const unsigned char *label = NULL; + int labellen = 0; + const EVP_MD *mgf1md = NULL, *md = NULL; + RSA_OAEP_PARAMS *oaep; + const ASN1_OBJECT *aoid; + const void *parameter = NULL; + int ptype = 0; + + pkctx = CMS_RecipientInfo_get0_pkey_ctx(ri); + if (pkctx == NULL) + return 0; + if (!CMS_RecipientInfo_ktri_get0_algs(ri, NULL, NULL, &cmsalg)) + return -1; + nid = OBJ_obj2nid(cmsalg->algorithm); + if (nid == NID_rsaEncryption) + return 1; + if (nid != NID_rsaesOaep) { + ERR_raise(ERR_LIB_CMS, CMS_R_UNSUPPORTED_ENCRYPTION_TYPE); + return -1; + } + /* Decode OAEP parameters */ + oaep = rsa_oaep_decode(cmsalg); + + if (oaep == NULL) { + ERR_raise(ERR_LIB_CMS, CMS_R_INVALID_OAEP_PARAMETERS); + goto err; + } + + mgf1md = ossl_x509_algor_get_md(oaep->maskHash); + if (mgf1md == NULL) + goto err; + md = ossl_x509_algor_get_md(oaep->hashFunc); + if (md == NULL) + goto err; + + if (oaep->pSourceFunc != NULL) { + X509_ALGOR_get0(&aoid, &ptype, ¶meter, oaep->pSourceFunc); + + if (OBJ_obj2nid(aoid) != NID_pSpecified) { + ERR_raise(ERR_LIB_CMS, CMS_R_UNSUPPORTED_LABEL_SOURCE); + goto err; + } + if (ptype != V_ASN1_OCTET_STRING) { + ERR_raise(ERR_LIB_CMS, CMS_R_INVALID_LABEL); + goto err; + } + + label = ASN1_STRING_get0_data(parameter); + labellen = ASN1_STRING_length(parameter); + } + + if (EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_OAEP_PADDING) <= 0) + goto err; + if (EVP_PKEY_CTX_set_rsa_oaep_md(pkctx, md) <= 0) + goto err; + if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkctx, mgf1md) <= 0) + goto err; + if (label != NULL) { + unsigned char *dup_label = OPENSSL_memdup(label, labellen); + + if (dup_label == NULL) + goto err; + + if (EVP_PKEY_CTX_set0_rsa_oaep_label(pkctx, dup_label, labellen) <= 0) { + OPENSSL_free(dup_label); + goto err; + } + } + /* Carry on */ + rv = 1; + +err: + RSA_OAEP_PARAMS_free(oaep); + return rv; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-28389/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-28389/vuln.c new file mode 100644 index 0000000..69d40c3 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-28389/vuln.c @@ -0,0 +1,85 @@ +/* Provenance: openssl/openssl rsa_cms_decrypt (vuln). + * repo: openssl/openssl + * commit: 6e74b1275cbc1fd1cf7ba32f662602d68501f6ca + * parent: 6e74b1275cbc1fd1cf7ba32f662602d68501f6ca + * commit_url: https://github.com/openssl/openssl/commit/af2a5fecd3e71a29e7568f9c1453dec5cebbaff4 + * cve: CVE-2026-28389 + * license: Apache-2.0 + * function: rsa_cms_decrypt + * relpath: crypto/cms/cms_rsa.c + */ + +static int rsa_cms_decrypt(CMS_RecipientInfo *ri) +{ + EVP_PKEY_CTX *pkctx; + X509_ALGOR *cmsalg; + int nid; + int rv = -1; + unsigned char *label = NULL; + int labellen = 0; + const EVP_MD *mgf1md = NULL, *md = NULL; + RSA_OAEP_PARAMS *oaep; + + pkctx = CMS_RecipientInfo_get0_pkey_ctx(ri); + if (pkctx == NULL) + return 0; + if (!CMS_RecipientInfo_ktri_get0_algs(ri, NULL, NULL, &cmsalg)) + return -1; + nid = OBJ_obj2nid(cmsalg->algorithm); + if (nid == NID_rsaEncryption) + return 1; + if (nid != NID_rsaesOaep) { + ERR_raise(ERR_LIB_CMS, CMS_R_UNSUPPORTED_ENCRYPTION_TYPE); + return -1; + } + /* Decode OAEP parameters */ + oaep = rsa_oaep_decode(cmsalg); + + if (oaep == NULL) { + ERR_raise(ERR_LIB_CMS, CMS_R_INVALID_OAEP_PARAMETERS); + goto err; + } + + mgf1md = ossl_x509_algor_get_md(oaep->maskHash); + if (mgf1md == NULL) + goto err; + md = ossl_x509_algor_get_md(oaep->hashFunc); + if (md == NULL) + goto err; + + if (oaep->pSourceFunc != NULL) { + X509_ALGOR *plab = oaep->pSourceFunc; + + if (OBJ_obj2nid(plab->algorithm) != NID_pSpecified) { + ERR_raise(ERR_LIB_CMS, CMS_R_UNSUPPORTED_LABEL_SOURCE); + goto err; + } + if (plab->parameter->type != V_ASN1_OCTET_STRING) { + ERR_raise(ERR_LIB_CMS, CMS_R_INVALID_LABEL); + goto err; + } + + label = plab->parameter->value.octet_string->data; + /* Stop label being freed when OAEP parameters are freed */ + plab->parameter->value.octet_string->data = NULL; + labellen = plab->parameter->value.octet_string->length; + } + + if (EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_OAEP_PADDING) <= 0) + goto err; + if (EVP_PKEY_CTX_set_rsa_oaep_md(pkctx, md) <= 0) + goto err; + if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkctx, mgf1md) <= 0) + goto err; + if (label != NULL + && EVP_PKEY_CTX_set0_rsa_oaep_label(pkctx, label, labellen) <= 0) { + OPENSSL_free(label); + goto err; + } + /* Carry on */ + rv = 1; + +err: + RSA_OAEP_PARAMS_free(oaep); + return rv; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-31789/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-31789/fixed.c new file mode 100644 index 0000000..1c14535 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-31789/fixed.c @@ -0,0 +1,55 @@ +/* Provenance: openssl/openssl buf2hexstr_sep (fixed). + * repo: openssl/openssl + * commit: a91e537d16d74050dbde50bb0dfb1fe9930f0521 + * parent: b7ae7a093997b5cd549bc21cccd715510fef86c0 + * commit_url: https://github.com/openssl/openssl/commit/a91e537d16d74050dbde50bb0dfb1fe9930f0521 + * cve: CVE-2026-31789 + * license: Apache-2.0 + * function: buf2hexstr_sep + * relpath: crypto/o_str.c + */ + +static int buf2hexstr_sep(char *str, size_t str_n, size_t *strlength, + const unsigned char *buf, size_t buflen, + const char sep) +{ + static const char hexdig[] = "0123456789ABCDEF"; + const unsigned char *p; + char *q; + size_t i; + int has_sep = (sep != CH_ZERO); + size_t len = has_sep ? buflen * 3 : 1 + buflen * 2; + + if (buflen > (has_sep ? SIZE_MAX / 3 : (SIZE_MAX - 1) / 2)) { + ERR_raise(ERR_LIB_CRYPTO, CRYPTO_R_TOO_MANY_BYTES); + return 0; + } + + if (len == 0) + ++len; + if (strlength != NULL) + *strlength = len; + if (str == NULL) + return 1; + + if (str_n < len) { + ERR_raise(ERR_LIB_CRYPTO, CRYPTO_R_TOO_SMALL_BUFFER); + return 0; + } + + q = str; + for (i = 0, p = buf; i < buflen; i++, p++) { + *q++ = hexdig[(*p >> 4) & 0xf]; + *q++ = hexdig[*p & 0xf]; + if (has_sep) + *q++ = sep; + } + if (has_sep && buflen > 0) + --q; + *q = CH_ZERO; + +#ifdef CHARSET_EBCDIC + ebcdic2ascii(str, str, q - str); +#endif + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-31789/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-31789/vuln.c new file mode 100644 index 0000000..8172aa9 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-31789/vuln.c @@ -0,0 +1,50 @@ +/* Provenance: openssl/openssl buf2hexstr_sep (vuln). + * repo: openssl/openssl + * commit: b7ae7a093997b5cd549bc21cccd715510fef86c0 + * parent: b7ae7a093997b5cd549bc21cccd715510fef86c0 + * commit_url: https://github.com/openssl/openssl/commit/a91e537d16d74050dbde50bb0dfb1fe9930f0521 + * cve: CVE-2026-31789 + * license: Apache-2.0 + * function: buf2hexstr_sep + * relpath: crypto/o_str.c + */ + +static int buf2hexstr_sep(char *str, size_t str_n, size_t *strlength, + const unsigned char *buf, size_t buflen, + const char sep) +{ + static const char hexdig[] = "0123456789ABCDEF"; + const unsigned char *p; + char *q; + size_t i; + int has_sep = (sep != CH_ZERO); + size_t len = has_sep ? buflen * 3 : 1 + buflen * 2; + + if (len == 0) + ++len; + if (strlength != NULL) + *strlength = len; + if (str == NULL) + return 1; + + if (str_n < len) { + ERR_raise(ERR_LIB_CRYPTO, CRYPTO_R_TOO_SMALL_BUFFER); + return 0; + } + + q = str; + for (i = 0, p = buf; i < buflen; i++, p++) { + *q++ = hexdig[(*p >> 4) & 0xf]; + *q++ = hexdig[*p & 0xf]; + if (has_sep) + *q++ = sep; + } + if (has_sep && buflen > 0) + --q; + *q = CH_ZERO; + +#ifdef CHARSET_EBCDIC + ebcdic2ascii(str, str, q - str); +#endif + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-31790-rsasve_generate/fixed.in b/benchmarks/pairs/vfc/openssl-cve-2026-31790-rsasve_generate/fixed.in new file mode 100644 index 0000000..2233727 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-31790-rsasve_generate/fixed.in @@ -0,0 +1,67 @@ +/* Provenance: openssl/openssl rsasve_generate (fixed). + * repo: openssl/openssl + * commit: abd8b2eec7e3f3fda60ecfb68498b246b52af482 + * parent: a24216018e1ede8ff01a4ff5afff7dfbd443e2f9 + * commit_url: https://github.com/openssl/openssl/commit/abd8b2eec7e3f3fda60ecfb68498b246b52af482 + * cve: CVE-2026-31790 + * license: Apache-2.0 + * function: rsasve_generate + * relpath: providers/implementations/kem/rsa_kem.c.in + */ + +static int rsasve_generate(PROV_RSA_CTX *prsactx, + unsigned char *out, size_t *outlen, + unsigned char *secret, size_t *secretlen) +{ + int ret; + size_t nlen; + + /* Step (1): nlen = Ceil(len(n)/8) */ + nlen = RSA_size(prsactx->rsa); + + if (out == NULL) { + if (nlen == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); + return 0; + } + if (outlen == NULL && secretlen == NULL) + return 0; + if (outlen != NULL) + *outlen = nlen; + if (secretlen != NULL) + *secretlen = nlen; + return 1; + } + + /* + * If outlen is specified, then it must report the length + * of the out buffer on input so that we can confirm + * its size is sufficient for encapsulation + */ + if (outlen != NULL && *outlen < nlen) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_OUTPUT_LENGTH); + return 0; + } + + /* + * Step (2): Generate a random byte string z of nlen bytes where + * 1 < z < n - 1 + */ + if (!rsasve_gen_rand_bytes(prsactx->rsa, secret, (int)nlen)) + return 0; + + /* Step(3): out = RSAEP((n,e), z) */ + ret = RSA_public_encrypt((int)nlen, secret, out, prsactx->rsa, + RSA_NO_PADDING); + if (ret <= 0 || ret != (int)nlen) { + OPENSSL_cleanse(secret, nlen); + return 0; + } + + if (outlen != NULL) + *outlen = nlen; + if (secretlen != NULL) + *secretlen = nlen; + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-31790-rsasve_generate/vuln.in b/benchmarks/pairs/vfc/openssl-cve-2026-31790-rsasve_generate/vuln.in new file mode 100644 index 0000000..cec3c8f --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-31790-rsasve_generate/vuln.in @@ -0,0 +1,66 @@ +/* Provenance: openssl/openssl rsasve_generate (vuln). + * repo: openssl/openssl + * commit: a24216018e1ede8ff01a4ff5afff7dfbd443e2f9 + * parent: a24216018e1ede8ff01a4ff5afff7dfbd443e2f9 + * commit_url: https://github.com/openssl/openssl/commit/abd8b2eec7e3f3fda60ecfb68498b246b52af482 + * cve: CVE-2026-31790 + * license: Apache-2.0 + * function: rsasve_generate + * relpath: providers/implementations/kem/rsa_kem.c.in + */ + +static int rsasve_generate(PROV_RSA_CTX *prsactx, + unsigned char *out, size_t *outlen, + unsigned char *secret, size_t *secretlen) +{ + int ret; + size_t nlen; + + /* Step (1): nlen = Ceil(len(n)/8) */ + nlen = RSA_size(prsactx->rsa); + + if (out == NULL) { + if (nlen == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); + return 0; + } + if (outlen == NULL && secretlen == NULL) + return 0; + if (outlen != NULL) + *outlen = nlen; + if (secretlen != NULL) + *secretlen = nlen; + return 1; + } + + /* + * If outlen is specified, then it must report the length + * of the out buffer on input so that we can confirm + * its size is sufficient for encapsulation + */ + if (outlen != NULL && *outlen < nlen) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_OUTPUT_LENGTH); + return 0; + } + + /* + * Step (2): Generate a random byte string z of nlen bytes where + * 1 < z < n - 1 + */ + if (!rsasve_gen_rand_bytes(prsactx->rsa, secret, (int)nlen)) + return 0; + + /* Step(3): out = RSAEP((n,e), z) */ + ret = RSA_public_encrypt((int)nlen, secret, out, prsactx->rsa, + RSA_NO_PADDING); + if (ret) { + ret = 1; + if (outlen != NULL) + *outlen = nlen; + if (secretlen != NULL) + *secretlen = nlen; + } else { + OPENSSL_cleanse(secret, nlen); + } + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-31790/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-31790/fixed.c new file mode 100644 index 0000000..f0fc70d --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-31790/fixed.c @@ -0,0 +1,67 @@ +/* Provenance: openssl/openssl rsasve_generate (fixed). + * repo: openssl/openssl + * commit: eed200f58cd8645ed77e46b7e9f764e284df379e + * parent: a91e537d16d74050dbde50bb0dfb1fe9930f0521 + * commit_url: https://github.com/openssl/openssl/commit/eed200f58cd8645ed77e46b7e9f764e284df379e + * cve: CVE-2026-31790 + * license: Apache-2.0 + * function: rsasve_generate + * relpath: providers/implementations/kem/rsa_kem.c + */ + +static int rsasve_generate(PROV_RSA_CTX *prsactx, + unsigned char *out, size_t *outlen, + unsigned char *secret, size_t *secretlen) +{ + int ret; + size_t nlen; + + /* Step (1): nlen = Ceil(len(n)/8) */ + nlen = RSA_size(prsactx->rsa); + + if (out == NULL) { + if (nlen == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); + return 0; + } + if (outlen == NULL && secretlen == NULL) + return 0; + if (outlen != NULL) + *outlen = nlen; + if (secretlen != NULL) + *secretlen = nlen; + return 1; + } + + /* + * If outlen is specified, then it must report the length + * of the out buffer on input so that we can confirm + * its size is sufficient for encapsulation + */ + if (outlen != NULL && *outlen < nlen) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_OUTPUT_LENGTH); + return 0; + } + + /* + * Step (2): Generate a random byte string z of nlen bytes where + * 1 < z < n - 1 + */ + if (!rsasve_gen_rand_bytes(prsactx->rsa, secret, nlen)) + return 0; + + /* Step(3): out = RSAEP((n,e), z) */ + ret = RSA_public_encrypt((int)nlen, secret, out, prsactx->rsa, + RSA_NO_PADDING); + if (ret <= 0 || ret != (int)nlen) { + OPENSSL_cleanse(secret, nlen); + return 0; + } + + if (outlen != NULL) + *outlen = nlen; + if (secretlen != NULL) + *secretlen = nlen; + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-31790/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-31790/vuln.c new file mode 100644 index 0000000..efab4c4 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-31790/vuln.c @@ -0,0 +1,65 @@ +/* Provenance: openssl/openssl rsasve_generate (vuln). + * repo: openssl/openssl + * commit: a91e537d16d74050dbde50bb0dfb1fe9930f0521 + * parent: a91e537d16d74050dbde50bb0dfb1fe9930f0521 + * commit_url: https://github.com/openssl/openssl/commit/eed200f58cd8645ed77e46b7e9f764e284df379e + * cve: CVE-2026-31790 + * license: Apache-2.0 + * function: rsasve_generate + * relpath: providers/implementations/kem/rsa_kem.c + */ + +static int rsasve_generate(PROV_RSA_CTX *prsactx, + unsigned char *out, size_t *outlen, + unsigned char *secret, size_t *secretlen) +{ + int ret; + size_t nlen; + + /* Step (1): nlen = Ceil(len(n)/8) */ + nlen = RSA_size(prsactx->rsa); + + if (out == NULL) { + if (nlen == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); + return 0; + } + if (outlen == NULL && secretlen == NULL) + return 0; + if (outlen != NULL) + *outlen = nlen; + if (secretlen != NULL) + *secretlen = nlen; + return 1; + } + + /* + * If outlen is specified, then it must report the length + * of the out buffer on input so that we can confirm + * its size is sufficient for encapsulation + */ + if (outlen != NULL && *outlen < nlen) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_OUTPUT_LENGTH); + return 0; + } + + /* + * Step (2): Generate a random byte string z of nlen bytes where + * 1 < z < n - 1 + */ + if (!rsasve_gen_rand_bytes(prsactx->rsa, secret, nlen)) + return 0; + + /* Step(3): out = RSAEP((n,e), z) */ + ret = RSA_public_encrypt(nlen, secret, out, prsactx->rsa, RSA_NO_PADDING); + if (ret) { + ret = 1; + if (outlen != NULL) + *outlen = nlen; + if (secretlen != NULL) + *secretlen = nlen; + } else { + OPENSSL_cleanse(secret, nlen); + } + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-34181/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-34181/fixed.c new file mode 100644 index 0000000..6ce1a9b --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-34181/fixed.c @@ -0,0 +1,74 @@ +/* Provenance: openssl/openssl PBMAC1_PBKDF2_HMAC (fixed). + * repo: openssl/openssl + * commit: 5a0230b6cc95a576b0c2b7b5b2ba7c74232e7b7c + * parent: fcb23806047f5afbe55d5d601a527fc24bf7ca2c + * commit_url: https://github.com/openssl/openssl/commit/5a0230b6cc95a576b0c2b7b5b2ba7c74232e7b7c + * cve: CVE-2026-34181 + * license: Apache-2.0 + * function: PBMAC1_PBKDF2_HMAC + * relpath: crypto/pkcs12/p12_mutl.c + */ + +static int PBMAC1_PBKDF2_HMAC(OSSL_LIB_CTX *ctx, const char *propq, + const char *pass, int passlen, + const X509_ALGOR *macalg, unsigned char *key) +{ + PBKDF2PARAM *pbkdf2_param = NULL; + const ASN1_OBJECT *kdf_hmac_oid; + int kdf_hmac_nid; + int ret = -1; + int keylen = 0; + EVP_MD *kdf_md = NULL; + const ASN1_OCTET_STRING *pbkdf2_salt = NULL; + + pbkdf2_param = PBMAC1_get1_pbkdf2_param(macalg); + if (pbkdf2_param == NULL) { + ERR_raise(ERR_LIB_PKCS12, ERR_R_UNSUPPORTED); + goto err; + } + + if (pbkdf2_param->prf == NULL) { + kdf_hmac_nid = NID_hmacWithSHA1; + } else { + X509_ALGOR_get0(&kdf_hmac_oid, NULL, NULL, pbkdf2_param->prf); + kdf_hmac_nid = OBJ_obj2nid(kdf_hmac_oid); + } + + kdf_md = EVP_MD_fetch(ctx, OBJ_nid2sn(ossl_hmac2mdnid(kdf_hmac_nid)), propq); + if (kdf_md == NULL) { + ERR_raise(ERR_LIB_PKCS12, ERR_R_FETCH_FAILED); + goto err; + } + + /* Validate salt is an OCTET STRING choice */ + if (pbkdf2_param->salt == NULL + || pbkdf2_param->salt->type != V_ASN1_OCTET_STRING) { + ERR_raise_data(ERR_LIB_PKCS12, PKCS12_R_PARSE_ERROR, "Invalid Salt"); + goto err; + } + pbkdf2_salt = pbkdf2_param->salt->value.octet_string; + + /* RFC 9879 specifies missing key length as invalid */ + if (pbkdf2_param->keylength != NULL) + keylen = ASN1_INTEGER_get(pbkdf2_param->keylength); + /* RFC 9879 specifies too short key length as untrustworthy too */ + if (keylen < 20 || keylen > EVP_MAX_MD_SIZE) { + ERR_raise_data(ERR_LIB_PKCS12, PKCS12_R_PARSE_ERROR, + "Invalid Key length (%d is not in the range 20..64)", keylen); + goto err; + } + + if (PKCS5_PBKDF2_HMAC(pass, passlen, pbkdf2_salt->data, pbkdf2_salt->length, + ASN1_INTEGER_get(pbkdf2_param->iter), kdf_md, keylen, key) + <= 0) { + ERR_raise(ERR_LIB_PKCS12, ERR_R_INTERNAL_ERROR); + goto err; + } + ret = keylen; + +err: + EVP_MD_free(kdf_md); + PBKDF2PARAM_free(pbkdf2_param); + + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-34181/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-34181/vuln.c new file mode 100644 index 0000000..def08cd --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-34181/vuln.c @@ -0,0 +1,73 @@ +/* Provenance: openssl/openssl PBMAC1_PBKDF2_HMAC (vuln). + * repo: openssl/openssl + * commit: fcb23806047f5afbe55d5d601a527fc24bf7ca2c + * parent: fcb23806047f5afbe55d5d601a527fc24bf7ca2c + * commit_url: https://github.com/openssl/openssl/commit/5a0230b6cc95a576b0c2b7b5b2ba7c74232e7b7c + * cve: CVE-2026-34181 + * license: Apache-2.0 + * function: PBMAC1_PBKDF2_HMAC + * relpath: crypto/pkcs12/p12_mutl.c + */ + +static int PBMAC1_PBKDF2_HMAC(OSSL_LIB_CTX *ctx, const char *propq, + const char *pass, int passlen, + const X509_ALGOR *macalg, unsigned char *key) +{ + PBKDF2PARAM *pbkdf2_param = NULL; + const ASN1_OBJECT *kdf_hmac_oid; + int kdf_hmac_nid; + int ret = -1; + int keylen = 0; + EVP_MD *kdf_md = NULL; + const ASN1_OCTET_STRING *pbkdf2_salt = NULL; + + pbkdf2_param = PBMAC1_get1_pbkdf2_param(macalg); + if (pbkdf2_param == NULL) { + ERR_raise(ERR_LIB_PKCS12, ERR_R_UNSUPPORTED); + goto err; + } + + if (pbkdf2_param->prf == NULL) { + kdf_hmac_nid = NID_hmacWithSHA1; + } else { + X509_ALGOR_get0(&kdf_hmac_oid, NULL, NULL, pbkdf2_param->prf); + kdf_hmac_nid = OBJ_obj2nid(kdf_hmac_oid); + } + + kdf_md = EVP_MD_fetch(ctx, OBJ_nid2sn(ossl_hmac2mdnid(kdf_hmac_nid)), propq); + if (kdf_md == NULL) { + ERR_raise(ERR_LIB_PKCS12, ERR_R_FETCH_FAILED); + goto err; + } + + /* Validate salt is an OCTET STRING choice */ + if (pbkdf2_param->salt == NULL + || pbkdf2_param->salt->type != V_ASN1_OCTET_STRING) { + ERR_raise_data(ERR_LIB_PKCS12, PKCS12_R_PARSE_ERROR, "Invalid Salt"); + goto err; + } + pbkdf2_salt = pbkdf2_param->salt->value.octet_string; + + /* RFC 9579 specifies missing key length as invalid */ + if (pbkdf2_param->keylength != NULL) + keylen = ASN1_INTEGER_get(pbkdf2_param->keylength); + if (keylen <= 0 || keylen > EVP_MAX_MD_SIZE) { + ERR_raise_data(ERR_LIB_PKCS12, PKCS12_R_PARSE_ERROR, + "Invalid Key length (%d is not in the range 1..64)", keylen); + goto err; + } + + if (PKCS5_PBKDF2_HMAC(pass, passlen, pbkdf2_salt->data, pbkdf2_salt->length, + ASN1_INTEGER_get(pbkdf2_param->iter), kdf_md, keylen, key) + <= 0) { + ERR_raise(ERR_LIB_PKCS12, ERR_R_INTERNAL_ERROR); + goto err; + } + ret = keylen; + +err: + EVP_MD_free(kdf_md); + PBKDF2PARAM_free(pbkdf2_param); + + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-35188/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-35188/fixed.c new file mode 100644 index 0000000..6d2d9a8 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-35188/fixed.c @@ -0,0 +1,109 @@ +/* Provenance: openssl/openssl check_cert_ocsp_resp (fixed). + * repo: openssl/openssl + * commit: 58633b658fe74095c8cdde191e4ce1bf94f8c5f9 + * parent: 68ef88913e321bdb47eee88118ceba18ed2388cd + * commit_url: https://github.com/openssl/openssl/commit/58633b658fe74095c8cdde191e4ce1bf94f8c5f9 + * cve: CVE-2026-35188 + * license: Apache-2.0 + * function: check_cert_ocsp_resp + * relpath: crypto/x509/x509_vfy.c + */ + +static int check_cert_ocsp_resp(X509_STORE_CTX *ctx) +{ + int cert_status, crl_reason; + int i; + OCSP_RESPONSE *resp = NULL; + OCSP_BASICRESP *bs = NULL; + OCSP_SINGLERESP *sr = NULL; + OCSP_CERTID *sr_cert_id = NULL; + ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; + ASN1_OBJECT *cert_id_md_oid; + EVP_MD *cert_id_md = NULL; + OCSP_CERTID *cert_id = NULL; + int ret = V_OCSP_CERTSTATUS_UNKNOWN; + int num; + + num = sk_OCSP_RESPONSE_num(ctx->ocsp_resp); + + if (num < 0 || num <= ctx->error_depth) + return X509_V_ERR_OCSP_NO_RESPONSE; + + if ((resp = sk_OCSP_RESPONSE_value(ctx->ocsp_resp, ctx->error_depth)) == NULL + || (bs = OCSP_response_get1_basic(resp)) == NULL + || (num = OCSP_resp_count(bs)) < 1) + return X509_V_ERR_OCSP_NO_RESPONSE; + + if (OCSP_response_status(resp) != OCSP_RESPONSE_STATUS_SUCCESSFUL) { + OCSP_BASICRESP_free(bs); + bs = NULL; + ret = X509_V_ERR_OCSP_RESP_INVALID; + goto end; + } + + if (OCSP_basic_verify(bs, ctx->chain, ctx->store, 0) <= 0) { + ret = X509_V_ERR_OCSP_SIGNATURE_FAILURE; + goto end; + } + + /* find the right single response in the OCSP response */ + for (i = 0; i < num; i++) { + sr = OCSP_resp_get0(bs, i); + + /* determine the md algorithm which was used to create cert id */ + sr_cert_id = (OCSP_CERTID *)OCSP_SINGLERESP_get0_id(sr); + OCSP_id_get0_info(NULL, &cert_id_md_oid, NULL, NULL, sr_cert_id); + if (cert_id_md_oid != NULL) { + char md_name[80]; + + if (i2t_ASN1_OBJECT(md_name, sizeof(md_name), cert_id_md_oid) > 0) + cert_id_md = EVP_MD_fetch(ctx->libctx, md_name, ctx->propq); + } + + /* search the stack for the requested OCSP response */ + cert_id = OCSP_cert_to_id(cert_id_md, ctx->current_cert, ctx->current_issuer); + EVP_MD_free(cert_id_md); + cert_id_md = NULL; + if (cert_id == NULL) { + ret = X509_V_ERR_OCSP_RESP_INVALID; + goto end; + } + + if (!OCSP_id_cmp(cert_id, sr_cert_id)) + break; + + OCSP_CERTID_free(cert_id); + cert_id = NULL; + } + + if (cert_id == NULL) { + ret = X509_V_ERR_OCSP_NO_RESPONSE; + goto end; + } + + if (OCSP_resp_find_status(bs, cert_id, &cert_status, &crl_reason, &rev, + &thisupd, &nextupd) + <= 0) { + ret = X509_V_ERR_OCSP_RESP_INVALID; + goto end; + } + + if (cert_status == V_OCSP_CERTSTATUS_GOOD) { + /* + * Note: + * A OCSP stapling result will be accepted up to 5 minutes + * after it expired! + */ + if (!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) + ret = X509_V_ERR_OCSP_HAS_EXPIRED; + else + ret = V_OCSP_CERTSTATUS_GOOD; + } else { + ret = cert_status; + } + +end: + OCSP_CERTID_free(cert_id); + OCSP_BASICRESP_free(bs); + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-35188/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-35188/vuln.c new file mode 100644 index 0000000..bd9ea50 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-35188/vuln.c @@ -0,0 +1,108 @@ +/* Provenance: openssl/openssl check_cert_ocsp_resp (vuln). + * repo: openssl/openssl + * commit: 68ef88913e321bdb47eee88118ceba18ed2388cd + * parent: 68ef88913e321bdb47eee88118ceba18ed2388cd + * commit_url: https://github.com/openssl/openssl/commit/58633b658fe74095c8cdde191e4ce1bf94f8c5f9 + * cve: CVE-2026-35188 + * license: Apache-2.0 + * function: check_cert_ocsp_resp + * relpath: crypto/x509/x509_vfy.c + */ + +static int check_cert_ocsp_resp(X509_STORE_CTX *ctx) +{ + int cert_status, crl_reason; + int i; + OCSP_RESPONSE *resp = NULL; + OCSP_BASICRESP *bs = NULL; + OCSP_SINGLERESP *sr = NULL; + OCSP_CERTID *sr_cert_id = NULL; + ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; + ASN1_OBJECT *cert_id_md_oid; + EVP_MD *cert_id_md = NULL; + OCSP_CERTID *cert_id = NULL; + int ret = V_OCSP_CERTSTATUS_UNKNOWN; + int num; + + num = sk_OCSP_RESPONSE_num(ctx->ocsp_resp); + + if (num < 0 || num <= ctx->error_depth) + return X509_V_ERR_OCSP_NO_RESPONSE; + + if ((resp = sk_OCSP_RESPONSE_value(ctx->ocsp_resp, ctx->error_depth)) == NULL + || (bs = OCSP_response_get1_basic(resp)) == NULL + || (num = OCSP_resp_count(bs)) < 1) + return X509_V_ERR_OCSP_NO_RESPONSE; + + if (OCSP_response_status(resp) != OCSP_RESPONSE_STATUS_SUCCESSFUL) { + OCSP_BASICRESP_free(bs); + ret = X509_V_ERR_OCSP_RESP_INVALID; + goto end; + } + + if (OCSP_basic_verify(bs, ctx->chain, ctx->store, 0) <= 0) { + ret = X509_V_ERR_OCSP_SIGNATURE_FAILURE; + goto end; + } + + /* find the right single response in the OCSP response */ + for (i = 0; i < num; i++) { + sr = OCSP_resp_get0(bs, i); + + /* determine the md algorithm which was used to create cert id */ + sr_cert_id = (OCSP_CERTID *)OCSP_SINGLERESP_get0_id(sr); + OCSP_id_get0_info(NULL, &cert_id_md_oid, NULL, NULL, sr_cert_id); + if (cert_id_md_oid != NULL) { + char md_name[80]; + + if (i2t_ASN1_OBJECT(md_name, sizeof(md_name), cert_id_md_oid) > 0) + cert_id_md = EVP_MD_fetch(ctx->libctx, md_name, ctx->propq); + } + + /* search the stack for the requested OCSP response */ + cert_id = OCSP_cert_to_id(cert_id_md, ctx->current_cert, ctx->current_issuer); + EVP_MD_free(cert_id_md); + cert_id_md = NULL; + if (cert_id == NULL) { + ret = X509_V_ERR_OCSP_RESP_INVALID; + goto end; + } + + if (!OCSP_id_cmp(cert_id, sr_cert_id)) + break; + + OCSP_CERTID_free(cert_id); + cert_id = NULL; + } + + if (cert_id == NULL) { + ret = X509_V_ERR_OCSP_NO_RESPONSE; + goto end; + } + + if (OCSP_resp_find_status(bs, cert_id, &cert_status, &crl_reason, &rev, + &thisupd, &nextupd) + <= 0) { + ret = X509_V_ERR_OCSP_RESP_INVALID; + goto end; + } + + if (cert_status == V_OCSP_CERTSTATUS_GOOD) { + /* + * Note: + * A OCSP stapling result will be accepted up to 5 minutes + * after it expired! + */ + if (!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) + ret = X509_V_ERR_OCSP_HAS_EXPIRED; + else + ret = V_OCSP_CERTSTATUS_GOOD; + } else { + ret = cert_status; + } + +end: + OCSP_CERTID_free(cert_id); + OCSP_BASICRESP_free(bs); + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-42764/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-42764/fixed.c new file mode 100644 index 0000000..7b7c9c6 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-42764/fixed.c @@ -0,0 +1,259 @@ +/* Provenance: openssl/openssl port_default_packet_handler (fixed). + * repo: openssl/openssl + * commit: 5097ec4dae239112498abb722e255ea60ef7ac48 + * parent: 58633b658fe74095c8cdde191e4ce1bf94f8c5f9 + * commit_url: https://github.com/openssl/openssl/commit/5097ec4dae239112498abb722e255ea60ef7ac48 + * cve: CVE-2026-42764 + * license: Apache-2.0 + * function: port_default_packet_handler + * relpath: ssl/quic/quic_port.c + */ + +static void port_default_packet_handler(QUIC_URXE *e, void *arg, + const QUIC_CONN_ID *dcid) +{ + QUIC_PORT *port = arg; + PACKET pkt; + QUIC_PKT_HDR hdr; + QUIC_CHANNEL *ch = NULL, *new_ch = NULL; + QUIC_CONN_ID odcid; + uint8_t gen_new_token = 0; + OSSL_QRX *qrx = NULL; + OSSL_QRX *qrx_src = NULL; + OSSL_QRX_ARGS qrx_args = { 0 }; + uint64_t cause_flags = 0; + OSSL_QRX_PKT *qrx_pkt = NULL; + + /* Don't handle anything if we are no longer running. */ + if (!ossl_quic_port_is_running(port)) + goto undesirable; + + if (port_try_handle_stateless_reset(port, e)) + goto undesirable; + + if (dcid != NULL + && ossl_quic_lcidm_lookup(port->lcidm, dcid, NULL, + (void **)&ch)) { + assert(ch != NULL); + ossl_quic_channel_inject(ch, e); + return; + } + + /* + * If we have an incoming packet which doesn't match any existing connection + * we assume this is an attempt to make a new connection. + */ + if (!port->allow_incoming) + goto undesirable; + + /* + * packet without destination connection id is invalid/corrupted here. + * stop wasting CPU cycles now. + */ + if (dcid == NULL) + goto undesirable; + + /* + * We have got a packet for an unknown DCID. This might be an attempt to + * open a new connection. + */ + if (e->data_len < QUIC_MIN_INITIAL_DGRAM_LEN) + goto undesirable; + + if (!PACKET_buf_init(&pkt, ossl_quic_urxe_data(e), e->data_len)) + goto undesirable; + + /* + * We set short_conn_id_len to SIZE_MAX here which will cause the decode + * operation to fail if we get a 1-RTT packet. This is fine since we only + * care about Initial packets. + */ + if (!ossl_quic_wire_decode_pkt_hdr(&pkt, SIZE_MAX, 1, 0, &hdr, NULL, + &cause_flags)) { + /* + * If we fail due to a bad version, we know the packet up to the version + * number was decoded, and we use it below to send a version + * negotiation packet + */ + if ((cause_flags & QUIC_PKT_HDR_DECODE_BAD_VERSION) == 0) + goto undesirable; + } + + switch (hdr.version) { + case QUIC_VERSION_1: + break; + + case QUIC_VERSION_NONE: + default: + + /* + * If we get here, then we have a bogus version, and might need + * to send a version negotiation packet. According to + * RFC 9000 s. 6 and 14.1, we only do so however, if the UDP datagram + * is a minimum of 1200 bytes in size + */ + if (e->data_len < 1200) + goto undesirable; + + /* + * If we don't get a supported version, respond with a ver + * negotiation packet, and discard + * TODO(QUIC FUTURE): Rate limit the reception of these + */ + port_send_version_negotiation(port, &e->peer, &hdr); + goto undesirable; + } + + /* + * We only care about Initial packets which might be trying to establish a + * connection. + */ + if (hdr.type != QUIC_PKT_TYPE_INITIAL) + goto undesirable; + + odcid.id_len = 0; + + /* + * Create qrx now so we can check integrity of packet + * which does not belong to any channel. + */ + qrx_args.libctx = port->engine->libctx; + qrx_args.demux = port->demux; + qrx_args.short_conn_id_len = dcid->id_len; + qrx_args.max_deferred = 32; + qrx = ossl_qrx_new(&qrx_args); + if (qrx == NULL) + goto undesirable; + + /* + * Derive secrets for qrx only. + */ + if (!ossl_quic_provide_initial_secret(port->engine->libctx, + port->engine->propq, + &hdr.dst_conn_id, + /* is_server */ 1, + qrx, NULL)) + goto undesirable; + + if (ossl_qrx_validate_initial_packet(qrx, e, (const QUIC_CONN_ID *)dcid) == 0) + goto undesirable; + + if (port->validate_addr == 0) { + /* + * Forget qrx, because it becomes (almost) useless here. We must let + * channel to create a new QRX for connection ID server chooses. The + * validation keys for new DCID will be derived by + * ossl_quic_channel_on_new_conn() when we will be creating channel. + * See RFC 9000 section 7.2 negotiating connection id to better + * understand what's going on here. + * + * Did we say qrx is almost useless? Why? Because qrx remembers packets + * we just validated. Those packets must be injected to channel we are + * going to create. We use qrx_src alias so we can read packets from + * qrx and inject them to channel. + */ + qrx_src = qrx; + qrx = NULL; + } + /* + * TODO(QUIC FUTURE): there should be some logic similar to accounting half-open + * states in TCP. If we reach certain threshold, then we want to + * validate clients. + */ + if (port->validate_addr == 1 && hdr.token == NULL) { + port_send_retry(port, &e->peer, &hdr); + goto undesirable; + } + + /* + * Note, even if we don't enforce the sending of retry frames for + * server address validation, we may still get a token if we sent + * a NEW_TOKEN frame during a prior connection, which we should still + * validate here + */ + if (hdr.token != NULL + && port_validate_token(&hdr, port, &e->peer, + &odcid, &gen_new_token) + == 0) { + /* + * RFC 9000 s 8.1.3 + * When a server receives an Initial packet with an address + * validation token, it MUST attempt to validate the token, + * unless it has already completed address validation. + * If the token is invalid, then the server SHOULD proceed as + * if the client did not have a validated address, + * including potentially sending a Retry packet + * Note: If address validation is disabled, just act like + * the request is valid + */ + if (port->validate_addr == 1) { + /* + * Again: we should consider saving initial encryption level + * secrets to token here to save some CPU cycles. + */ + port_send_retry(port, &e->peer, &hdr); + goto undesirable; + } + + /* + * client is under amplification limit, until it completes + * handshake. + * + * forget qrx so channel can create a new one + * with valid initial encryption level keys. + */ + if (qrx != NULL) { + qrx_src = qrx; + qrx = NULL; + } + } + + port_bind_channel(port, &e->peer, &hdr.dst_conn_id, + &odcid, qrx, &new_ch); + + /* + * if packet validates it gets moved to channel, we've just bound + * to port. + */ + if (new_ch == NULL) + goto undesirable; + + /* + * Generate a token for sending in a later NEW_TOKEN frame + */ + if (gen_new_token == 1) + generate_new_token(new_ch, &e->peer); + + if (qrx != NULL) { + /* + * The qrx belongs to channel now, so don't free it. + */ + qrx = NULL; + } else { + /* + * We still need to salvage packets from almost forgotten qrx + * and pass them to channel. + */ + while (ossl_qrx_read_pkt(qrx_src, &qrx_pkt) == 1) + ossl_quic_channel_inject_pkt(new_ch, qrx_pkt); + ossl_qrx_update_pn_space(qrx_src, new_ch->qrx); + } + + /* + * If function reaches this place, then packet got validated in + * ossl_qrx_validate_initial_packet(). Keep in mind the function + * ossl_qrx_validate_initial_packet() decrypts the packet to validate it. + * If packet validation was successful (and it was because we are here), + * then the function puts the packet to qrx->rx_pending. We must not call + * ossl_qrx_inject_urxe() here now, because we don't want to insert + * the packet to qrx->urx_pending which keeps packet waiting for decryption. + * + * We are going to call ossl_quic_demux_release_urxe() to dispose buffer + * which still holds encrypted data. + */ + +undesirable: + ossl_qrx_free(qrx); + ossl_qrx_free(qrx_src); + ossl_quic_demux_release_urxe(port->demux, e); +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-42764/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-42764/vuln.c new file mode 100644 index 0000000..5d3e80e --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-42764/vuln.c @@ -0,0 +1,257 @@ +/* Provenance: openssl/openssl port_default_packet_handler (vuln). + * repo: openssl/openssl + * commit: 58633b658fe74095c8cdde191e4ce1bf94f8c5f9 + * parent: 58633b658fe74095c8cdde191e4ce1bf94f8c5f9 + * commit_url: https://github.com/openssl/openssl/commit/5097ec4dae239112498abb722e255ea60ef7ac48 + * cve: CVE-2026-42764 + * license: Apache-2.0 + * function: port_default_packet_handler + * relpath: ssl/quic/quic_port.c + */ + +static void port_default_packet_handler(QUIC_URXE *e, void *arg, + const QUIC_CONN_ID *dcid) +{ + QUIC_PORT *port = arg; + PACKET pkt; + QUIC_PKT_HDR hdr; + QUIC_CHANNEL *ch = NULL, *new_ch = NULL; + QUIC_CONN_ID odcid; + uint8_t gen_new_token = 0; + OSSL_QRX *qrx = NULL; + OSSL_QRX *qrx_src = NULL; + OSSL_QRX_ARGS qrx_args = { 0 }; + uint64_t cause_flags = 0; + OSSL_QRX_PKT *qrx_pkt = NULL; + + /* Don't handle anything if we are no longer running. */ + if (!ossl_quic_port_is_running(port)) + goto undesirable; + + if (port_try_handle_stateless_reset(port, e)) + goto undesirable; + + if (dcid != NULL + && ossl_quic_lcidm_lookup(port->lcidm, dcid, NULL, + (void **)&ch)) { + assert(ch != NULL); + ossl_quic_channel_inject(ch, e); + return; + } + + /* + * If we have an incoming packet which doesn't match any existing connection + * we assume this is an attempt to make a new connection. + */ + if (!port->allow_incoming) + goto undesirable; + + /* + * packet without destination connection id is invalid/corrupted here. + * stop wasting CPU cycles now. + */ + if (dcid == NULL) + goto undesirable; + + /* + * We have got a packet for an unknown DCID. This might be an attempt to + * open a new connection. + */ + if (e->data_len < QUIC_MIN_INITIAL_DGRAM_LEN) + goto undesirable; + + if (!PACKET_buf_init(&pkt, ossl_quic_urxe_data(e), e->data_len)) + goto undesirable; + + /* + * We set short_conn_id_len to SIZE_MAX here which will cause the decode + * operation to fail if we get a 1-RTT packet. This is fine since we only + * care about Initial packets. + */ + if (!ossl_quic_wire_decode_pkt_hdr(&pkt, SIZE_MAX, 1, 0, &hdr, NULL, + &cause_flags)) { + /* + * If we fail due to a bad version, we know the packet up to the version + * number was decoded, and we use it below to send a version + * negotiation packet + */ + if ((cause_flags & QUIC_PKT_HDR_DECODE_BAD_VERSION) == 0) + goto undesirable; + } + + switch (hdr.version) { + case QUIC_VERSION_1: + break; + + case QUIC_VERSION_NONE: + default: + + /* + * If we get here, then we have a bogus version, and might need + * to send a version negotiation packet. According to + * RFC 9000 s. 6 and 14.1, we only do so however, if the UDP datagram + * is a minimum of 1200 bytes in size + */ + if (e->data_len < 1200) + goto undesirable; + + /* + * If we don't get a supported version, respond with a ver + * negotiation packet, and discard + * TODO(QUIC FUTURE): Rate limit the reception of these + */ + port_send_version_negotiation(port, &e->peer, &hdr); + goto undesirable; + } + + /* + * We only care about Initial packets which might be trying to establish a + * connection. + */ + if (hdr.type != QUIC_PKT_TYPE_INITIAL) + goto undesirable; + + odcid.id_len = 0; + + /* + * Create qrx now so we can check integrity of packet + * which does not belong to any channel. + */ + qrx_args.libctx = port->engine->libctx; + qrx_args.demux = port->demux; + qrx_args.short_conn_id_len = dcid->id_len; + qrx_args.max_deferred = 32; + qrx = ossl_qrx_new(&qrx_args); + if (qrx == NULL) + goto undesirable; + + /* + * Derive secrets for qrx only. + */ + if (!ossl_quic_provide_initial_secret(port->engine->libctx, + port->engine->propq, + &hdr.dst_conn_id, + /* is_server */ 1, + qrx, NULL)) + goto undesirable; + + if (ossl_qrx_validate_initial_packet(qrx, e, (const QUIC_CONN_ID *)dcid) == 0) + goto undesirable; + + if (port->validate_addr == 0) { + /* + * Forget qrx, because it becomes (almost) useless here. We must let + * channel to create a new QRX for connection ID server chooses. The + * validation keys for new DCID will be derived by + * ossl_quic_channel_on_new_conn() when we will be creating channel. + * See RFC 9000 section 7.2 negotiating connection id to better + * understand what's going on here. + * + * Did we say qrx is almost useless? Why? Because qrx remembers packets + * we just validated. Those packets must be injected to channel we are + * going to create. We use qrx_src alias so we can read packets from + * qrx and inject them to channel. + */ + qrx_src = qrx; + qrx = NULL; + } + /* + * TODO(QUIC FUTURE): there should be some logic similar to accounting half-open + * states in TCP. If we reach certain threshold, then we want to + * validate clients. + */ + if (port->validate_addr == 1 && hdr.token == NULL) { + port_send_retry(port, &e->peer, &hdr); + goto undesirable; + } + + /* + * Note, even if we don't enforce the sending of retry frames for + * server address validation, we may still get a token if we sent + * a NEW_TOKEN frame during a prior connection, which we should still + * validate here + */ + if (hdr.token != NULL + && port_validate_token(&hdr, port, &e->peer, + &odcid, &gen_new_token) + == 0) { + /* + * RFC 9000 s 8.1.3 + * When a server receives an Initial packet with an address + * validation token, it MUST attempt to validate the token, + * unless it has already completed address validation. + * If the token is invalid, then the server SHOULD proceed as + * if the client did not have a validated address, + * including potentially sending a Retry packet + * Note: If address validation is disabled, just act like + * the request is valid + */ + if (port->validate_addr == 1) { + /* + * Again: we should consider saving initial encryption level + * secrets to token here to save some CPU cycles. + */ + port_send_retry(port, &e->peer, &hdr); + goto undesirable; + } + + /* + * client is under amplification limit, until it completes + * handshake. + * + * forget qrx so channel can create a new one + * with valid initial encryption level keys. + */ + qrx_src = qrx; + qrx = NULL; + } + + port_bind_channel(port, &e->peer, &hdr.dst_conn_id, + &odcid, qrx, &new_ch); + + /* + * if packet validates it gets moved to channel, we've just bound + * to port. + */ + if (new_ch == NULL) + goto undesirable; + + /* + * Generate a token for sending in a later NEW_TOKEN frame + */ + if (gen_new_token == 1) + generate_new_token(new_ch, &e->peer); + + if (qrx != NULL) { + /* + * The qrx belongs to channel now, so don't free it. + */ + qrx = NULL; + } else { + /* + * We still need to salvage packets from almost forgotten qrx + * and pass them to channel. + */ + while (ossl_qrx_read_pkt(qrx_src, &qrx_pkt) == 1) + ossl_quic_channel_inject_pkt(new_ch, qrx_pkt); + ossl_qrx_update_pn_space(qrx_src, new_ch->qrx); + } + + /* + * If function reaches this place, then packet got validated in + * ossl_qrx_validate_initial_packet(). Keep in mind the function + * ossl_qrx_validate_initial_packet() decrypts the packet to validate it. + * If packet validation was successful (and it was because we are here), + * then the function puts the packet to qrx->rx_pending. We must not call + * ossl_qrx_inject_urxe() here now, because we don't want to insert + * the packet to qrx->urx_pending which keeps packet waiting for decryption. + * + * We are going to call ossl_quic_demux_release_urxe() to dispose buffer + * which still holds encrypted data. + */ + +undesirable: + ossl_qrx_free(qrx); + ossl_qrx_free(qrx_src); + ossl_quic_demux_release_urxe(port->demux, e); +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-42765/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-42765/fixed.c new file mode 100644 index 0000000..49c729a --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-42765/fixed.c @@ -0,0 +1,121 @@ +/* Provenance: openssl/openssl check_revocation (fixed). + * repo: openssl/openssl + * commit: a9af3442290e8a04706a3cd5f284ffd5b486e3f6 + * parent: 5097ec4dae239112498abb722e255ea60ef7ac48 + * commit_url: https://github.com/openssl/openssl/commit/a9af3442290e8a04706a3cd5f284ffd5b486e3f6 + * cve: CVE-2026-42765 + * license: Apache-2.0 + * function: check_revocation + * relpath: crypto/x509/x509_vfy.c + */ + +static int check_revocation(X509_STORE_CTX *ctx) +{ + int i = 0, last = 0, ok = 0; + int crl_check_enabled = (ctx->param->flags & X509_V_FLAG_CRL_CHECK) != 0; + int crl_check_all_enabled = crl_check_enabled && (ctx->param->flags & X509_V_FLAG_CRL_CHECK_ALL) != 0; + int ocsp_check_enabled = (ctx->param->flags & X509_V_FLAG_OCSP_RESP_CHECK) != 0; + int ocsp_check_all_enabled = ocsp_check_enabled && (ctx->param->flags & X509_V_FLAG_OCSP_RESP_CHECK_ALL) != 0; + + if (!crl_check_enabled && !ocsp_check_enabled) + return 1; + + if (ocsp_check_enabled) { +#ifndef OPENSSL_NO_OCSP + /* + * certificate status checking with OCSP + */ + if (ocsp_check_all_enabled) + last = sk_X509_num(ctx->chain) - 1; + else if (!crl_check_all_enabled && ctx->parent != NULL) + return 1; /* If checking CRL paths this isn't the EE certificate */ + + for (i = 0; i <= last; i++) { + ctx->error_depth = i; + ctx->current_cert = sk_X509_value(ctx->chain, i); + + /* skip if cert is apparently self-signed */ + if (ctx->current_cert->ex_flags & EXFLAG_SS) + continue; + + /* the issuer certificate is the next in the chain */ + ctx->current_issuer = sk_X509_value(ctx->chain, i + 1); + if (ctx->current_issuer == NULL) { + /* + * No issuer exists at i+1 — this is the partial-chain + * trust anchor. OCSP requires an issuer to build the + * CertID, so skip OCSP checking for this certificate. + */ + if ((ctx->param->flags & X509_V_FLAG_PARTIAL_CHAIN) != 0) + continue; + return verify_cb_ocsp(ctx, X509_V_ERR_OCSP_VERIFY_FAILED); + } + + ok = check_cert_ocsp_resp(ctx); + + /* + * In the case the certificate status is REVOKED, the verification + * can stop here. + */ + if (ok == V_OCSP_CERTSTATUS_REVOKED) { + return verify_cb_ocsp(ctx, ctx->error != 0 ? ctx->error : X509_V_ERR_OCSP_VERIFY_FAILED); + } + + /* + * In the case the certificate status is GOOD, continue with the next + * certificate. + */ + if (ok == V_OCSP_CERTSTATUS_GOOD) + continue; + + /* + * As stated in RFC 6961 section 2.2: + * If OCSP is not enabled or the client receives a "ocsp_response_list" + * that does not contain a response for one or more of the certificates + * in the completed certificate chain, the client SHOULD attempt to + * validate the certificate using an alternative retrieval method, + * such as downloading the relevant CRL; + */ + if (crl_check_all_enabled || (crl_check_enabled && i == 0)) { + ok = check_cert_crl(ctx); + if (!ok) + return ok; + } else { + ok = verify_cb_ocsp(ctx, X509_V_ERR_OCSP_VERIFY_FAILED); + if (!ok) + return ok; + } + } +#endif + } + + if (crl_check_enabled && !ocsp_check_all_enabled) { + /* certificate status check with CRLs */ + if (crl_check_all_enabled) { + last = sk_X509_num(ctx->chain) - 1; + } else { + /* If checking CRL paths this isn't the EE certificate */ + if (ctx->parent != NULL) + return 1; + last = 0; + } + + /* + * in the case that OCSP is only enabled for the server certificate + * and CRL for the complete chain, the rest of the chain has to be + * checked here + */ + if (ocsp_check_enabled && crl_check_all_enabled) + i = 1; + else + i = 0; + for (; i <= last; i++) { + ctx->error_depth = i; + ok = check_cert_crl(ctx); + if (!ok) + return ok; + } + } + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-42765/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-42765/vuln.c new file mode 100644 index 0000000..f8b4736 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-42765/vuln.c @@ -0,0 +1,111 @@ +/* Provenance: openssl/openssl check_revocation (vuln). + * repo: openssl/openssl + * commit: 5097ec4dae239112498abb722e255ea60ef7ac48 + * parent: 5097ec4dae239112498abb722e255ea60ef7ac48 + * commit_url: https://github.com/openssl/openssl/commit/a9af3442290e8a04706a3cd5f284ffd5b486e3f6 + * cve: CVE-2026-42765 + * license: Apache-2.0 + * function: check_revocation + * relpath: crypto/x509/x509_vfy.c + */ + +static int check_revocation(X509_STORE_CTX *ctx) +{ + int i = 0, last = 0, ok = 0; + int crl_check_enabled = (ctx->param->flags & X509_V_FLAG_CRL_CHECK) != 0; + int crl_check_all_enabled = crl_check_enabled && (ctx->param->flags & X509_V_FLAG_CRL_CHECK_ALL) != 0; + int ocsp_check_enabled = (ctx->param->flags & X509_V_FLAG_OCSP_RESP_CHECK) != 0; + int ocsp_check_all_enabled = ocsp_check_enabled && (ctx->param->flags & X509_V_FLAG_OCSP_RESP_CHECK_ALL) != 0; + + if (!crl_check_enabled && !ocsp_check_enabled) + return 1; + + if (ocsp_check_enabled) { +#ifndef OPENSSL_NO_OCSP + /* + * certificate status checking with OCSP + */ + if (ocsp_check_all_enabled) + last = sk_X509_num(ctx->chain) - 1; + else if (!crl_check_all_enabled && ctx->parent != NULL) + return 1; /* If checking CRL paths this isn't the EE certificate */ + + for (i = 0; i <= last; i++) { + ctx->error_depth = i; + ctx->current_cert = sk_X509_value(ctx->chain, i); + + /* skip if cert is apparently self-signed */ + if (ctx->current_cert->ex_flags & EXFLAG_SS) + continue; + + /* the issuer certificate is the next in the chain */ + ctx->current_issuer = sk_X509_value(ctx->chain, i + 1); + + ok = check_cert_ocsp_resp(ctx); + + /* + * In the case the certificate status is REVOKED, the verification + * can stop here. + */ + if (ok == V_OCSP_CERTSTATUS_REVOKED) { + return verify_cb_ocsp(ctx, ctx->error != 0 ? ctx->error : X509_V_ERR_OCSP_VERIFY_FAILED); + } + + /* + * In the case the certificate status is GOOD, continue with the next + * certificate. + */ + if (ok == V_OCSP_CERTSTATUS_GOOD) + continue; + + /* + * As stated in RFC 6961 section 2.2: + * If OCSP is not enabled or the client receives a "ocsp_response_list" + * that does not contain a response for one or more of the certificates + * in the completed certificate chain, the client SHOULD attempt to + * validate the certificate using an alternative retrieval method, + * such as downloading the relevant CRL; + */ + if (crl_check_all_enabled || (crl_check_enabled && i == 0)) { + ok = check_cert_crl(ctx); + if (!ok) + return ok; + } else { + ok = verify_cb_ocsp(ctx, X509_V_ERR_OCSP_VERIFY_FAILED); + if (!ok) + return ok; + } + } +#endif + } + + if (crl_check_enabled && !ocsp_check_all_enabled) { + /* certificate status check with CRLs */ + if (crl_check_all_enabled) { + last = sk_X509_num(ctx->chain) - 1; + } else { + /* If checking CRL paths this isn't the EE certificate */ + if (ctx->parent != NULL) + return 1; + last = 0; + } + + /* + * in the case that OCSP is only enabled for the server certificate + * and CRL for the complete chain, the rest of the chain has to be + * checked here + */ + if (ocsp_check_enabled && crl_check_all_enabled) + i = 1; + else + i = 0; + for (; i <= last; i++) { + ctx->error_depth = i; + ok = check_cert_crl(ctx); + if (!ok) + return ok; + } + } + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-42766/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-42766/fixed.c new file mode 100644 index 0000000..cd2f26d --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-42766/fixed.c @@ -0,0 +1,132 @@ +/* Provenance: openssl/openssl ossl_cms_RecipientInfo_pwri_crypt (fixed). + * repo: openssl/openssl + * commit: 74245170b5a64b234ac4af27c86a25ec251c8b2a + * parent: a9af3442290e8a04706a3cd5f284ffd5b486e3f6 + * commit_url: https://github.com/openssl/openssl/commit/74245170b5a64b234ac4af27c86a25ec251c8b2a + * cve: CVE-2026-42766 + * license: Apache-2.0 + * function: ossl_cms_RecipientInfo_pwri_crypt + * relpath: crypto/cms/cms_pwri.c + */ + +int ossl_cms_RecipientInfo_pwri_crypt(const CMS_ContentInfo *cms, + CMS_RecipientInfo *ri, int en_de) +{ + CMS_EncryptedContentInfo *ec; + CMS_PasswordRecipientInfo *pwri; + int r = 0; + X509_ALGOR *algtmp, *kekalg = NULL; + EVP_CIPHER_CTX *kekctx = NULL; + char name[OSSL_MAX_NAME_SIZE]; + EVP_CIPHER *kekcipher; + unsigned char *key = NULL; + size_t keylen; + const CMS_CTX *cms_ctx = ossl_cms_get0_cmsctx(cms); + + ec = ossl_cms_get0_env_enc_content(cms); + + pwri = ri->d.pwri; + + if (pwri->pass == NULL) { + ERR_raise(ERR_LIB_CMS, CMS_R_NO_PASSWORD); + return 0; + } + algtmp = pwri->keyEncryptionAlgorithm; + + if (!algtmp || OBJ_obj2nid(algtmp->algorithm) != NID_id_alg_PWRI_KEK) { + ERR_raise(ERR_LIB_CMS, CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM); + return 0; + } + + kekalg = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(X509_ALGOR), + algtmp->parameter); + + if (kekalg == NULL) { + ERR_raise(ERR_LIB_CMS, CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER); + return 0; + } + + OBJ_obj2txt(name, sizeof(name), kekalg->algorithm, 0); + kekcipher = EVP_CIPHER_fetch(ossl_cms_ctx_get0_libctx(cms_ctx), name, + ossl_cms_ctx_get0_propq(cms_ctx)); + + if (kekcipher == NULL) { + ERR_raise(ERR_LIB_CMS, CMS_R_UNKNOWN_CIPHER); + goto err; + } + + kekctx = EVP_CIPHER_CTX_new(); + if (kekctx == NULL) { + ERR_raise(ERR_LIB_CMS, ERR_R_EVP_LIB); + goto err; + } + /* Fixup cipher based on AlgorithmIdentifier to set IV etc */ + if (!EVP_CipherInit_ex(kekctx, kekcipher, NULL, NULL, NULL, en_de)) + goto err; + EVP_CIPHER_CTX_set_padding(kekctx, 0); + if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0) { + ERR_raise(ERR_LIB_CMS, CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR); + goto err; + } + + algtmp = pwri->keyDerivationAlgorithm; + + /* Finish password based key derivation to setup key in "ctx" */ + + if (algtmp == NULL) { + ERR_raise_data(ERR_LIB_CMS, CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER, + "Missing KeyDerivationAlgorithm"); + goto err; + } + if (!EVP_PBE_CipherInit_ex(algtmp->algorithm, + (char *)pwri->pass, (int)pwri->passlen, + algtmp->parameter, kekctx, en_de, + cms_ctx->libctx, cms_ctx->propq)) { + ERR_raise(ERR_LIB_CMS, ERR_R_EVP_LIB); + goto err; + } + + /* Finally wrap/unwrap the key */ + + if (en_de) { + + if (!kek_wrap_key(NULL, &keylen, ec->key, ec->keylen, kekctx, cms_ctx)) + goto err; + + key = OPENSSL_malloc(keylen); + + if (key == NULL) + goto err; + + if (!kek_wrap_key(key, &keylen, ec->key, ec->keylen, kekctx, cms_ctx)) + goto err; + pwri->encryptedKey->data = key; + pwri->encryptedKey->length = (int)keylen; + } else { + key = OPENSSL_malloc(pwri->encryptedKey->length); + if (key == NULL) + goto err; + if (!kek_unwrap_key(key, &keylen, + pwri->encryptedKey->data, + pwri->encryptedKey->length, kekctx)) { + ERR_raise(ERR_LIB_CMS, CMS_R_UNWRAP_FAILURE); + goto err; + } + + OPENSSL_clear_free(ec->key, ec->keylen); + ec->key = key; + ec->keylen = keylen; + } + + r = 1; + +err: + EVP_CIPHER_free(kekcipher); + EVP_CIPHER_CTX_free(kekctx); + + if (!r) + OPENSSL_free(key); + X509_ALGOR_free(kekalg); + + return r; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-42766/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-42766/vuln.c new file mode 100644 index 0000000..58bcdee --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-42766/vuln.c @@ -0,0 +1,127 @@ +/* Provenance: openssl/openssl ossl_cms_RecipientInfo_pwri_crypt (vuln). + * repo: openssl/openssl + * commit: a9af3442290e8a04706a3cd5f284ffd5b486e3f6 + * parent: a9af3442290e8a04706a3cd5f284ffd5b486e3f6 + * commit_url: https://github.com/openssl/openssl/commit/74245170b5a64b234ac4af27c86a25ec251c8b2a + * cve: CVE-2026-42766 + * license: Apache-2.0 + * function: ossl_cms_RecipientInfo_pwri_crypt + * relpath: crypto/cms/cms_pwri.c + */ + +int ossl_cms_RecipientInfo_pwri_crypt(const CMS_ContentInfo *cms, + CMS_RecipientInfo *ri, int en_de) +{ + CMS_EncryptedContentInfo *ec; + CMS_PasswordRecipientInfo *pwri; + int r = 0; + X509_ALGOR *algtmp, *kekalg = NULL; + EVP_CIPHER_CTX *kekctx = NULL; + char name[OSSL_MAX_NAME_SIZE]; + EVP_CIPHER *kekcipher; + unsigned char *key = NULL; + size_t keylen; + const CMS_CTX *cms_ctx = ossl_cms_get0_cmsctx(cms); + + ec = ossl_cms_get0_env_enc_content(cms); + + pwri = ri->d.pwri; + + if (pwri->pass == NULL) { + ERR_raise(ERR_LIB_CMS, CMS_R_NO_PASSWORD); + return 0; + } + algtmp = pwri->keyEncryptionAlgorithm; + + if (!algtmp || OBJ_obj2nid(algtmp->algorithm) != NID_id_alg_PWRI_KEK) { + ERR_raise(ERR_LIB_CMS, CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM); + return 0; + } + + kekalg = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(X509_ALGOR), + algtmp->parameter); + + if (kekalg == NULL) { + ERR_raise(ERR_LIB_CMS, CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER); + return 0; + } + + OBJ_obj2txt(name, sizeof(name), kekalg->algorithm, 0); + kekcipher = EVP_CIPHER_fetch(ossl_cms_ctx_get0_libctx(cms_ctx), name, + ossl_cms_ctx_get0_propq(cms_ctx)); + + if (kekcipher == NULL) { + ERR_raise(ERR_LIB_CMS, CMS_R_UNKNOWN_CIPHER); + goto err; + } + + kekctx = EVP_CIPHER_CTX_new(); + if (kekctx == NULL) { + ERR_raise(ERR_LIB_CMS, ERR_R_EVP_LIB); + goto err; + } + /* Fixup cipher based on AlgorithmIdentifier to set IV etc */ + if (!EVP_CipherInit_ex(kekctx, kekcipher, NULL, NULL, NULL, en_de)) + goto err; + EVP_CIPHER_CTX_set_padding(kekctx, 0); + if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0) { + ERR_raise(ERR_LIB_CMS, CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR); + goto err; + } + + algtmp = pwri->keyDerivationAlgorithm; + + /* Finish password based key derivation to setup key in "ctx" */ + + if (!EVP_PBE_CipherInit_ex(algtmp->algorithm, + (char *)pwri->pass, (int)pwri->passlen, + algtmp->parameter, kekctx, en_de, + cms_ctx->libctx, cms_ctx->propq)) { + ERR_raise(ERR_LIB_CMS, ERR_R_EVP_LIB); + goto err; + } + + /* Finally wrap/unwrap the key */ + + if (en_de) { + + if (!kek_wrap_key(NULL, &keylen, ec->key, ec->keylen, kekctx, cms_ctx)) + goto err; + + key = OPENSSL_malloc(keylen); + + if (key == NULL) + goto err; + + if (!kek_wrap_key(key, &keylen, ec->key, ec->keylen, kekctx, cms_ctx)) + goto err; + pwri->encryptedKey->data = key; + pwri->encryptedKey->length = (int)keylen; + } else { + key = OPENSSL_malloc(pwri->encryptedKey->length); + if (key == NULL) + goto err; + if (!kek_unwrap_key(key, &keylen, + pwri->encryptedKey->data, + pwri->encryptedKey->length, kekctx)) { + ERR_raise(ERR_LIB_CMS, CMS_R_UNWRAP_FAILURE); + goto err; + } + + OPENSSL_clear_free(ec->key, ec->keylen); + ec->key = key; + ec->keylen = keylen; + } + + r = 1; + +err: + EVP_CIPHER_free(kekcipher); + EVP_CIPHER_CTX_free(kekctx); + + if (!r) + OPENSSL_free(key); + X509_ALGOR_free(kekalg); + + return r; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-42768-pkcs7_decrypt_rinfo/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-42768-pkcs7_decrypt_rinfo/fixed.c new file mode 100644 index 0000000..6b26a75 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-42768-pkcs7_decrypt_rinfo/fixed.c @@ -0,0 +1,47 @@ +/* Provenance: openssl/openssl pkcs7_decrypt_rinfo (fixed). + * repo: openssl/openssl + * commit: d5030cdf32d6cd27bd964a0cb7aed2b7cb713369 + * parent: f04d65692dd8109be9f387ce2ddd9fb1ab612b6b + * commit_url: https://github.com/openssl/openssl/commit/d5030cdf32d6cd27bd964a0cb7aed2b7cb713369 + * cve: CVE-2026-42768 + * license: Apache-2.0 + * function: pkcs7_decrypt_rinfo + * relpath: crypto/pkcs7/pk7_doit.c + */ + +static int pkcs7_decrypt_rinfo(unsigned char **pek, int *peklen, + PKCS7_RECIP_INFO *ri, EVP_PKEY *pkey, + size_t fixlen) +{ + EVP_PKEY_CTX *pctx = NULL; + unsigned char *ek = NULL; + size_t eklen; + int ret = -1; + const PKCS7_CTX *ctx = ri->ctx; + + pctx = EVP_PKEY_CTX_new_from_pkey(ossl_pkcs7_ctx_get0_libctx(ctx), pkey, + ossl_pkcs7_ctx_get0_propq(ctx)); + if (pctx == NULL) + return -1; + + if (EVP_PKEY_decrypt_init(pctx) <= 0) + goto err; + + ret = evp_pkey_decrypt_alloc(pctx, &ek, &eklen, fixlen, + ASN1_STRING_get0_data(ri->enc_key), ASN1_STRING_length(ri->enc_key)); + if (ret <= 0) + goto err; + + ret = 1; + + OPENSSL_clear_free(*pek, *peklen); + *pek = ek; + *peklen = (int)eklen; + +err: + EVP_PKEY_CTX_free(pctx); + if (!ret) + OPENSSL_free(ek); + + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-42768-pkcs7_decrypt_rinfo/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-42768-pkcs7_decrypt_rinfo/vuln.c new file mode 100644 index 0000000..ee119e5 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-42768-pkcs7_decrypt_rinfo/vuln.c @@ -0,0 +1,54 @@ +/* Provenance: openssl/openssl pkcs7_decrypt_rinfo (vuln). + * repo: openssl/openssl + * commit: f04d65692dd8109be9f387ce2ddd9fb1ab612b6b + * parent: f04d65692dd8109be9f387ce2ddd9fb1ab612b6b + * commit_url: https://github.com/openssl/openssl/commit/d5030cdf32d6cd27bd964a0cb7aed2b7cb713369 + * cve: CVE-2026-42768 + * license: Apache-2.0 + * function: pkcs7_decrypt_rinfo + * relpath: crypto/pkcs7/pk7_doit.c + */ + +static int pkcs7_decrypt_rinfo(unsigned char **pek, int *peklen, + PKCS7_RECIP_INFO *ri, EVP_PKEY *pkey, + size_t fixlen) +{ + EVP_PKEY_CTX *pctx = NULL; + unsigned char *ek = NULL; + size_t eklen; + int ret = -1; + const PKCS7_CTX *ctx = ri->ctx; + + pctx = EVP_PKEY_CTX_new_from_pkey(ossl_pkcs7_ctx_get0_libctx(ctx), pkey, + ossl_pkcs7_ctx_get0_propq(ctx)); + if (pctx == NULL) + return -1; + + if (EVP_PKEY_decrypt_init(pctx) <= 0) + goto err; + + if (EVP_PKEY_is_a(pkey, "RSA")) + /* upper layer pkcs7 code incorrectly assumes that a successful RSA + * decryption means that the key matches ciphertext (which never + * was the case, implicit rejection or not), so to make it work + * disable implicit rejection for RSA keys */ + EVP_PKEY_CTX_ctrl_str(pctx, "rsa_pkcs1_implicit_rejection", "0"); + + ret = evp_pkey_decrypt_alloc(pctx, &ek, &eklen, fixlen, + ASN1_STRING_get0_data(ri->enc_key), ASN1_STRING_length(ri->enc_key)); + if (ret <= 0) + goto err; + + ret = 1; + + OPENSSL_clear_free(*pek, *peklen); + *pek = ek; + *peklen = (int)eklen; + +err: + EVP_PKEY_CTX_free(pctx); + if (!ret) + OPENSSL_free(ek); + + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-42768/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-42768/fixed.c new file mode 100644 index 0000000..aa9c84f --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-42768/fixed.c @@ -0,0 +1,89 @@ +/* Provenance: openssl/openssl cms_RecipientInfo_ktri_decrypt (fixed). + * repo: openssl/openssl + * commit: d5030cdf32d6cd27bd964a0cb7aed2b7cb713369 + * parent: f04d65692dd8109be9f387ce2ddd9fb1ab612b6b + * commit_url: https://github.com/openssl/openssl/commit/d5030cdf32d6cd27bd964a0cb7aed2b7cb713369 + * cve: CVE-2026-42768 + * license: Apache-2.0 + * function: cms_RecipientInfo_ktri_decrypt + * relpath: crypto/cms/cms_env.c + */ + +static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms, + CMS_RecipientInfo *ri) +{ + CMS_KeyTransRecipientInfo *ktri = ri->d.ktri; + EVP_PKEY *pkey = ktri->pkey; + unsigned char *ek = NULL; + size_t eklen; + int ret = 0; + size_t fixlen = 0; + const EVP_CIPHER *cipher = NULL; + EVP_CIPHER *fetched_cipher = NULL; + CMS_EncryptedContentInfo *ec; + const CMS_CTX *ctx = ossl_cms_get0_cmsctx(cms); + OSSL_LIB_CTX *libctx = ossl_cms_ctx_get0_libctx(ctx); + const char *propq = ossl_cms_ctx_get0_propq(ctx); + + ec = ossl_cms_get0_env_enc_content(cms); + + if (ktri->pkey == NULL) { + ERR_raise(ERR_LIB_CMS, CMS_R_NO_PRIVATE_KEY); + return 0; + } + + if (cms->d.envelopedData->encryptedContentInfo->havenocert + && !cms->d.envelopedData->encryptedContentInfo->debug) { + X509_ALGOR *calg = ec->contentEncryptionAlgorithm; + char name[OSSL_MAX_NAME_SIZE]; + + OBJ_obj2txt(name, sizeof(name), calg->algorithm, 0); + + (void)ERR_set_mark(); + fetched_cipher = EVP_CIPHER_fetch(libctx, name, propq); + + if (fetched_cipher != NULL) + cipher = fetched_cipher; + else + cipher = EVP_get_cipherbyobj(calg->algorithm); + if (cipher == NULL) { + (void)ERR_clear_last_mark(); + ERR_raise(ERR_LIB_CMS, CMS_R_UNKNOWN_CIPHER); + return 0; + } + (void)ERR_pop_to_mark(); + + fixlen = EVP_CIPHER_get_key_length(cipher); + EVP_CIPHER_free(fetched_cipher); + } + + ktri->pctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, propq); + if (ktri->pctx == NULL) + goto err; + + if (EVP_PKEY_decrypt_init(ktri->pctx) <= 0) + goto err; + + if (!ossl_cms_env_asn1_ctrl(ri, 1)) + goto err; + + if (evp_pkey_decrypt_alloc(ktri->pctx, &ek, &eklen, fixlen, + ktri->encryptedKey->data, + ktri->encryptedKey->length) + <= 0) + goto err; + + ret = 1; + + OPENSSL_clear_free(ec->key, ec->keylen); + ec->key = ek; + ec->keylen = eklen; + +err: + EVP_PKEY_CTX_free(ktri->pctx); + ktri->pctx = NULL; + if (!ret) + OPENSSL_free(ek); + + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-42768/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-42768/vuln.c new file mode 100644 index 0000000..63b8baa --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-42768/vuln.c @@ -0,0 +1,96 @@ +/* Provenance: openssl/openssl cms_RecipientInfo_ktri_decrypt (vuln). + * repo: openssl/openssl + * commit: f04d65692dd8109be9f387ce2ddd9fb1ab612b6b + * parent: f04d65692dd8109be9f387ce2ddd9fb1ab612b6b + * commit_url: https://github.com/openssl/openssl/commit/d5030cdf32d6cd27bd964a0cb7aed2b7cb713369 + * cve: CVE-2026-42768 + * license: Apache-2.0 + * function: cms_RecipientInfo_ktri_decrypt + * relpath: crypto/cms/cms_env.c + */ + +static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms, + CMS_RecipientInfo *ri) +{ + CMS_KeyTransRecipientInfo *ktri = ri->d.ktri; + EVP_PKEY *pkey = ktri->pkey; + unsigned char *ek = NULL; + size_t eklen; + int ret = 0; + size_t fixlen = 0; + const EVP_CIPHER *cipher = NULL; + EVP_CIPHER *fetched_cipher = NULL; + CMS_EncryptedContentInfo *ec; + const CMS_CTX *ctx = ossl_cms_get0_cmsctx(cms); + OSSL_LIB_CTX *libctx = ossl_cms_ctx_get0_libctx(ctx); + const char *propq = ossl_cms_ctx_get0_propq(ctx); + + ec = ossl_cms_get0_env_enc_content(cms); + + if (ktri->pkey == NULL) { + ERR_raise(ERR_LIB_CMS, CMS_R_NO_PRIVATE_KEY); + return 0; + } + + if (cms->d.envelopedData->encryptedContentInfo->havenocert + && !cms->d.envelopedData->encryptedContentInfo->debug) { + X509_ALGOR *calg = ec->contentEncryptionAlgorithm; + char name[OSSL_MAX_NAME_SIZE]; + + OBJ_obj2txt(name, sizeof(name), calg->algorithm, 0); + + (void)ERR_set_mark(); + fetched_cipher = EVP_CIPHER_fetch(libctx, name, propq); + + if (fetched_cipher != NULL) + cipher = fetched_cipher; + else + cipher = EVP_get_cipherbyobj(calg->algorithm); + if (cipher == NULL) { + (void)ERR_clear_last_mark(); + ERR_raise(ERR_LIB_CMS, CMS_R_UNKNOWN_CIPHER); + return 0; + } + (void)ERR_pop_to_mark(); + + fixlen = EVP_CIPHER_get_key_length(cipher); + EVP_CIPHER_free(fetched_cipher); + } + + ktri->pctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, propq); + if (ktri->pctx == NULL) + goto err; + + if (EVP_PKEY_decrypt_init(ktri->pctx) <= 0) + goto err; + + if (!ossl_cms_env_asn1_ctrl(ri, 1)) + goto err; + + if (EVP_PKEY_is_a(pkey, "RSA")) + /* upper layer CMS code incorrectly assumes that a successful RSA + * decryption means that the key matches ciphertext (which never + * was the case, implicit rejection or not), so to make it work + * disable implicit rejection for RSA keys */ + EVP_PKEY_CTX_ctrl_str(ktri->pctx, "rsa_pkcs1_implicit_rejection", "0"); + + if (evp_pkey_decrypt_alloc(ktri->pctx, &ek, &eklen, fixlen, + ktri->encryptedKey->data, + ktri->encryptedKey->length) + <= 0) + goto err; + + ret = 1; + + OPENSSL_clear_free(ec->key, ec->keylen); + ec->key = ek; + ec->keylen = eklen; + +err: + EVP_PKEY_CTX_free(ktri->pctx); + ktri->pctx = NULL; + if (!ret) + OPENSSL_free(ek); + + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-42769/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-42769/fixed.c new file mode 100644 index 0000000..65dcbca --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-42769/fixed.c @@ -0,0 +1,52 @@ +/* Provenance: openssl/openssl selfsigned_verify_cb (fixed). + * repo: openssl/openssl + * commit: c2765d53c2649b56bc1ca1bb799e42002953056a + * parent: d5030cdf32d6cd27bd964a0cb7aed2b7cb713369 + * commit_url: https://github.com/openssl/openssl/commit/c2765d53c2649b56bc1ca1bb799e42002953056a + * cve: CVE-2026-42769 + * license: Apache-2.0 + * function: selfsigned_verify_cb + * relpath: crypto/cmp/cmp_genm.c + */ + +static int selfsigned_verify_cb(int ok, X509_STORE_CTX *store_ctx) +{ + if (ok == 0 + && X509_STORE_CTX_get_error_depth(store_ctx) == 0 + && X509_STORE_CTX_get_error(store_ctx) + == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) { + /* in this case, custom chain building */ + int i; + STACK_OF(X509) *trust; + STACK_OF(X509) *chain = X509_STORE_CTX_get0_chain(store_ctx); + STACK_OF(X509) *untrusted = X509_STORE_CTX_get0_untrusted(store_ctx); + X509_STORE_CTX_check_issued_fn check_issued = X509_STORE_CTX_get_check_issued(store_ctx); + X509 *cert = sk_X509_value(chain, 0); /* target cert */ + X509 *issuer; + + for (i = 0; i < sk_X509_num(untrusted); i++) { + cert = sk_X509_value(untrusted, i); + if (!X509_add_cert(chain, cert, X509_ADD_FLAG_UP_REF)) + return 0; + } + + trust = X509_STORE_get1_all_certs(X509_STORE_CTX_get0_store(store_ctx)); + for (i = 0; i < sk_X509_num(trust); i++) { + issuer = sk_X509_value(trust, i); + if ((*check_issued)(store_ctx, cert, issuer)) { + if (X509_add_cert(chain, issuer, X509_ADD_FLAG_UP_REF)) + ok = 1; + break; + } + } + sk_X509_pop_free(trust, X509_free); + return ok; + } else { + X509_STORE *ts = X509_STORE_CTX_get0_store(store_ctx); + X509_STORE_CTX_verify_cb verify_cb; + + if (ts == NULL || (verify_cb = X509_STORE_get_verify_cb(ts)) == NULL) + return ok; + return (*verify_cb)(ok, store_ctx); + } +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-42769/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-42769/vuln.c new file mode 100644 index 0000000..b70867e --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-42769/vuln.c @@ -0,0 +1,52 @@ +/* Provenance: openssl/openssl selfsigned_verify_cb (vuln). + * repo: openssl/openssl + * commit: d5030cdf32d6cd27bd964a0cb7aed2b7cb713369 + * parent: d5030cdf32d6cd27bd964a0cb7aed2b7cb713369 + * commit_url: https://github.com/openssl/openssl/commit/c2765d53c2649b56bc1ca1bb799e42002953056a + * cve: CVE-2026-42769 + * license: Apache-2.0 + * function: selfsigned_verify_cb + * relpath: crypto/cmp/cmp_genm.c + */ + +static int selfsigned_verify_cb(int ok, X509_STORE_CTX *store_ctx) +{ + if (ok == 0 + && X509_STORE_CTX_get_error_depth(store_ctx) == 0 + && X509_STORE_CTX_get_error(store_ctx) + == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) { + /* in this case, custom chain building */ + int i; + STACK_OF(X509) *trust; + STACK_OF(X509) *chain = X509_STORE_CTX_get0_chain(store_ctx); + STACK_OF(X509) *untrusted = X509_STORE_CTX_get0_untrusted(store_ctx); + X509_STORE_CTX_check_issued_fn check_issued = X509_STORE_CTX_get_check_issued(store_ctx); + X509 *cert = sk_X509_value(chain, 0); /* target cert */ + X509 *issuer; + + for (i = 0; i < sk_X509_num(untrusted); i++) { + cert = sk_X509_value(untrusted, i); + if (!X509_add_cert(chain, cert, X509_ADD_FLAG_UP_REF)) + return 0; + } + + trust = X509_STORE_get1_all_certs(X509_STORE_CTX_get0_store(store_ctx)); + for (i = 0; i < sk_X509_num(trust); i++) { + issuer = sk_X509_value(trust, i); + if ((*check_issued)(store_ctx, cert, issuer)) { + if (X509_add_cert(chain, cert, X509_ADD_FLAG_UP_REF)) + ok = 1; + break; + } + } + sk_X509_pop_free(trust, X509_free); + return ok; + } else { + X509_STORE *ts = X509_STORE_CTX_get0_store(store_ctx); + X509_STORE_CTX_verify_cb verify_cb; + + if (ts == NULL || (verify_cb = X509_STORE_get_verify_cb(ts)) == NULL) + return ok; + return (*verify_cb)(ok, store_ctx); + } +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-42771/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-42771/fixed.c new file mode 100644 index 0000000..c271875 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-42771/fixed.c @@ -0,0 +1,55 @@ +/* Provenance: openssl/openssl validate_hostname_part (fixed). + * repo: openssl/openssl + * commit: b3a555a0a7aa0028887149f6f973af89a4937bea + * parent: 0f3fab2eccc7c3417093a8243dd15d95b6cb472d + * commit_url: https://github.com/openssl/openssl/commit/b3a555a0a7aa0028887149f6f973af89a4937bea + * cve: CVE-2026-42771 + * license: Apache-2.0 + * function: validate_hostname_part + * relpath: crypto/x509/x509_vpm.c + */ + +static int validate_hostname_part(const char *name, size_t len, + ossl_charset_t charset) +{ + size_t i, part_len; + char c, prev; + + if (len < 2 || len > 256) + return 0; + + part_len = 0; + prev = '\0'; + for (i = 0; i < len; i++) { + c = name[i]; + if (c == '.') { + /* + * Can not start a label with a . + * unless it is the very first character. + */ + if (part_len == 0 && i != 0) + return 0; + /* Can not end a label with a - */ + if (prev == '-') + return 0; + part_len = 0; + } else { + /* Can not start a label with a - */ + if (part_len == 0 && c == '-') { + return 0; + } + if (!is_label_ok(c, charset) && c != '-') + return 0; + part_len++; + } + if (part_len > 63) + return 0; + + prev = c; + } + /* Can not end with a . or a _ */ + if (prev == '.' || prev == '-') + return 0; + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-42771/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-42771/vuln.c new file mode 100644 index 0000000..b67f2fd --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-42771/vuln.c @@ -0,0 +1,55 @@ +/* Provenance: openssl/openssl validate_hostname_part (vuln). + * repo: openssl/openssl + * commit: 0f3fab2eccc7c3417093a8243dd15d95b6cb472d + * parent: 0f3fab2eccc7c3417093a8243dd15d95b6cb472d + * commit_url: https://github.com/openssl/openssl/commit/b3a555a0a7aa0028887149f6f973af89a4937bea + * cve: CVE-2026-42771 + * license: Apache-2.0 + * function: validate_hostname_part + * relpath: crypto/x509/x509_vpm.c + */ + +static int validate_hostname_part(const char *name, size_t len, + ossl_charset_t charset) +{ + size_t i, part_len; + char c, prev; + + if (len < 2 || len > 256) + return 0; + + part_len = 0; + prev = '\0'; + for (i = 0; i < len; i++) { + c = name[i]; + if (c == '.') { + /* + * Can not start a label with a . + * unless it is the very first character. + */ + if (part_len == 0 && i != 0) + return 0; + /* Can not end a label with a - */ + if (prev == '-') + return 0; + part_len = 0; + } else { + /* Can not start a label with a - */ + if (part_len == 0 && c == '-') { + return 0; + } + if (!is_label_ok(c, charset) && c != '-') + return 0; + } + part_len++; + if (part_len > 63) + return 0; + + prev = c; + } + /* Can not end with a . or a _ */ + if (prev == '.' || prev == '-') + return 0; + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-45445/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-45445/fixed.c new file mode 100644 index 0000000..9fad995 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-45445/fixed.c @@ -0,0 +1,45 @@ +/* Provenance: openssl/openssl aes_ocb_cipher (fixed). + * repo: openssl/openssl + * commit: f87f0b6a8e04bcdeb98afc82b0da06a2d537f399 + * parent: 5f489043b662fed32fbf7eb7442c479568eb43fd + * commit_url: https://github.com/openssl/openssl/commit/f87f0b6a8e04bcdeb98afc82b0da06a2d537f399 + * cve: CVE-2026-45445 + * license: Apache-2.0 + * function: aes_ocb_cipher + * relpath: providers/implementations/ciphers/cipher_aes_ocb.c + */ + +static int aes_ocb_cipher(void *vctx, unsigned char *out, size_t *outl, + size_t outsize, const unsigned char *in, size_t inl) +{ + PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx; + + if (!ossl_prov_is_running()) + return 0; + + if (outsize < inl) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + /* + * Mirror the streaming handler: refuse if the key has not been set, + * and push the buffered IV into the OCB context before any data is + * processed. Without this, CRYPTO_ocb128_encrypt/decrypt runs with + * Offset_0 = 0 regardless of the caller's IV -- catastrophic + * (key, nonce) reuse, and a subsequent EVP_*Final_ex() emits a tag + * that is a function of (key, iv) only. + */ + if (!ctx->key_set || !update_iv(ctx)) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + + if (!aes_generic_ocb_cipher(ctx, in, out, inl)) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + + *outl = inl; + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-45445/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-45445/vuln.c new file mode 100644 index 0000000..5a1a603 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-45445/vuln.c @@ -0,0 +1,32 @@ +/* Provenance: openssl/openssl aes_ocb_cipher (vuln). + * repo: openssl/openssl + * commit: 5f489043b662fed32fbf7eb7442c479568eb43fd + * parent: 5f489043b662fed32fbf7eb7442c479568eb43fd + * commit_url: https://github.com/openssl/openssl/commit/f87f0b6a8e04bcdeb98afc82b0da06a2d537f399 + * cve: CVE-2026-45445 + * license: Apache-2.0 + * function: aes_ocb_cipher + * relpath: providers/implementations/ciphers/cipher_aes_ocb.c + */ + +static int aes_ocb_cipher(void *vctx, unsigned char *out, size_t *outl, + size_t outsize, const unsigned char *in, size_t inl) +{ + PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx; + + if (!ossl_prov_is_running()) + return 0; + + if (outsize < inl) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + if (!aes_generic_ocb_cipher(ctx, in, out, inl)) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + + *outl = inl; + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-45446-aes_siv_set_ctx_params/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-45446-aes_siv_set_ctx_params/fixed.c new file mode 100644 index 0000000..aeeb660 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-45446-aes_siv_set_ctx_params/fixed.c @@ -0,0 +1,54 @@ +/* Provenance: openssl/openssl aes_siv_set_ctx_params (fixed). + * repo: openssl/openssl + * commit: 609bcb24866d64f1fc49d38b852edbb39057d721 + * parent: f87f0b6a8e04bcdeb98afc82b0da06a2d537f399 + * commit_url: https://github.com/openssl/openssl/commit/609bcb24866d64f1fc49d38b852edbb39057d721 + * cve: CVE-2026-45446 + * license: Apache-2.0 + * function: aes_siv_set_ctx_params + * relpath: providers/implementations/ciphers/cipher_aes_siv.c + */ + +static int aes_siv_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx; + struct aes_siv_set_ctx_params_st p; + unsigned int speed = 0; + SIV128_CONTEXT *sctx = &ctx->siv; + + if (ctx == NULL || !aes_siv_set_ctx_params_decoder(params, &p)) + return 0; + + if (p.tag != NULL) { + if (ctx->enc) + return 1; + if (p.tag->data_type != OSSL_PARAM_OCTET_STRING + || !ctx->hw->settag(ctx, p.tag->data, p.tag->data_size)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + } + + if (p.speed != NULL) { + if (!OSSL_PARAM_get_uint(p.speed, &speed)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + ctx->hw->setspeed(ctx, (int)speed); + } + + if (p.keylen != NULL) { + size_t keylen; + + if (!OSSL_PARAM_get_size_t(p.keylen, &keylen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + /* The key length can not be modified */ + if (keylen != ctx->keylen) + return 0; + } + sctx->final_ret = -1; + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-45446-aes_siv_set_ctx_params/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-45446-aes_siv_set_ctx_params/vuln.c new file mode 100644 index 0000000..b978dfd --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-45446-aes_siv_set_ctx_params/vuln.c @@ -0,0 +1,51 @@ +/* Provenance: openssl/openssl aes_siv_set_ctx_params (vuln). + * repo: openssl/openssl + * commit: f87f0b6a8e04bcdeb98afc82b0da06a2d537f399 + * parent: f87f0b6a8e04bcdeb98afc82b0da06a2d537f399 + * commit_url: https://github.com/openssl/openssl/commit/609bcb24866d64f1fc49d38b852edbb39057d721 + * cve: CVE-2026-45446 + * license: Apache-2.0 + * function: aes_siv_set_ctx_params + * relpath: providers/implementations/ciphers/cipher_aes_siv.c + */ + +static int aes_siv_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx; + struct aes_siv_set_ctx_params_st p; + unsigned int speed = 0; + + if (ctx == NULL || !aes_siv_set_ctx_params_decoder(params, &p)) + return 0; + + if (p.tag != NULL) { + if (ctx->enc) + return 1; + if (p.tag->data_type != OSSL_PARAM_OCTET_STRING + || !ctx->hw->settag(ctx, p.tag->data, p.tag->data_size)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + } + + if (p.speed != NULL) { + if (!OSSL_PARAM_get_uint(p.speed, &speed)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + ctx->hw->setspeed(ctx, (int)speed); + } + + if (p.keylen != NULL) { + size_t keylen; + + if (!OSSL_PARAM_get_size_t(p.keylen, &keylen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + /* The key length can not be modified */ + if (keylen != ctx->keylen) + return 0; + } + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-45446/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-45446/fixed.c new file mode 100644 index 0000000..6e918b3 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-45446/fixed.c @@ -0,0 +1,95 @@ +/* Provenance: openssl/openssl aes_gcm_siv_initkey (fixed). + * repo: openssl/openssl + * commit: 609bcb24866d64f1fc49d38b852edbb39057d721 + * parent: f87f0b6a8e04bcdeb98afc82b0da06a2d537f399 + * commit_url: https://github.com/openssl/openssl/commit/609bcb24866d64f1fc49d38b852edbb39057d721 + * cve: CVE-2026-45446 + * license: Apache-2.0 + * function: aes_gcm_siv_initkey + * relpath: providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c + */ + +static int aes_gcm_siv_initkey(void *vctx) +{ + PROV_AES_GCM_SIV_CTX *ctx = (PROV_AES_GCM_SIV_CTX *)vctx; + uint8_t output[BLOCK_SIZE]; + uint32_t counter = 0x0; + size_t i; + union { + uint32_t counter; + uint8_t block[BLOCK_SIZE]; + } data; + int out_len; + EVP_CIPHER *ecb = NULL; + DECLARE_IS_ENDIAN; + + switch (ctx->key_len) { + case 16: + ecb = EVP_CIPHER_fetch(ctx->libctx, "AES-128-ECB", NULL); + break; + case 24: + ecb = EVP_CIPHER_fetch(ctx->libctx, "AES-192-ECB", NULL); + break; + case 32: + ecb = EVP_CIPHER_fetch(ctx->libctx, "AES-256-ECB", NULL); + break; + default: + goto err; + } + + if (ctx->ecb_ctx == NULL && (ctx->ecb_ctx = EVP_CIPHER_CTX_new()) == NULL) + goto err; + if (!EVP_EncryptInit_ex2(ctx->ecb_ctx, ecb, ctx->key_gen_key, NULL, NULL)) + goto err; + + memset(&data, 0, sizeof(data)); + memcpy(&data.block[sizeof(data.counter)], ctx->nonce, NONCE_SIZE); + + ctx->generated_tag = 0; + memset(ctx->tag, 0, TAG_SIZE); + + /* msg_auth_key is always 16 bytes in size, regardless of AES128/AES256 */ + /* counter is stored little-endian */ + for (i = 0; i < BLOCK_SIZE; i += 8) { + if (IS_LITTLE_ENDIAN) { + data.counter = counter; + } else { + data.counter = GSWAP4(counter); + } + /* Block size is 16 (128 bits), but only 8 bytes are used */ + out_len = BLOCK_SIZE; + if (!EVP_EncryptUpdate(ctx->ecb_ctx, output, &out_len, data.block, BLOCK_SIZE)) + goto err; + memcpy(&ctx->msg_auth_key[i], output, 8); + counter++; + } + + /* msg_enc_key length is directly tied to key length AES128/AES256 */ + for (i = 0; i < ctx->key_len; i += 8) { + if (IS_LITTLE_ENDIAN) { + data.counter = counter; + } else { + data.counter = GSWAP4(counter); + } + /* Block size is 16 bytes (128 bits), but only 8 bytes are used */ + out_len = BLOCK_SIZE; + if (!EVP_EncryptUpdate(ctx->ecb_ctx, output, &out_len, data.block, BLOCK_SIZE)) + goto err; + memcpy(&ctx->msg_enc_key[i], output, 8); + counter++; + } + + if (!EVP_EncryptInit_ex2(ctx->ecb_ctx, ecb, ctx->msg_enc_key, NULL, NULL)) + goto err; + + /* Freshen up the state */ + ctx->used_enc = 0; + ctx->used_dec = 0; + EVP_CIPHER_free(ecb); + return 1; +err: + EVP_CIPHER_CTX_free(ctx->ecb_ctx); + EVP_CIPHER_free(ecb); + ctx->ecb_ctx = NULL; + return 0; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-45446/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-45446/vuln.c new file mode 100644 index 0000000..1d5ca7e --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-45446/vuln.c @@ -0,0 +1,92 @@ +/* Provenance: openssl/openssl aes_gcm_siv_initkey (vuln). + * repo: openssl/openssl + * commit: f87f0b6a8e04bcdeb98afc82b0da06a2d537f399 + * parent: f87f0b6a8e04bcdeb98afc82b0da06a2d537f399 + * commit_url: https://github.com/openssl/openssl/commit/609bcb24866d64f1fc49d38b852edbb39057d721 + * cve: CVE-2026-45446 + * license: Apache-2.0 + * function: aes_gcm_siv_initkey + * relpath: providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c + */ + +static int aes_gcm_siv_initkey(void *vctx) +{ + PROV_AES_GCM_SIV_CTX *ctx = (PROV_AES_GCM_SIV_CTX *)vctx; + uint8_t output[BLOCK_SIZE]; + uint32_t counter = 0x0; + size_t i; + union { + uint32_t counter; + uint8_t block[BLOCK_SIZE]; + } data; + int out_len; + EVP_CIPHER *ecb = NULL; + DECLARE_IS_ENDIAN; + + switch (ctx->key_len) { + case 16: + ecb = EVP_CIPHER_fetch(ctx->libctx, "AES-128-ECB", NULL); + break; + case 24: + ecb = EVP_CIPHER_fetch(ctx->libctx, "AES-192-ECB", NULL); + break; + case 32: + ecb = EVP_CIPHER_fetch(ctx->libctx, "AES-256-ECB", NULL); + break; + default: + goto err; + } + + if (ctx->ecb_ctx == NULL && (ctx->ecb_ctx = EVP_CIPHER_CTX_new()) == NULL) + goto err; + if (!EVP_EncryptInit_ex2(ctx->ecb_ctx, ecb, ctx->key_gen_key, NULL, NULL)) + goto err; + + memset(&data, 0, sizeof(data)); + memcpy(&data.block[sizeof(data.counter)], ctx->nonce, NONCE_SIZE); + + /* msg_auth_key is always 16 bytes in size, regardless of AES128/AES256 */ + /* counter is stored little-endian */ + for (i = 0; i < BLOCK_SIZE; i += 8) { + if (IS_LITTLE_ENDIAN) { + data.counter = counter; + } else { + data.counter = GSWAP4(counter); + } + /* Block size is 16 (128 bits), but only 8 bytes are used */ + out_len = BLOCK_SIZE; + if (!EVP_EncryptUpdate(ctx->ecb_ctx, output, &out_len, data.block, BLOCK_SIZE)) + goto err; + memcpy(&ctx->msg_auth_key[i], output, 8); + counter++; + } + + /* msg_enc_key length is directly tied to key length AES128/AES256 */ + for (i = 0; i < ctx->key_len; i += 8) { + if (IS_LITTLE_ENDIAN) { + data.counter = counter; + } else { + data.counter = GSWAP4(counter); + } + /* Block size is 16 bytes (128 bits), but only 8 bytes are used */ + out_len = BLOCK_SIZE; + if (!EVP_EncryptUpdate(ctx->ecb_ctx, output, &out_len, data.block, BLOCK_SIZE)) + goto err; + memcpy(&ctx->msg_enc_key[i], output, 8); + counter++; + } + + if (!EVP_EncryptInit_ex2(ctx->ecb_ctx, ecb, ctx->msg_enc_key, NULL, NULL)) + goto err; + + /* Freshen up the state */ + ctx->used_enc = 0; + ctx->used_dec = 0; + EVP_CIPHER_free(ecb); + return 1; +err: + EVP_CIPHER_CTX_free(ctx->ecb_ctx); + EVP_CIPHER_free(ecb); + ctx->ecb_ctx = NULL; + return 0; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-45447/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-45447/fixed.c new file mode 100644 index 0000000..138400b --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-45447/fixed.c @@ -0,0 +1,165 @@ +/* Provenance: openssl/openssl PKCS7_verify (fixed). + * repo: openssl/openssl + * commit: f4129fbe3cde786d363510069fe297234f99be8f + * parent: 609bcb24866d64f1fc49d38b852edbb39057d721 + * commit_url: https://github.com/openssl/openssl/commit/f4129fbe3cde786d363510069fe297234f99be8f + * cve: CVE-2026-45447 + * license: Apache-2.0 + * function: PKCS7_verify + * relpath: crypto/pkcs7/pk7_smime.c + */ + +int PKCS7_verify(PKCS7 *p7, const STACK_OF(X509) *certs, X509_STORE *store, + BIO *indata, BIO *out, int flags) +{ + STACK_OF(X509) *signers; + STACK_OF(X509) *included_certs; + STACK_OF(X509) *untrusted = NULL; + X509 *signer; + STACK_OF(PKCS7_SIGNER_INFO) *sinfos; + PKCS7_SIGNER_INFO *si; + X509_STORE_CTX *cert_ctx = NULL; + char *buf = NULL; + int i, j = 0, k, ret = 0; + BIO *p7bio = NULL; + BIO *tmpout = NULL; + BIO *next = NULL; + const PKCS7_CTX *p7_ctx; + + if (p7 == NULL) { + ERR_raise(ERR_LIB_PKCS7, PKCS7_R_INVALID_NULL_POINTER); + return 0; + } + + if (!PKCS7_type_is_signed(p7)) { + ERR_raise(ERR_LIB_PKCS7, PKCS7_R_WRONG_CONTENT_TYPE); + return 0; + } + + /* Check for no data and no content: no data to verify signature */ + if (PKCS7_get_detached(p7) && indata == NULL) { + ERR_raise(ERR_LIB_PKCS7, PKCS7_R_NO_CONTENT); + return 0; + } + + if (flags & PKCS7_NO_DUAL_CONTENT) { + /* + * This was originally "#if 0" because we thought that only old broken + * Netscape did this. It turns out that Authenticode uses this kind + * of "extended" PKCS7 format, and things like UEFI secure boot and + * tools like osslsigncode need it. In Authenticode the verification + * process is different, but the existing PKCs7 verification works. + */ + if (!PKCS7_get_detached(p7) && indata != NULL) { + ERR_raise(ERR_LIB_PKCS7, PKCS7_R_CONTENT_AND_DATA_PRESENT); + return 0; + } + } + + sinfos = PKCS7_get_signer_info(p7); + + if (!sinfos || !sk_PKCS7_SIGNER_INFO_num(sinfos)) { + ERR_raise(ERR_LIB_PKCS7, PKCS7_R_NO_SIGNATURES_ON_DATA); + return 0; + } + + signers = PKCS7_get0_signers(p7, certs, flags); + if (signers == NULL) + return 0; + + /* Now verify the certificates */ + p7_ctx = ossl_pkcs7_get0_ctx(p7); + cert_ctx = X509_STORE_CTX_new_ex(ossl_pkcs7_ctx_get0_libctx(p7_ctx), + ossl_pkcs7_ctx_get0_propq(p7_ctx)); + if (cert_ctx == NULL) + goto err; + if ((flags & PKCS7_NOVERIFY) == 0) { + if (!ossl_x509_add_certs_new(&untrusted, certs, X509_ADD_FLAG_NO_DUP)) + goto err; + included_certs = pkcs7_get0_certificates(p7); + if ((flags & PKCS7_NOCHAIN) == 0 + && !ossl_x509_add_certs_new(&untrusted, included_certs, + X509_ADD_FLAG_NO_DUP)) + goto err; + + for (k = 0; k < sk_X509_num(signers); k++) { + signer = sk_X509_value(signers, k); + if (!X509_STORE_CTX_init(cert_ctx, store, signer, untrusted)) { + ERR_raise(ERR_LIB_PKCS7, ERR_R_X509_LIB); + goto err; + } + if ((flags & PKCS7_NOCHAIN) == 0 + && !X509_STORE_CTX_set_default(cert_ctx, "smime_sign")) + goto err; + if (!(flags & PKCS7_NOCRL)) + X509_STORE_CTX_set0_crls(cert_ctx, p7->d.sign->crl); + i = X509_verify_cert(cert_ctx); + if (i <= 0) { + j = X509_STORE_CTX_get_error(cert_ctx); + ERR_raise_data(ERR_LIB_PKCS7, PKCS7_R_CERTIFICATE_VERIFY_ERROR, + "Verify error: %s", + X509_verify_cert_error_string(j)); + goto err; + } + /* Check for revocation status here */ + } + } + + if ((p7bio = PKCS7_dataInit(p7, indata)) == NULL) + goto err; + + if (flags & PKCS7_TEXT) { + if ((tmpout = BIO_new(BIO_s_mem())) == NULL) { + ERR_raise(ERR_LIB_PKCS7, ERR_R_BIO_LIB); + goto err; + } + BIO_set_mem_eof_return(tmpout, 0); + } else + tmpout = out; + + /* We now have to 'read' from p7bio to calculate digests etc. */ + if ((buf = OPENSSL_malloc(BUFFERSIZE)) == NULL) + goto err; + for (;;) { + i = BIO_read(p7bio, buf, BUFFERSIZE); + if (i <= 0) + break; + if (tmpout) + BIO_write(tmpout, buf, i); + } + + if (flags & PKCS7_TEXT) { + if (!SMIME_text(tmpout, out)) { + ERR_raise(ERR_LIB_PKCS7, PKCS7_R_SMIME_TEXT_ERROR); + goto err; + } + } + + /* Now Verify All Signatures */ + if (!(flags & PKCS7_NOSIGS)) + for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(sinfos); i++) { + si = sk_PKCS7_SIGNER_INFO_value(sinfos, i); + signer = sk_X509_value(signers, i); + j = PKCS7_signatureVerify(p7bio, p7, si, signer); + if (j <= 0) { + ERR_raise(ERR_LIB_PKCS7, PKCS7_R_SIGNATURE_FAILURE); + goto err; + } + } + + ret = 1; + +err: + if (flags & PKCS7_TEXT) + BIO_free(tmpout); + X509_STORE_CTX_free(cert_ctx); + OPENSSL_free(buf); + while (p7bio != NULL && p7bio != indata) { + next = BIO_pop(p7bio); + BIO_free(p7bio); + p7bio = next; + } + sk_X509_free(signers); + sk_X509_free(untrusted); + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-45447/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-45447/vuln.c new file mode 100644 index 0000000..eb1e7c6 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-45447/vuln.c @@ -0,0 +1,162 @@ +/* Provenance: openssl/openssl PKCS7_verify (vuln). + * repo: openssl/openssl + * commit: 609bcb24866d64f1fc49d38b852edbb39057d721 + * parent: 609bcb24866d64f1fc49d38b852edbb39057d721 + * commit_url: https://github.com/openssl/openssl/commit/f4129fbe3cde786d363510069fe297234f99be8f + * cve: CVE-2026-45447 + * license: Apache-2.0 + * function: PKCS7_verify + * relpath: crypto/pkcs7/pk7_smime.c + */ + +int PKCS7_verify(PKCS7 *p7, const STACK_OF(X509) *certs, X509_STORE *store, + BIO *indata, BIO *out, int flags) +{ + STACK_OF(X509) *signers; + STACK_OF(X509) *included_certs; + STACK_OF(X509) *untrusted = NULL; + X509 *signer; + STACK_OF(PKCS7_SIGNER_INFO) *sinfos; + PKCS7_SIGNER_INFO *si; + X509_STORE_CTX *cert_ctx = NULL; + char *buf = NULL; + int i, j = 0, k, ret = 0; + BIO *p7bio = NULL; + BIO *tmpout = NULL; + const PKCS7_CTX *p7_ctx; + + if (p7 == NULL) { + ERR_raise(ERR_LIB_PKCS7, PKCS7_R_INVALID_NULL_POINTER); + return 0; + } + + if (!PKCS7_type_is_signed(p7)) { + ERR_raise(ERR_LIB_PKCS7, PKCS7_R_WRONG_CONTENT_TYPE); + return 0; + } + + /* Check for no data and no content: no data to verify signature */ + if (PKCS7_get_detached(p7) && indata == NULL) { + ERR_raise(ERR_LIB_PKCS7, PKCS7_R_NO_CONTENT); + return 0; + } + + if (flags & PKCS7_NO_DUAL_CONTENT) { + /* + * This was originally "#if 0" because we thought that only old broken + * Netscape did this. It turns out that Authenticode uses this kind + * of "extended" PKCS7 format, and things like UEFI secure boot and + * tools like osslsigncode need it. In Authenticode the verification + * process is different, but the existing PKCs7 verification works. + */ + if (!PKCS7_get_detached(p7) && indata != NULL) { + ERR_raise(ERR_LIB_PKCS7, PKCS7_R_CONTENT_AND_DATA_PRESENT); + return 0; + } + } + + sinfos = PKCS7_get_signer_info(p7); + + if (!sinfos || !sk_PKCS7_SIGNER_INFO_num(sinfos)) { + ERR_raise(ERR_LIB_PKCS7, PKCS7_R_NO_SIGNATURES_ON_DATA); + return 0; + } + + signers = PKCS7_get0_signers(p7, certs, flags); + if (signers == NULL) + return 0; + + /* Now verify the certificates */ + p7_ctx = ossl_pkcs7_get0_ctx(p7); + cert_ctx = X509_STORE_CTX_new_ex(ossl_pkcs7_ctx_get0_libctx(p7_ctx), + ossl_pkcs7_ctx_get0_propq(p7_ctx)); + if (cert_ctx == NULL) + goto err; + if ((flags & PKCS7_NOVERIFY) == 0) { + if (!ossl_x509_add_certs_new(&untrusted, certs, X509_ADD_FLAG_NO_DUP)) + goto err; + included_certs = pkcs7_get0_certificates(p7); + if ((flags & PKCS7_NOCHAIN) == 0 + && !ossl_x509_add_certs_new(&untrusted, included_certs, + X509_ADD_FLAG_NO_DUP)) + goto err; + + for (k = 0; k < sk_X509_num(signers); k++) { + signer = sk_X509_value(signers, k); + if (!X509_STORE_CTX_init(cert_ctx, store, signer, untrusted)) { + ERR_raise(ERR_LIB_PKCS7, ERR_R_X509_LIB); + goto err; + } + if ((flags & PKCS7_NOCHAIN) == 0 + && !X509_STORE_CTX_set_default(cert_ctx, "smime_sign")) + goto err; + if (!(flags & PKCS7_NOCRL)) + X509_STORE_CTX_set0_crls(cert_ctx, p7->d.sign->crl); + i = X509_verify_cert(cert_ctx); + if (i <= 0) { + j = X509_STORE_CTX_get_error(cert_ctx); + ERR_raise_data(ERR_LIB_PKCS7, PKCS7_R_CERTIFICATE_VERIFY_ERROR, + "Verify error: %s", + X509_verify_cert_error_string(j)); + goto err; + } + /* Check for revocation status here */ + } + } + + if ((p7bio = PKCS7_dataInit(p7, indata)) == NULL) + goto err; + + if (flags & PKCS7_TEXT) { + if ((tmpout = BIO_new(BIO_s_mem())) == NULL) { + ERR_raise(ERR_LIB_PKCS7, ERR_R_BIO_LIB); + goto err; + } + BIO_set_mem_eof_return(tmpout, 0); + } else + tmpout = out; + + /* We now have to 'read' from p7bio to calculate digests etc. */ + if ((buf = OPENSSL_malloc(BUFFERSIZE)) == NULL) + goto err; + for (;;) { + i = BIO_read(p7bio, buf, BUFFERSIZE); + if (i <= 0) + break; + if (tmpout) + BIO_write(tmpout, buf, i); + } + + if (flags & PKCS7_TEXT) { + if (!SMIME_text(tmpout, out)) { + ERR_raise(ERR_LIB_PKCS7, PKCS7_R_SMIME_TEXT_ERROR); + goto err; + } + } + + /* Now Verify All Signatures */ + if (!(flags & PKCS7_NOSIGS)) + for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(sinfos); i++) { + si = sk_PKCS7_SIGNER_INFO_value(sinfos, i); + signer = sk_X509_value(signers, i); + j = PKCS7_signatureVerify(p7bio, p7, si, signer); + if (j <= 0) { + ERR_raise(ERR_LIB_PKCS7, PKCS7_R_SIGNATURE_FAILURE); + goto err; + } + } + + ret = 1; + +err: + if (flags & PKCS7_TEXT) + BIO_free(tmpout); + X509_STORE_CTX_free(cert_ctx); + OPENSSL_free(buf); + if (indata != NULL) + BIO_pop(p7bio); + BIO_free_all(p7bio); + sk_X509_free(signers); + sk_X509_free(untrusted); + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-54874-dtls1_process_record/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-54874-dtls1_process_record/fixed.c new file mode 100644 index 0000000..a7973b1 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-54874-dtls1_process_record/fixed.c @@ -0,0 +1,193 @@ +/* Provenance: openssl/openssl dtls1_process_record (fixed). + * repo: openssl/openssl + * commit: 1ca5a124b48f1ffe6980ad33724b452fbd62da1e + * parent: a0c8ec557d9cac078f032d76cdf684fe743eb382 + * commit_url: https://github.com/openssl/openssl/commit/1ca5a124b48f1ffe6980ad33724b452fbd62da1e + * cve: CVE-2026-54874 + * license: Apache-2.0 + * function: dtls1_process_record + * relpath: ssl/record/ssl3_record.c + */ + +int dtls1_process_record(SSL *s, DTLS1_BITMAP *bitmap) +{ + int i; + int enc_err; + SSL_SESSION *sess; + SSL3_RECORD *rr; + int imac_size; + size_t mac_size = 0; + unsigned char md[EVP_MAX_MD_SIZE]; + size_t max_plain_length = SSL3_RT_MAX_PLAIN_LENGTH; + SSL_MAC_BUF macbuf = { NULL, 0 }; + int ret = 0; + + rr = RECORD_LAYER_get_rrec(&s->rlayer); + sess = s->session; + + /* + * At this point, s->rlayer.packet_length == SSL3_RT_HEADER_LNGTH + rr->length, + * and we have that many bytes in s->rlayer.packet + */ + rr->input = &(RECORD_LAYER_get_packet(&s->rlayer)[DTLS1_RT_HEADER_LENGTH]); + + /* + * ok, we can now read from 's->rlayer.packet' data into 'rr'. rr->input + * points at rr->length bytes, which need to be copied into rr->data by + * either the decryption or by the decompression. When the data is 'copied' + * into the rr->data buffer, rr->input will be pointed at the new buffer + */ + + /* + * We now have - encrypted [ MAC [ compressed [ plain ] ] ] rr->length + * bytes of encrypted compressed stuff. + */ + + /* check is not needed I believe */ + if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH) { + SSLfatal(s, SSL_AD_RECORD_OVERFLOW, SSL_R_ENCRYPTED_LENGTH_TOO_LONG); + return 0; + } + + /* decrypt in place in 'rr->input' */ + rr->data = rr->input; + rr->orig_len = rr->length; + + if (s->read_hash != NULL) { + const EVP_MD *tmpmd = EVP_MD_CTX_get0_md(s->read_hash); + + if (tmpmd != NULL) { + imac_size = EVP_MD_get_size(tmpmd); + if (!ossl_assert(imac_size >= 0 && imac_size <= EVP_MAX_MD_SIZE)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB); + return 0; + } + mac_size = (size_t)imac_size; + } + } + + if (SSL_READ_ETM(s) && s->read_hash) { + unsigned char *mac; + + if (rr->orig_len < mac_size) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_TOO_SHORT); + return 0; + } + rr->length -= mac_size; + mac = rr->data + rr->length; + i = s->method->ssl3_enc->mac(s, rr, md, 0 /* not send */); + if (i == 0 || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0) { + SSLfatal(s, SSL_AD_BAD_RECORD_MAC, + SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC); + return 0; + } + /* + * We've handled the mac now - there is no MAC inside the encrypted + * record + */ + mac_size = 0; + } + + /* + * Set a mark around the packet decryption attempt. This is DTLS, so + * bad packets are just ignored, and we don't want to leave stray + * errors in the queue from processing bogus junk that we ignored. + */ + ERR_set_mark(); + enc_err = s->method->ssl3_enc->enc(s, rr, 1, 0, &macbuf, mac_size); + + /*- + * enc_err is: + * 0: if the record is publicly invalid, or an internal error, or AEAD + * decryption failed, or ETM decryption failed. + * 1: Success or MTE decryption failed (MAC will be randomised) + */ + if (enc_err == 0) { + ERR_pop_to_mark(); + if (ossl_statem_in_error(s)) { + /* SSLfatal() got called */ + goto end; + } + /* For DTLS we simply ignore bad packets. */ + rr->length = 0; + RECORD_LAYER_reset_packet_length(&s->rlayer); + goto end; + } + ERR_clear_last_mark(); + OSSL_TRACE_BEGIN(TLS) + { + BIO_printf(trc_out, "dec %zd\n", rr->length); + BIO_dump_indent(trc_out, rr->data, rr->length, 4); + } + OSSL_TRACE_END(TLS); + + /* r->length is now the compressed data plus mac */ + if ((sess != NULL) + && !SSL_READ_ETM(s) + && (s->enc_read_ctx != NULL) + && (EVP_MD_CTX_get0_md(s->read_hash) != NULL)) { + /* s->read_hash != NULL => mac_size != -1 */ + + i = s->method->ssl3_enc->mac(s, rr, md, 0 /* not send */); + if (i == 0 || macbuf.mac == NULL + || CRYPTO_memcmp(md, macbuf.mac, mac_size) != 0) + enc_err = 0; + if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH + mac_size) + enc_err = 0; + } + + if (enc_err == 0) { + /* decryption failed, silently discard message */ + rr->length = 0; + RECORD_LAYER_reset_packet_length(&s->rlayer); + goto end; + } + + /* r->length is now just compressed */ + if (s->expand != NULL) { + if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH) { + SSLfatal(s, SSL_AD_RECORD_OVERFLOW, + SSL_R_COMPRESSED_LENGTH_TOO_LONG); + goto end; + } + if (!ssl3_do_uncompress(s, rr)) { + SSLfatal(s, SSL_AD_DECOMPRESSION_FAILURE, SSL_R_BAD_DECOMPRESSION); + goto end; + } + } + + /* use current Max Fragment Length setting if applicable */ + if (s->session != NULL && USE_MAX_FRAGMENT_LENGTH_EXT(s->session)) + max_plain_length = GET_MAX_FRAGMENT_LENGTH(s->session); + + /* send overflow if the plaintext is too long now it has passed MAC */ + if (rr->length > max_plain_length) { + SSLfatal(s, SSL_AD_RECORD_OVERFLOW, SSL_R_DATA_LENGTH_TOO_LONG); + goto end; + } + + rr->off = 0; + /*- + * So at this point the following is true + * ssl->s3.rrec.type is the type of record + * ssl->s3.rrec.length == number of bytes in record + * ssl->s3.rrec.off == offset to first valid byte + * ssl->s3.rrec.data == where to take bytes from, increment + * after use :-). + */ + + /* + * Leave s->rlayer.packet_length alone: ssl3_read_n() starts each new record + * by resetting it, and it must still describe this record's on-wire bytes + * for dtls1_buffer_record() should this record end up being buffered. + */ + + /* Mark receipt of record. */ + dtls1_record_bitmap_update(s, bitmap); + + ret = 1; +end: + if (macbuf.alloced) + OPENSSL_free(macbuf.mac); + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-54874-dtls1_process_record/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-54874-dtls1_process_record/vuln.c new file mode 100644 index 0000000..92ca002 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-54874-dtls1_process_record/vuln.c @@ -0,0 +1,190 @@ +/* Provenance: openssl/openssl dtls1_process_record (vuln). + * repo: openssl/openssl + * commit: a0c8ec557d9cac078f032d76cdf684fe743eb382 + * parent: a0c8ec557d9cac078f032d76cdf684fe743eb382 + * commit_url: https://github.com/openssl/openssl/commit/1ca5a124b48f1ffe6980ad33724b452fbd62da1e + * cve: CVE-2026-54874 + * license: Apache-2.0 + * function: dtls1_process_record + * relpath: ssl/record/ssl3_record.c + */ + +int dtls1_process_record(SSL *s, DTLS1_BITMAP *bitmap) +{ + int i; + int enc_err; + SSL_SESSION *sess; + SSL3_RECORD *rr; + int imac_size; + size_t mac_size = 0; + unsigned char md[EVP_MAX_MD_SIZE]; + size_t max_plain_length = SSL3_RT_MAX_PLAIN_LENGTH; + SSL_MAC_BUF macbuf = { NULL, 0 }; + int ret = 0; + + rr = RECORD_LAYER_get_rrec(&s->rlayer); + sess = s->session; + + /* + * At this point, s->rlayer.packet_length == SSL3_RT_HEADER_LNGTH + rr->length, + * and we have that many bytes in s->rlayer.packet + */ + rr->input = &(RECORD_LAYER_get_packet(&s->rlayer)[DTLS1_RT_HEADER_LENGTH]); + + /* + * ok, we can now read from 's->rlayer.packet' data into 'rr'. rr->input + * points at rr->length bytes, which need to be copied into rr->data by + * either the decryption or by the decompression. When the data is 'copied' + * into the rr->data buffer, rr->input will be pointed at the new buffer + */ + + /* + * We now have - encrypted [ MAC [ compressed [ plain ] ] ] rr->length + * bytes of encrypted compressed stuff. + */ + + /* check is not needed I believe */ + if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH) { + SSLfatal(s, SSL_AD_RECORD_OVERFLOW, SSL_R_ENCRYPTED_LENGTH_TOO_LONG); + return 0; + } + + /* decrypt in place in 'rr->input' */ + rr->data = rr->input; + rr->orig_len = rr->length; + + if (s->read_hash != NULL) { + const EVP_MD *tmpmd = EVP_MD_CTX_get0_md(s->read_hash); + + if (tmpmd != NULL) { + imac_size = EVP_MD_get_size(tmpmd); + if (!ossl_assert(imac_size >= 0 && imac_size <= EVP_MAX_MD_SIZE)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB); + return 0; + } + mac_size = (size_t)imac_size; + } + } + + if (SSL_READ_ETM(s) && s->read_hash) { + unsigned char *mac; + + if (rr->orig_len < mac_size) { + SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_TOO_SHORT); + return 0; + } + rr->length -= mac_size; + mac = rr->data + rr->length; + i = s->method->ssl3_enc->mac(s, rr, md, 0 /* not send */); + if (i == 0 || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0) { + SSLfatal(s, SSL_AD_BAD_RECORD_MAC, + SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC); + return 0; + } + /* + * We've handled the mac now - there is no MAC inside the encrypted + * record + */ + mac_size = 0; + } + + /* + * Set a mark around the packet decryption attempt. This is DTLS, so + * bad packets are just ignored, and we don't want to leave stray + * errors in the queue from processing bogus junk that we ignored. + */ + ERR_set_mark(); + enc_err = s->method->ssl3_enc->enc(s, rr, 1, 0, &macbuf, mac_size); + + /*- + * enc_err is: + * 0: if the record is publicly invalid, or an internal error, or AEAD + * decryption failed, or ETM decryption failed. + * 1: Success or MTE decryption failed (MAC will be randomised) + */ + if (enc_err == 0) { + ERR_pop_to_mark(); + if (ossl_statem_in_error(s)) { + /* SSLfatal() got called */ + goto end; + } + /* For DTLS we simply ignore bad packets. */ + rr->length = 0; + RECORD_LAYER_reset_packet_length(&s->rlayer); + goto end; + } + ERR_clear_last_mark(); + OSSL_TRACE_BEGIN(TLS) + { + BIO_printf(trc_out, "dec %zd\n", rr->length); + BIO_dump_indent(trc_out, rr->data, rr->length, 4); + } + OSSL_TRACE_END(TLS); + + /* r->length is now the compressed data plus mac */ + if ((sess != NULL) + && !SSL_READ_ETM(s) + && (s->enc_read_ctx != NULL) + && (EVP_MD_CTX_get0_md(s->read_hash) != NULL)) { + /* s->read_hash != NULL => mac_size != -1 */ + + i = s->method->ssl3_enc->mac(s, rr, md, 0 /* not send */); + if (i == 0 || macbuf.mac == NULL + || CRYPTO_memcmp(md, macbuf.mac, mac_size) != 0) + enc_err = 0; + if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH + mac_size) + enc_err = 0; + } + + if (enc_err == 0) { + /* decryption failed, silently discard message */ + rr->length = 0; + RECORD_LAYER_reset_packet_length(&s->rlayer); + goto end; + } + + /* r->length is now just compressed */ + if (s->expand != NULL) { + if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH) { + SSLfatal(s, SSL_AD_RECORD_OVERFLOW, + SSL_R_COMPRESSED_LENGTH_TOO_LONG); + goto end; + } + if (!ssl3_do_uncompress(s, rr)) { + SSLfatal(s, SSL_AD_DECOMPRESSION_FAILURE, SSL_R_BAD_DECOMPRESSION); + goto end; + } + } + + /* use current Max Fragment Length setting if applicable */ + if (s->session != NULL && USE_MAX_FRAGMENT_LENGTH_EXT(s->session)) + max_plain_length = GET_MAX_FRAGMENT_LENGTH(s->session); + + /* send overflow if the plaintext is too long now it has passed MAC */ + if (rr->length > max_plain_length) { + SSLfatal(s, SSL_AD_RECORD_OVERFLOW, SSL_R_DATA_LENGTH_TOO_LONG); + goto end; + } + + rr->off = 0; + /*- + * So at this point the following is true + * ssl->s3.rrec.type is the type of record + * ssl->s3.rrec.length == number of bytes in record + * ssl->s3.rrec.off == offset to first valid byte + * ssl->s3.rrec.data == where to take bytes from, increment + * after use :-). + */ + + /* we have pulled in a full packet so zero things */ + RECORD_LAYER_reset_packet_length(&s->rlayer); + + /* Mark receipt of record. */ + dtls1_record_bitmap_update(s, bitmap); + + ret = 1; +end: + if (macbuf.alloced) + OPENSSL_free(macbuf.mac); + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-54874-dtls_rlayer_buffer_recor/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-54874-dtls_rlayer_buffer_recor/fixed.c new file mode 100644 index 0000000..4a42b7c --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-54874-dtls_rlayer_buffer_recor/fixed.c @@ -0,0 +1,56 @@ +/* Provenance: openssl/openssl dtls_rlayer_buffer_record (fixed). + * repo: openssl/openssl + * commit: 7110cb2f75806d0bf809eb2f90790d477900be40 + * parent: 9ec2f6d2ae2bcad907cf7ee38584855bafe4979a + * commit_url: https://github.com/openssl/openssl/commit/7110cb2f75806d0bf809eb2f90790d477900be40 + * cve: CVE-2026-54874 + * license: Apache-2.0 + * function: dtls_rlayer_buffer_record + * relpath: ssl/record/methods/dtls_meth.c + */ + +static int dtls_rlayer_buffer_record(OSSL_RECORD_LAYER *rl, struct pqueue_st *queue, + unsigned char *priority) +{ + DTLS_RLAYER_RECORD_DATA *rdata; + pitem *item; + + /* Limit the size of the queue to prevent DOS attacks */ + if (pqueue_size(queue) >= 100) + return 0; + + rdata = OPENSSL_malloc(sizeof(*rdata)); + item = pitem_new(priority, rdata); + if (rdata == NULL || item == NULL) { + OPENSSL_free(rdata); + pitem_free(item); + RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return -1; + } + + /* + * Take a copy of just this record's on-wire bytes (header + ciphertext) + * rather than the whole (much larger) read buffer. The live rl->rbuf is + * left untouched and continues to be used for subsequent reads. + */ + rdata->packet_length = rl->packet_length; + rdata->packet = OPENSSL_memdup(rl->packet, rl->packet_length); + if (rdata->packet == NULL) { + OPENSSL_free(rdata); + pitem_free(item); + RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_CRYPTO_LIB); + return -1; + } + memcpy(&(rdata->rrec), &rl->rrec[0], sizeof(TLS_RL_RECORD)); + + item->data = rdata; + + if (pqueue_insert(queue, item) == NULL) { + /* Must be a duplicate so ignore it */ + OPENSSL_free(rdata->packet); + OPENSSL_free(rdata); + pitem_free(item); + } + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-54874-dtls_rlayer_buffer_recor/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-54874-dtls_rlayer_buffer_recor/vuln.c new file mode 100644 index 0000000..6bfdbdd --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-54874-dtls_rlayer_buffer_recor/vuln.c @@ -0,0 +1,59 @@ +/* Provenance: openssl/openssl dtls_rlayer_buffer_record (vuln). + * repo: openssl/openssl + * commit: 9ec2f6d2ae2bcad907cf7ee38584855bafe4979a + * parent: 9ec2f6d2ae2bcad907cf7ee38584855bafe4979a + * commit_url: https://github.com/openssl/openssl/commit/7110cb2f75806d0bf809eb2f90790d477900be40 + * cve: CVE-2026-54874 + * license: Apache-2.0 + * function: dtls_rlayer_buffer_record + * relpath: ssl/record/methods/dtls_meth.c + */ + +static int dtls_rlayer_buffer_record(OSSL_RECORD_LAYER *rl, struct pqueue_st *queue, + unsigned char *priority) +{ + DTLS_RLAYER_RECORD_DATA *rdata; + pitem *item; + + /* Limit the size of the queue to prevent DOS attacks */ + if (pqueue_size(queue) >= 100) + return 0; + + rdata = OPENSSL_malloc(sizeof(*rdata)); + item = pitem_new(priority, rdata); + if (rdata == NULL || item == NULL) { + OPENSSL_free(rdata); + pitem_free(item); + RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return -1; + } + + rdata->packet = rl->packet; + rdata->packet_length = rl->packet_length; + memcpy(&(rdata->rbuf), &rl->rbuf, sizeof(TLS_BUFFER)); + memcpy(&(rdata->rrec), &rl->rrec[0], sizeof(TLS_RL_RECORD)); + + item->data = rdata; + + rl->packet = NULL; + rl->packet_length = 0; + memset(&rl->rbuf, 0, sizeof(TLS_BUFFER)); + memset(&rl->rrec[0], 0, sizeof(rl->rrec[0])); + + if (!tls_setup_read_buffer(rl)) { + /* RLAYERfatal() already called */ + OPENSSL_free(rdata->rbuf.buf); + OPENSSL_free(rdata); + pitem_free(item); + return -1; + } + + if (pqueue_insert(queue, item) == NULL) { + /* Must be a duplicate so ignore it */ + OPENSSL_free(rdata->rbuf.buf); + OPENSSL_free(rdata); + pitem_free(item); + } + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-54874/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-54874/fixed.c new file mode 100644 index 0000000..6e285ea --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-54874/fixed.c @@ -0,0 +1,55 @@ +/* Provenance: openssl/openssl DTLS_RECORD_LAYER_clear (fixed). + * repo: openssl/openssl + * commit: 1ca5a124b48f1ffe6980ad33724b452fbd62da1e + * parent: a0c8ec557d9cac078f032d76cdf684fe743eb382 + * commit_url: https://github.com/openssl/openssl/commit/1ca5a124b48f1ffe6980ad33724b452fbd62da1e + * cve: CVE-2026-54874 + * license: Apache-2.0 + * function: DTLS_RECORD_LAYER_clear + * relpath: ssl/record/rec_layer_d1.c + */ + +void DTLS_RECORD_LAYER_clear(RECORD_LAYER *rl) +{ + DTLS_RECORD_LAYER *d; + pitem *item = NULL; + DTLS1_RECORD_DATA *rdata; + pqueue *unprocessed_rcds; + pqueue *processed_rcds; + pqueue *buffered_app_data; + + d = rl->d; + + while ((item = pqueue_pop(d->unprocessed_rcds.q)) != NULL) { + rdata = (DTLS1_RECORD_DATA *)item->data; + OPENSSL_free(rdata->packet); + OPENSSL_free(item->data); + pitem_free(item); + } + + while ((item = pqueue_pop(d->processed_rcds.q)) != NULL) { + rdata = (DTLS1_RECORD_DATA *)item->data; + if (rl->s->options & SSL_OP_CLEANSE_PLAINTEXT) + OPENSSL_cleanse(rdata->packet, rdata->packet_length); + OPENSSL_free(rdata->packet); + OPENSSL_free(item->data); + pitem_free(item); + } + + while ((item = pqueue_pop(d->buffered_app_data.q)) != NULL) { + rdata = (DTLS1_RECORD_DATA *)item->data; + if (rl->s->options & SSL_OP_CLEANSE_PLAINTEXT) + OPENSSL_cleanse(rdata->packet, rdata->packet_length); + OPENSSL_free(rdata->packet); + OPENSSL_free(item->data); + pitem_free(item); + } + + unprocessed_rcds = d->unprocessed_rcds.q; + processed_rcds = d->processed_rcds.q; + buffered_app_data = d->buffered_app_data.q; + memset(d, 0, sizeof(*d)); + d->unprocessed_rcds.q = unprocessed_rcds; + d->processed_rcds.q = processed_rcds; + d->buffered_app_data.q = buffered_app_data; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-54874/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-54874/vuln.c new file mode 100644 index 0000000..592d434 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-54874/vuln.c @@ -0,0 +1,55 @@ +/* Provenance: openssl/openssl DTLS_RECORD_LAYER_clear (vuln). + * repo: openssl/openssl + * commit: a0c8ec557d9cac078f032d76cdf684fe743eb382 + * parent: a0c8ec557d9cac078f032d76cdf684fe743eb382 + * commit_url: https://github.com/openssl/openssl/commit/1ca5a124b48f1ffe6980ad33724b452fbd62da1e + * cve: CVE-2026-54874 + * license: Apache-2.0 + * function: DTLS_RECORD_LAYER_clear + * relpath: ssl/record/rec_layer_d1.c + */ + +void DTLS_RECORD_LAYER_clear(RECORD_LAYER *rl) +{ + DTLS_RECORD_LAYER *d; + pitem *item = NULL; + DTLS1_RECORD_DATA *rdata; + pqueue *unprocessed_rcds; + pqueue *processed_rcds; + pqueue *buffered_app_data; + + d = rl->d; + + while ((item = pqueue_pop(d->unprocessed_rcds.q)) != NULL) { + rdata = (DTLS1_RECORD_DATA *)item->data; + OPENSSL_free(rdata->rbuf.buf); + OPENSSL_free(item->data); + pitem_free(item); + } + + while ((item = pqueue_pop(d->processed_rcds.q)) != NULL) { + rdata = (DTLS1_RECORD_DATA *)item->data; + if (rl->s->options & SSL_OP_CLEANSE_PLAINTEXT) + OPENSSL_cleanse(rdata->rbuf.buf, rdata->rbuf.len); + OPENSSL_free(rdata->rbuf.buf); + OPENSSL_free(item->data); + pitem_free(item); + } + + while ((item = pqueue_pop(d->buffered_app_data.q)) != NULL) { + rdata = (DTLS1_RECORD_DATA *)item->data; + if (rl->s->options & SSL_OP_CLEANSE_PLAINTEXT) + OPENSSL_cleanse(rdata->rbuf.buf, rdata->rbuf.len); + OPENSSL_free(rdata->rbuf.buf); + OPENSSL_free(item->data); + pitem_free(item); + } + + unprocessed_rcds = d->unprocessed_rcds.q; + processed_rcds = d->processed_rcds.q; + buffered_app_data = d->buffered_app_data.q; + memset(d, 0, sizeof(*d)); + d->unprocessed_rcds.q = unprocessed_rcds; + d->processed_rcds.q = processed_rcds; + d->buffered_app_data.q = buffered_app_data; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-63072-cms_kek_cipher/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-63072-cms_kek_cipher/fixed.c new file mode 100644 index 0000000..a19e5a1 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-63072-cms_kek_cipher/fixed.c @@ -0,0 +1,65 @@ +/* Provenance: openssl/openssl cms_kek_cipher (fixed). + * repo: openssl/openssl + * commit: 2a3dac874c8057c1f0186849bf1ede1ae7b6b756 + * parent: 1951c3cbd9d5101e027a1eb126f26c3c758f6cc0 + * commit_url: https://github.com/openssl/openssl/commit/2a3dac874c8057c1f0186849bf1ede1ae7b6b756 + * cve: CVE-2026-63072 + * license: Apache-2.0 + * function: cms_kek_cipher + * relpath: crypto/cms/cms_kemri.c + */ + +static int cms_kek_cipher(unsigned char **pout, size_t *poutlen, + const unsigned char *ss, size_t sslen, + const unsigned char *in, size_t inlen, + CMS_KEMRecipientInfo *kemri, int enc) +{ + /* Key encryption key */ + unsigned char kek[EVP_MAX_KEY_LENGTH]; + size_t keklen = kemri->kekLength; + unsigned char *out = NULL; + int outlen = 0; + int rv = 0; + size_t outsize; + + if (keklen > sizeof(kek)) { + ERR_raise(ERR_LIB_CMS, CMS_R_INVALID_KEY_LENGTH); + return 0; + } + + if (inlen > INT_MAX) + return 0; + + if (!kdf_derive(kek, keklen, ss, sslen, kemri)) + goto err; + + /* Set KEK in context */ + if (!EVP_CipherInit_ex(kemri->ctx, NULL, NULL, kek, NULL, enc)) + goto err; + /* obtain output length of ciphered key */ + if (!EVP_CipherUpdate(kemri->ctx, NULL, &outlen, in, (int)inlen)) + goto err; + /* + * On its integrity-failure paths that primitive writes and cleanses up to + * inlen bytes of the output buffer. Size the buffer for that worst case so + * a failed unwrap cannot write past the allocation. + */ + outsize = (size_t)outlen < inlen ? inlen : (size_t)outlen; + out = OPENSSL_malloc(outsize); + if (out == NULL) + goto err; + if (!EVP_CipherUpdate(kemri->ctx, out, &outlen, in, (int)inlen)) + goto err; + *pout = out; + out = NULL; + *poutlen = (size_t)outlen; + + rv = 1; +err: + OPENSSL_free(out); + OPENSSL_cleanse(kek, sizeof(kek)); + EVP_CIPHER_CTX_reset(kemri->ctx); + EVP_PKEY_CTX_free(kemri->pctx); + kemri->pctx = NULL; + return rv; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-63072-cms_kek_cipher/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-63072-cms_kek_cipher/vuln.c new file mode 100644 index 0000000..bebfaf1 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-63072-cms_kek_cipher/vuln.c @@ -0,0 +1,58 @@ +/* Provenance: openssl/openssl cms_kek_cipher (vuln). + * repo: openssl/openssl + * commit: 1951c3cbd9d5101e027a1eb126f26c3c758f6cc0 + * parent: 1951c3cbd9d5101e027a1eb126f26c3c758f6cc0 + * commit_url: https://github.com/openssl/openssl/commit/2a3dac874c8057c1f0186849bf1ede1ae7b6b756 + * cve: CVE-2026-63072 + * license: Apache-2.0 + * function: cms_kek_cipher + * relpath: crypto/cms/cms_kemri.c + */ + +static int cms_kek_cipher(unsigned char **pout, size_t *poutlen, + const unsigned char *ss, size_t sslen, + const unsigned char *in, size_t inlen, + CMS_KEMRecipientInfo *kemri, int enc) +{ + /* Key encryption key */ + unsigned char kek[EVP_MAX_KEY_LENGTH]; + size_t keklen = kemri->kekLength; + unsigned char *out = NULL; + int outlen = 0; + int rv = 0; + + if (keklen > sizeof(kek)) { + ERR_raise(ERR_LIB_CMS, CMS_R_INVALID_KEY_LENGTH); + return 0; + } + + if (inlen > INT_MAX) + return 0; + + if (!kdf_derive(kek, keklen, ss, sslen, kemri)) + goto err; + + /* Set KEK in context */ + if (!EVP_CipherInit_ex(kemri->ctx, NULL, NULL, kek, NULL, enc)) + goto err; + /* obtain output length of ciphered key */ + if (!EVP_CipherUpdate(kemri->ctx, NULL, &outlen, in, (int)inlen)) + goto err; + out = OPENSSL_malloc(outlen); + if (out == NULL) + goto err; + if (!EVP_CipherUpdate(kemri->ctx, out, &outlen, in, (int)inlen)) + goto err; + *pout = out; + out = NULL; + *poutlen = (size_t)outlen; + + rv = 1; +err: + OPENSSL_free(out); + OPENSSL_cleanse(kek, sizeof(kek)); + EVP_CIPHER_CTX_reset(kemri->ctx); + EVP_PKEY_CTX_free(kemri->pctx); + kemri->pctx = NULL; + return rv; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-63072/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-63072/fixed.c new file mode 100644 index 0000000..d7d034e --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-63072/fixed.c @@ -0,0 +1,62 @@ +/* Provenance: openssl/openssl cms_kek_cipher (fixed). + * repo: openssl/openssl + * commit: a0c8ec557d9cac078f032d76cdf684fe743eb382 + * parent: d307f61f1b341b6eb7d5d07bd6902a939c709bc6 + * commit_url: https://github.com/openssl/openssl/commit/a0c8ec557d9cac078f032d76cdf684fe743eb382 + * cve: CVE-2026-63072 + * license: Apache-2.0 + * function: cms_kek_cipher + * relpath: crypto/cms/cms_kari.c + */ + +static int cms_kek_cipher(unsigned char **pout, size_t *poutlen, + const unsigned char *in, size_t inlen, + CMS_KeyAgreeRecipientInfo *kari, int enc) +{ + /* Key encryption key */ + unsigned char kek[EVP_MAX_KEY_LENGTH]; + size_t keklen; + int rv = 0; + unsigned char *out = NULL; + size_t out_alloc_len = 0; + int outlen; + size_t outsize; + + keklen = EVP_CIPHER_CTX_get_key_length(kari->ctx); + if (keklen > EVP_MAX_KEY_LENGTH) + return 0; + /* Derive KEK */ + if (EVP_PKEY_derive(kari->pctx, kek, &keklen) <= 0) + goto err; + /* Set KEK in context */ + if (!EVP_CipherInit_ex(kari->ctx, NULL, NULL, kek, NULL, enc)) + goto err; + /* obtain output length of ciphered key */ + if (!EVP_CipherUpdate(kari->ctx, NULL, &outlen, in, inlen)) + goto err; + /* + * On its integrity-failure paths that primitive writes and cleanses up to + * inlen bytes of the output buffer. Size the buffer for that worst case so + * a failed unwrap cannot write past the allocation. + */ + outsize = (size_t)outlen < inlen ? inlen : (size_t)outlen; + out = OPENSSL_malloc(outsize); + if (out == NULL) + goto err; + out_alloc_len = (size_t)outlen; + if (!EVP_CipherUpdate(kari->ctx, out, &outlen, in, (int)inlen)) + goto err; + *pout = out; + *poutlen = (size_t)outlen; + rv = 1; + +err: + OPENSSL_cleanse(kek, keklen); + if (!rv) + OPENSSL_clear_free(out, out_alloc_len); + EVP_CIPHER_CTX_reset(kari->ctx); + /* FIXME: WHY IS kari->pctx freed here? /RL */ + EVP_PKEY_CTX_free(kari->pctx); + kari->pctx = NULL; + return rv; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-63072/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-63072/vuln.c new file mode 100644 index 0000000..7fedc5a --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-63072/vuln.c @@ -0,0 +1,55 @@ +/* Provenance: openssl/openssl cms_kek_cipher (vuln). + * repo: openssl/openssl + * commit: d307f61f1b341b6eb7d5d07bd6902a939c709bc6 + * parent: d307f61f1b341b6eb7d5d07bd6902a939c709bc6 + * commit_url: https://github.com/openssl/openssl/commit/a0c8ec557d9cac078f032d76cdf684fe743eb382 + * cve: CVE-2026-63072 + * license: Apache-2.0 + * function: cms_kek_cipher + * relpath: crypto/cms/cms_kari.c + */ + +static int cms_kek_cipher(unsigned char **pout, size_t *poutlen, + const unsigned char *in, size_t inlen, + CMS_KeyAgreeRecipientInfo *kari, int enc) +{ + /* Key encryption key */ + unsigned char kek[EVP_MAX_KEY_LENGTH]; + size_t keklen; + int rv = 0; + unsigned char *out = NULL; + size_t out_alloc_len = 0; + int outlen; + + keklen = EVP_CIPHER_CTX_get_key_length(kari->ctx); + if (keklen > EVP_MAX_KEY_LENGTH) + return 0; + /* Derive KEK */ + if (EVP_PKEY_derive(kari->pctx, kek, &keklen) <= 0) + goto err; + /* Set KEK in context */ + if (!EVP_CipherInit_ex(kari->ctx, NULL, NULL, kek, NULL, enc)) + goto err; + /* obtain output length of ciphered key */ + if (!EVP_CipherUpdate(kari->ctx, NULL, &outlen, in, inlen)) + goto err; + out = OPENSSL_malloc(outlen); + if (out == NULL) + goto err; + out_alloc_len = (size_t)outlen; + if (!EVP_CipherUpdate(kari->ctx, out, &outlen, in, (int)inlen)) + goto err; + *pout = out; + *poutlen = (size_t)outlen; + rv = 1; + +err: + OPENSSL_cleanse(kek, keklen); + if (!rv) + OPENSSL_clear_free(out, out_alloc_len); + EVP_CIPHER_CTX_reset(kari->ctx); + /* FIXME: WHY IS kari->pctx freed here? /RL */ + EVP_PKEY_CTX_free(kari->pctx); + kari->pctx = NULL; + return rv; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-63073/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-63073/fixed.c new file mode 100644 index 0000000..dff5402 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-63073/fixed.c @@ -0,0 +1,188 @@ +/* Provenance: openssl/openssl ossl_cmp_msg_check_update (fixed). + * repo: openssl/openssl + * commit: a7e5a6eea8fd3ccca6b6fbba031a5fbf8a3d93b4 + * parent: 1e8c398db67404babd3e5af999bb6bd86f720c76 + * commit_url: https://github.com/openssl/openssl/commit/a7e5a6eea8fd3ccca6b6fbba031a5fbf8a3d93b4 + * cve: CVE-2026-63073 + * license: Apache-2.0 + * function: ossl_cmp_msg_check_update + * relpath: crypto/cmp/cmp_vfy.c + */ + +int ossl_cmp_msg_check_update(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg, + ossl_cmp_allow_unprotected_cb_t cb, int cb_arg) +{ + OSSL_CMP_PKIHEADER *hdr; + const X509_NAME *expected_sender; + int num_untrusted, num_added, res; + + if (!ossl_assert(ctx != NULL && msg != NULL && msg->header != NULL)) + return 0; + hdr = OSSL_CMP_MSG_get0_header(msg); + + /* If expected_sender is given, validate sender name of received msg */ + expected_sender = ctx->expected_sender; + if (expected_sender == NULL && ctx->srvCert != NULL) + expected_sender = X509_get_subject_name(ctx->srvCert); + if (expected_sender != NULL) { + const X509_NAME *actual_sender; + char *str; + + if (hdr->sender->type != GEN_DIRNAME) { + ERR_raise(ERR_LIB_CMP, CMP_R_SENDER_GENERALNAME_TYPE_NOT_SUPPORTED); + return 0; + } + actual_sender = hdr->sender->d.directoryName; + /* + * Compare actual sender name of response with expected sender name. + * Mitigates risk of accepting misused PBM secret or + * misused certificate of an unauthorized entity of a trusted hierarchy. + */ + if (!check_name(ctx, 0, "sender DN field", actual_sender, + "expected sender", expected_sender)) { + str = X509_NAME_oneline(actual_sender, NULL, 0); + ERR_raise_data(ERR_LIB_CMP, CMP_R_UNEXPECTED_SENDER, + "%s", str != NULL ? str : ""); + OPENSSL_free(str); + return 0; + } + } + /* Note: if recipient was NULL-DN it could be learned here if needed */ + + num_added = sk_X509_num(msg->extraCerts); + if (num_added > 10) + ossl_cmp_log1(WARN, ctx, "received CMP message contains %d extraCerts", + num_added); + /* + * Store any provided extraCerts in ctx for use in OSSL_CMP_validate_msg() + * and for future use, such that they are available to ctx->certConf_cb and + * the peer does not need to send them again in the same transaction. + * Note that it does not help validating the message before storing the + * extraCerts because they do not belong to the protected msg part anyway. + * The extraCerts are prepended. Allows simple removal if they shall not be + * cached. Also they get used first, which is likely good for efficiency. + */ + num_untrusted = ctx->untrusted == NULL ? 0 : sk_X509_num(ctx->untrusted); + res = ossl_x509_add_certs_new(&ctx->untrusted, msg->extraCerts, + /* this allows self-signed certs */ + X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP + | X509_ADD_FLAG_PREPEND); + num_added = (ctx->untrusted == NULL ? 0 : sk_X509_num(ctx->untrusted)) + - num_untrusted; + if (!res) { + while (num_added-- > 0) + X509_free(sk_X509_shift(ctx->untrusted)); + return 0; + } + + if (hdr->protectionAlg != NULL) + res = OSSL_CMP_validate_msg(ctx, msg) + /* explicitly permitted exceptions for invalid protection: */ + || (cb != NULL && (*cb)(ctx, msg, 1, cb_arg) > 0); + else + /* explicitly permitted exceptions for missing protection: */ + res = cb != NULL && (*cb)(ctx, msg, 0, cb_arg) > 0; +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + res = 1; /* support more aggressive fuzzing by letting invalid msg pass */ +#endif + + /* + * remove extraCerts again if not caching + * or if we failed validation above, lest a remote user + * starts sending us lots of certificates in invalid messages + * leading to a DOS from unbounded certificate stack growth + */ + if (ctx->noCacheExtraCerts || res != 1) + while (num_added-- > 0) + X509_free(sk_X509_shift(ctx->untrusted)); + + if (!res) { + if (hdr->protectionAlg != NULL) + ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_VALIDATING_PROTECTION); + else + ERR_raise(ERR_LIB_CMP, CMP_R_MISSING_PROTECTION); + return 0; + } + + /* check CMP version number in header */ + if (ossl_cmp_hdr_get_pvno(hdr) != OSSL_CMP_PVNO_2 + && ossl_cmp_hdr_get_pvno(hdr) != OSSL_CMP_PVNO_3) { +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PVNO); + return 0; +#endif + } + + if (OSSL_CMP_MSG_get_bodytype(msg) < 0) { +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + ERR_raise(ERR_LIB_CMP, CMP_R_PKIBODY_ERROR); + return 0; +#endif + } + + /* compare received transactionID with the expected one in previous msg */ + if (!check_transactionID_or_nonce(ctx->transactionID, hdr->transactionID, + CMP_R_TRANSACTIONID_UNMATCHED)) + return 0; + + /* + * enable clearing irrelevant errors + * in attempts to validate recipient nonce in case of delayed delivery. + */ + (void)ERR_set_mark(); + /* compare received nonce with the one we sent */ + if (!check_transactionID_or_nonce(ctx->senderNonce, hdr->recipNonce, + CMP_R_RECIPNONCE_UNMATCHED)) { + /* check if we are polling and received final response */ + if (ctx->first_senderNonce == NULL + || OSSL_CMP_MSG_get_bodytype(msg) == OSSL_CMP_PKIBODY_POLLREP + /* compare received nonce with our sender nonce at poll start */ + || !check_transactionID_or_nonce(ctx->first_senderNonce, + hdr->recipNonce, + CMP_R_RECIPNONCE_UNMATCHED)) { + (void)ERR_clear_last_mark(); + return 0; + } + } + (void)ERR_pop_to_mark(); + + /* if not yet present, learn transactionID */ + if (ctx->transactionID == NULL + && !OSSL_CMP_CTX_set1_transactionID(ctx, hdr->transactionID)) + return 0; + + /* + * RFC 4210 section 5.1.1 states: the recipNonce is copied from + * the senderNonce of the previous message in the transaction. + * --> Store for setting in next message + */ + if (!ossl_cmp_ctx_set1_recipNonce(ctx, hdr->senderNonce)) + return 0; + + if (ossl_cmp_hdr_get_protection_nid(hdr) == NID_id_PasswordBasedMAC) { + /* + * RFC 4210, 5.3.2: 'Note that if the PKI Message Protection is + * "shared secret information", then any certificate transported in + * the caPubs field may be directly trusted as a root CA + * certificate by the initiator.' + */ + switch (OSSL_CMP_MSG_get_bodytype(msg)) { + case OSSL_CMP_PKIBODY_IP: + case OSSL_CMP_PKIBODY_CP: + case OSSL_CMP_PKIBODY_KUP: + case OSSL_CMP_PKIBODY_CCP: + if (ctx->trusted != NULL) { + STACK_OF(X509) *certs = msg->body->value.ip->caPubs; + /* value.ip is same for cp, kup, and ccp */ + + if (!ossl_cmp_X509_STORE_add1_certs(ctx->trusted, certs, 0)) + /* adds both self-issued and not self-issued certs */ + return 0; + } + break; + default: + break; + } + } + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-63073/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-63073/vuln.c new file mode 100644 index 0000000..4d89f9b --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-63073/vuln.c @@ -0,0 +1,188 @@ +/* Provenance: openssl/openssl ossl_cmp_msg_check_update (vuln). + * repo: openssl/openssl + * commit: 1e8c398db67404babd3e5af999bb6bd86f720c76 + * parent: 1e8c398db67404babd3e5af999bb6bd86f720c76 + * commit_url: https://github.com/openssl/openssl/commit/a7e5a6eea8fd3ccca6b6fbba031a5fbf8a3d93b4 + * cve: CVE-2026-63073 + * license: Apache-2.0 + * function: ossl_cmp_msg_check_update + * relpath: crypto/cmp/cmp_vfy.c + */ + +int ossl_cmp_msg_check_update(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg, + ossl_cmp_allow_unprotected_cb_t cb, int cb_arg) +{ + OSSL_CMP_PKIHEADER *hdr; + const X509_NAME *expected_sender; + int num_untrusted, num_added, res; + + if (!ossl_assert(ctx != NULL && msg != NULL && msg->header != NULL)) + return 0; + hdr = OSSL_CMP_MSG_get0_header(msg); + + /* If expected_sender is given, validate sender name of received msg */ + expected_sender = ctx->expected_sender; + if (expected_sender == NULL && ctx->srvCert != NULL) + expected_sender = X509_get_subject_name(ctx->srvCert); + if (expected_sender != NULL) { + const X509_NAME *actual_sender; + char *str; + + if (hdr->sender->type != GEN_DIRNAME) { + ERR_raise(ERR_LIB_CMP, CMP_R_SENDER_GENERALNAME_TYPE_NOT_SUPPORTED); + return 0; + } + actual_sender = hdr->sender->d.directoryName; + /* + * Compare actual sender name of response with expected sender name. + * Mitigates risk of accepting misused PBM secret or + * misused certificate of an unauthorized entity of a trusted hierarchy. + */ + if (!check_name(ctx, 0, "sender DN field", actual_sender, + "expected sender", expected_sender)) { + str = X509_NAME_oneline(actual_sender, NULL, 0); + ERR_raise_data(ERR_LIB_CMP, CMP_R_UNEXPECTED_SENDER, + str != NULL ? str : ""); + OPENSSL_free(str); + return 0; + } + } + /* Note: if recipient was NULL-DN it could be learned here if needed */ + + num_added = sk_X509_num(msg->extraCerts); + if (num_added > 10) + ossl_cmp_log1(WARN, ctx, "received CMP message contains %d extraCerts", + num_added); + /* + * Store any provided extraCerts in ctx for use in OSSL_CMP_validate_msg() + * and for future use, such that they are available to ctx->certConf_cb and + * the peer does not need to send them again in the same transaction. + * Note that it does not help validating the message before storing the + * extraCerts because they do not belong to the protected msg part anyway. + * The extraCerts are prepended. Allows simple removal if they shall not be + * cached. Also they get used first, which is likely good for efficiency. + */ + num_untrusted = ctx->untrusted == NULL ? 0 : sk_X509_num(ctx->untrusted); + res = ossl_x509_add_certs_new(&ctx->untrusted, msg->extraCerts, + /* this allows self-signed certs */ + X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP + | X509_ADD_FLAG_PREPEND); + num_added = (ctx->untrusted == NULL ? 0 : sk_X509_num(ctx->untrusted)) + - num_untrusted; + if (!res) { + while (num_added-- > 0) + X509_free(sk_X509_shift(ctx->untrusted)); + return 0; + } + + if (hdr->protectionAlg != NULL) + res = OSSL_CMP_validate_msg(ctx, msg) + /* explicitly permitted exceptions for invalid protection: */ + || (cb != NULL && (*cb)(ctx, msg, 1, cb_arg) > 0); + else + /* explicitly permitted exceptions for missing protection: */ + res = cb != NULL && (*cb)(ctx, msg, 0, cb_arg) > 0; +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + res = 1; /* support more aggressive fuzzing by letting invalid msg pass */ +#endif + + /* + * remove extraCerts again if not caching + * or if we failed validation above, lest a remote user + * starts sending us lots of certificates in invalid messages + * leading to a DOS from unbounded certificate stack growth + */ + if (ctx->noCacheExtraCerts || res != 1) + while (num_added-- > 0) + X509_free(sk_X509_shift(ctx->untrusted)); + + if (!res) { + if (hdr->protectionAlg != NULL) + ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_VALIDATING_PROTECTION); + else + ERR_raise(ERR_LIB_CMP, CMP_R_MISSING_PROTECTION); + return 0; + } + + /* check CMP version number in header */ + if (ossl_cmp_hdr_get_pvno(hdr) != OSSL_CMP_PVNO_2 + && ossl_cmp_hdr_get_pvno(hdr) != OSSL_CMP_PVNO_3) { +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PVNO); + return 0; +#endif + } + + if (OSSL_CMP_MSG_get_bodytype(msg) < 0) { +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + ERR_raise(ERR_LIB_CMP, CMP_R_PKIBODY_ERROR); + return 0; +#endif + } + + /* compare received transactionID with the expected one in previous msg */ + if (!check_transactionID_or_nonce(ctx->transactionID, hdr->transactionID, + CMP_R_TRANSACTIONID_UNMATCHED)) + return 0; + + /* + * enable clearing irrelevant errors + * in attempts to validate recipient nonce in case of delayed delivery. + */ + (void)ERR_set_mark(); + /* compare received nonce with the one we sent */ + if (!check_transactionID_or_nonce(ctx->senderNonce, hdr->recipNonce, + CMP_R_RECIPNONCE_UNMATCHED)) { + /* check if we are polling and received final response */ + if (ctx->first_senderNonce == NULL + || OSSL_CMP_MSG_get_bodytype(msg) == OSSL_CMP_PKIBODY_POLLREP + /* compare received nonce with our sender nonce at poll start */ + || !check_transactionID_or_nonce(ctx->first_senderNonce, + hdr->recipNonce, + CMP_R_RECIPNONCE_UNMATCHED)) { + (void)ERR_clear_last_mark(); + return 0; + } + } + (void)ERR_pop_to_mark(); + + /* if not yet present, learn transactionID */ + if (ctx->transactionID == NULL + && !OSSL_CMP_CTX_set1_transactionID(ctx, hdr->transactionID)) + return 0; + + /* + * RFC 4210 section 5.1.1 states: the recipNonce is copied from + * the senderNonce of the previous message in the transaction. + * --> Store for setting in next message + */ + if (!ossl_cmp_ctx_set1_recipNonce(ctx, hdr->senderNonce)) + return 0; + + if (ossl_cmp_hdr_get_protection_nid(hdr) == NID_id_PasswordBasedMAC) { + /* + * RFC 4210, 5.3.2: 'Note that if the PKI Message Protection is + * "shared secret information", then any certificate transported in + * the caPubs field may be directly trusted as a root CA + * certificate by the initiator.' + */ + switch (OSSL_CMP_MSG_get_bodytype(msg)) { + case OSSL_CMP_PKIBODY_IP: + case OSSL_CMP_PKIBODY_CP: + case OSSL_CMP_PKIBODY_KUP: + case OSSL_CMP_PKIBODY_CCP: + if (ctx->trusted != NULL) { + STACK_OF(X509) *certs = msg->body->value.ip->caPubs; + /* value.ip is same for cp, kup, and ccp */ + + if (!ossl_cmp_X509_STORE_add1_certs(ctx->trusted, certs, 0)) + /* adds both self-issued and not self-issued certs */ + return 0; + } + break; + default: + break; + } + } + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-63074/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-63074/fixed.c new file mode 100644 index 0000000..863a0d5 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-63074/fixed.c @@ -0,0 +1,180 @@ +/* Provenance: openssl/openssl ossl_cmp_msg_check_update (fixed). + * repo: openssl/openssl + * commit: 21a5d9658b0c66daace60e10ea18ff32a448de9f + * parent: 9f2b8522d39ff869fac2ff7c3f20609b54843188 + * commit_url: https://github.com/openssl/openssl/commit/21a5d9658b0c66daace60e10ea18ff32a448de9f + * cve: CVE-2026-63074 + * license: Apache-2.0 + * function: ossl_cmp_msg_check_update + * relpath: crypto/cmp/cmp_vfy.c + */ + +int ossl_cmp_msg_check_update(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg, + ossl_cmp_allow_unprotected_cb_t cb, int cb_arg) +{ + OSSL_CMP_PKIHEADER *hdr; + const X509_NAME *expected_sender; + int num_extra_before, num_extra_after, num_added; + + if (!ossl_assert(ctx != NULL && msg != NULL && msg->header != NULL)) + return 0; + hdr = OSSL_CMP_MSG_get0_header(msg); + + /* validate sender name of received msg */ + if (hdr->sender->type != GEN_DIRNAME) { + ERR_raise(ERR_LIB_CMP, CMP_R_SENDER_GENERALNAME_TYPE_NOT_SUPPORTED); + return 0; + } + /* + * Compare actual sender name of response with expected sender name. + * Mitigates risk to accept misused PBM secret + * or misused certificate of an unauthorized entity of a trusted hierarchy. + */ + expected_sender = ctx->expected_sender; + if (expected_sender == NULL && ctx->srvCert != NULL) + expected_sender = X509_get_subject_name(ctx->srvCert); + if (!check_name(ctx, 0, "sender DN field", hdr->sender->d.directoryName, + "expected sender", expected_sender)) + return 0; + /* Note: if recipient was NULL-DN it could be learned here if needed */ + + if (sk_X509_num(msg->extraCerts) > 10) + ossl_cmp_warn(ctx, + "received CMP message contains more than 10 extraCerts"); + /* + * Store any provided extraCerts in ctx for use in OSSL_CMP_validate_msg() + * and for future use, such that they are available to ctx->certConf_cb and + * the peer does not need to send them again in the same transaction. + * Note that it does not help validating the message before storing the + * extraCerts because they do not belong to the protected msg part anyway. + * For efficiency, the extraCerts are prepended so they get used first. + */ + num_extra_before = sk_X509_num(ctx->untrusted); + if (!X509_add_certs(ctx->untrusted, msg->extraCerts, + /* this allows self-signed certs */ + X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP + | X509_ADD_FLAG_PREPEND)) + return 0; + num_extra_after = sk_X509_num(ctx->untrusted); + num_added = num_extra_after - num_extra_before; + /* validate message protection */ + if (hdr->protectionAlg != NULL) { + /* detect explicitly permitted exceptions for invalid protection */ + if (!OSSL_CMP_validate_msg(ctx, msg) + && (cb == NULL || (*cb)(ctx, msg, 1, cb_arg) <= 0)) { + /* + * remove extraCerts again if not caching + * or if we failed validation above, lest a remote user + * starts sending us lots of certificate in invalid messages + * leading to a DOS from unbounded certificate stack growth + */ + while (num_added-- > 0) + X509_free(sk_X509_shift(ctx->untrusted)); +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_VALIDATING_PROTECTION); + return 0; +#endif + } + } else { + /* detect explicitly permitted exceptions for missing protection */ + if (cb == NULL || (*cb)(ctx, msg, 0, cb_arg) <= 0) { + while (num_added-- > 0) + X509_free(sk_X509_shift(ctx->untrusted)); +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + ERR_raise(ERR_LIB_CMP, CMP_R_MISSING_PROTECTION); + return 0; +#endif + } + } + + /* check CMP version number in header */ + if (ossl_cmp_hdr_get_pvno(hdr) != OSSL_CMP_PVNO) { +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PVNO); + return 0; +#endif + } + + if (OSSL_CMP_MSG_get_bodytype(msg) < 0) { +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + ERR_raise(ERR_LIB_CMP, CMP_R_PKIBODY_ERROR); + return 0; +#endif + } + + /* compare received transactionID with the expected one in previous msg */ + if (ctx->transactionID != NULL + && (hdr->transactionID == NULL + || ASN1_OCTET_STRING_cmp(ctx->transactionID, + hdr->transactionID) + != 0)) { +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + ERR_raise(ERR_LIB_CMP, CMP_R_TRANSACTIONID_UNMATCHED); + return 0; +#endif + } + + /* compare received nonce with the one we sent */ + if (ctx->senderNonce != NULL + && (msg->header->recipNonce == NULL + || ASN1_OCTET_STRING_cmp(ctx->senderNonce, + hdr->recipNonce) + != 0)) { +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + ERR_raise(ERR_LIB_CMP, CMP_R_RECIPNONCE_UNMATCHED); + return 0; +#endif + } + + /* if not yet present, learn transactionID */ + if (ctx->transactionID == NULL + && !OSSL_CMP_CTX_set1_transactionID(ctx, hdr->transactionID)) + return 0; + + /* + * RFC 4210 section 5.1.1 states: the recipNonce is copied from + * the senderNonce of the previous message in the transaction. + * --> Store for setting in next message + */ + if (!ossl_cmp_ctx_set1_recipNonce(ctx, hdr->senderNonce)) + return 0; + + /* + * Store any provided extraCerts in ctx for future use, + * such that they are available to ctx->certConf_cb and + * the peer does not need to send them again in the same transaction. + * For efficiency, the extraCerts are prepended so they get used first. + */ + if (!X509_add_certs(ctx->untrusted, msg->extraCerts, + /* this allows self-signed certs */ + X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP + | X509_ADD_FLAG_PREPEND)) + return 0; + + if (ossl_cmp_hdr_get_protection_nid(hdr) == NID_id_PasswordBasedMAC) { + /* + * RFC 4210, 5.3.2: 'Note that if the PKI Message Protection is + * "shared secret information", then any certificate transported in + * the caPubs field may be directly trusted as a root CA + * certificate by the initiator.' + */ + switch (OSSL_CMP_MSG_get_bodytype(msg)) { + case OSSL_CMP_PKIBODY_IP: + case OSSL_CMP_PKIBODY_CP: + case OSSL_CMP_PKIBODY_KUP: + case OSSL_CMP_PKIBODY_CCP: + if (ctx->trusted != NULL) { + STACK_OF(X509) *certs = msg->body->value.ip->caPubs; + /* value.ip is same for cp, kup, and ccp */ + + if (!ossl_cmp_X509_STORE_add1_certs(ctx->trusted, certs, 0)) + /* adds both self-issued and not self-issued certs */ + return 0; + } + break; + default: + break; + } + } + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-63074/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-63074/vuln.c new file mode 100644 index 0000000..3b5ab24 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-63074/vuln.c @@ -0,0 +1,167 @@ +/* Provenance: openssl/openssl ossl_cmp_msg_check_update (vuln). + * repo: openssl/openssl + * commit: 9f2b8522d39ff869fac2ff7c3f20609b54843188 + * parent: 9f2b8522d39ff869fac2ff7c3f20609b54843188 + * commit_url: https://github.com/openssl/openssl/commit/21a5d9658b0c66daace60e10ea18ff32a448de9f + * cve: CVE-2026-63074 + * license: Apache-2.0 + * function: ossl_cmp_msg_check_update + * relpath: crypto/cmp/cmp_vfy.c + */ + +int ossl_cmp_msg_check_update(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg, + ossl_cmp_allow_unprotected_cb_t cb, int cb_arg) +{ + OSSL_CMP_PKIHEADER *hdr; + const X509_NAME *expected_sender; + + if (!ossl_assert(ctx != NULL && msg != NULL && msg->header != NULL)) + return 0; + hdr = OSSL_CMP_MSG_get0_header(msg); + + /* validate sender name of received msg */ + if (hdr->sender->type != GEN_DIRNAME) { + ERR_raise(ERR_LIB_CMP, CMP_R_SENDER_GENERALNAME_TYPE_NOT_SUPPORTED); + return 0; + } + /* + * Compare actual sender name of response with expected sender name. + * Mitigates risk to accept misused PBM secret + * or misused certificate of an unauthorized entity of a trusted hierarchy. + */ + expected_sender = ctx->expected_sender; + if (expected_sender == NULL && ctx->srvCert != NULL) + expected_sender = X509_get_subject_name(ctx->srvCert); + if (!check_name(ctx, 0, "sender DN field", hdr->sender->d.directoryName, + "expected sender", expected_sender)) + return 0; + /* Note: if recipient was NULL-DN it could be learned here if needed */ + + if (sk_X509_num(msg->extraCerts) > 10) + ossl_cmp_warn(ctx, + "received CMP message contains more than 10 extraCerts"); + /* + * Store any provided extraCerts in ctx for use in OSSL_CMP_validate_msg() + * and for future use, such that they are available to ctx->certConf_cb and + * the peer does not need to send them again in the same transaction. + * Note that it does not help validating the message before storing the + * extraCerts because they do not belong to the protected msg part anyway. + * For efficiency, the extraCerts are prepended so they get used first. + */ + if (!X509_add_certs(ctx->untrusted, msg->extraCerts, + /* this allows self-signed certs */ + X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP + | X509_ADD_FLAG_PREPEND)) + return 0; + + /* validate message protection */ + if (hdr->protectionAlg != NULL) { + /* detect explicitly permitted exceptions for invalid protection */ + if (!OSSL_CMP_validate_msg(ctx, msg) + && (cb == NULL || (*cb)(ctx, msg, 1, cb_arg) <= 0)) { +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_VALIDATING_PROTECTION); + return 0; +#endif + } + } else { + /* detect explicitly permitted exceptions for missing protection */ + if (cb == NULL || (*cb)(ctx, msg, 0, cb_arg) <= 0) { +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + ERR_raise(ERR_LIB_CMP, CMP_R_MISSING_PROTECTION); + return 0; +#endif + } + } + + /* check CMP version number in header */ + if (ossl_cmp_hdr_get_pvno(hdr) != OSSL_CMP_PVNO) { +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PVNO); + return 0; +#endif + } + + if (OSSL_CMP_MSG_get_bodytype(msg) < 0) { +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + ERR_raise(ERR_LIB_CMP, CMP_R_PKIBODY_ERROR); + return 0; +#endif + } + + /* compare received transactionID with the expected one in previous msg */ + if (ctx->transactionID != NULL + && (hdr->transactionID == NULL + || ASN1_OCTET_STRING_cmp(ctx->transactionID, + hdr->transactionID) + != 0)) { +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + ERR_raise(ERR_LIB_CMP, CMP_R_TRANSACTIONID_UNMATCHED); + return 0; +#endif + } + + /* compare received nonce with the one we sent */ + if (ctx->senderNonce != NULL + && (msg->header->recipNonce == NULL + || ASN1_OCTET_STRING_cmp(ctx->senderNonce, + hdr->recipNonce) + != 0)) { +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + ERR_raise(ERR_LIB_CMP, CMP_R_RECIPNONCE_UNMATCHED); + return 0; +#endif + } + + /* if not yet present, learn transactionID */ + if (ctx->transactionID == NULL + && !OSSL_CMP_CTX_set1_transactionID(ctx, hdr->transactionID)) + return 0; + + /* + * RFC 4210 section 5.1.1 states: the recipNonce is copied from + * the senderNonce of the previous message in the transaction. + * --> Store for setting in next message + */ + if (!ossl_cmp_ctx_set1_recipNonce(ctx, hdr->senderNonce)) + return 0; + + /* + * Store any provided extraCerts in ctx for future use, + * such that they are available to ctx->certConf_cb and + * the peer does not need to send them again in the same transaction. + * For efficiency, the extraCerts are prepended so they get used first. + */ + if (!X509_add_certs(ctx->untrusted, msg->extraCerts, + /* this allows self-signed certs */ + X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP + | X509_ADD_FLAG_PREPEND)) + return 0; + + if (ossl_cmp_hdr_get_protection_nid(hdr) == NID_id_PasswordBasedMAC) { + /* + * RFC 4210, 5.3.2: 'Note that if the PKI Message Protection is + * "shared secret information", then any certificate transported in + * the caPubs field may be directly trusted as a root CA + * certificate by the initiator.' + */ + switch (OSSL_CMP_MSG_get_bodytype(msg)) { + case OSSL_CMP_PKIBODY_IP: + case OSSL_CMP_PKIBODY_CP: + case OSSL_CMP_PKIBODY_KUP: + case OSSL_CMP_PKIBODY_CCP: + if (ctx->trusted != NULL) { + STACK_OF(X509) *certs = msg->body->value.ip->caPubs; + /* value.ip is same for cp, kup, and ccp */ + + if (!ossl_cmp_X509_STORE_add1_certs(ctx->trusted, certs, 0)) + /* adds both self-issued and not self-issued certs */ + return 0; + } + break; + default: + break; + } + } + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-63075-txp_pkt_commit/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-63075-txp_pkt_commit/fixed.c new file mode 100644 index 0000000..b9ecdbf --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-63075-txp_pkt_commit/fixed.c @@ -0,0 +1,189 @@ +/* Provenance: openssl/openssl txp_pkt_commit (fixed). + * repo: openssl/openssl + * commit: c902e5f16d6a9e130e96d3ca6d8f64d71652e393 + * parent: a1f348ccb328c3afbd4ba6883f9b7c813c043259 + * commit_url: https://github.com/openssl/openssl/commit/c902e5f16d6a9e130e96d3ca6d8f64d71652e393 + * cve: CVE-2026-63075 + * license: Apache-2.0 + * function: txp_pkt_commit + * relpath: ssl/quic/quic_txp.c + */ + +static int txp_pkt_commit(OSSL_QUIC_TX_PACKETISER *txp, + struct txp_pkt *pkt, + uint32_t archetype, + int *txpim_pkt_reffed) +{ + int ack_only, rc = 1; + uint32_t enc_level = pkt->h.enc_level; + uint32_t pn_space = ossl_quic_enc_level_to_pn_space(enc_level); + QUIC_TXPIM_PKT *tpkt = pkt->tpkt; + QUIC_STREAM *stream; + OSSL_QTX_PKT txpkt; + struct archetype_data a; + + *txpim_pkt_reffed = 0; + + /* Cannot send a packet with an empty payload. */ + if (pkt->h.bytes_appended == 0) + return 0; + + if (!txp_get_archetype_data(enc_level, archetype, &a)) + return 0; + + /* Packet Information for QTX */ + txpkt.hdr = &pkt->phdr; + txpkt.iovec = txp->el[enc_level].iovec; + txpkt.num_iovec = pkt->h.num_iovec; + txpkt.local = NULL; + txpkt.peer = BIO_ADDR_family(&txp->args.peer) == AF_UNSPEC + ? NULL + : &txp->args.peer; + txpkt.pn = txp->next_pn[pn_space]; + txpkt.flags = OSSL_QTX_PKT_FLAG_COALESCE; /* always try to coalesce */ + + /* Generate TXPIM chunks representing STOP_SENDING and RESET_STREAM frames. */ + for (stream = pkt->stream_head; stream != NULL; stream = stream->txp_next) + if (stream->txp_sent_stop_sending || stream->txp_sent_reset_stream) { + /* Log STOP_SENDING/RESET_STREAM chunk to TXPIM. */ + QUIC_TXPIM_CHUNK chunk; + + chunk.stream_id = stream->id; + chunk.start = UINT64_MAX; + chunk.end = 0; + chunk.has_fin = 0; + chunk.has_stop_sending = stream->txp_sent_stop_sending; + chunk.has_reset_stream = stream->txp_sent_reset_stream; + if (!ossl_quic_txpim_pkt_append_chunk(tpkt, &chunk)) + return 0; /* alloc error */ + } + + ack_only = txp_pkt_is_ack_only(tpkt); + + /* Dispatch packets that need loss/retransmit callbacks to FIFD. */ + if (!ack_only && !ossl_quic_fifd_pkt_commit(&txp->fifd, tpkt)) + return 0; + + /* + * Transmission and Post-Packet Generation Bookkeeping + * =================================================== + * + * No backing out anymore - at this point we need to increment our next PN + * counter, or the ACKM will complain when we try to record a duplicate + * packet with the same PN later. Non-ACK-only packets have also been + * recorded in ACKM, so if QTX write fails they are handled as though they + * were lost. ACK-only packets are not recorded and will be cleaned up by + * the caller. + */ + ++txp->next_pn[pn_space]; + if (!ack_only) + *txpim_pkt_reffed = 1; + + /* Send the packet. */ + if (!ossl_qtx_write_pkt(txp->args.qtx, &txpkt)) + return 0; + + if (ack_only + && !ossl_ackm_on_tx_ack_only_packet(txp->args.ackm, &tpkt->ackm_pkt)) + rc = 0; + + /* + * Record FC and stream abort frames as sent; deactivate streams which no + * longer have anything to do. + */ + for (stream = pkt->stream_head; stream != NULL; stream = stream->txp_next) { + if (stream->txp_sent_fc) { + stream->want_max_stream_data = 0; + ossl_quic_rxfc_has_cwm_changed(&stream->rxfc, 1); + } + + if (stream->txp_sent_stop_sending) + stream->want_stop_sending = 0; + + if (stream->txp_sent_reset_stream) + stream->want_reset_stream = 0; + + if (stream->txp_txfc_new_credit_consumed > 0) { + if (!ossl_assert(ossl_quic_txfc_consume_credit(&stream->txfc, + stream->txp_txfc_new_credit_consumed))) + /* + * Should not be possible, but we should continue with our + * bookkeeping as we have already committed the packet to the + * FIFD. Just change the value we return. + */ + rc = 0; + + stream->txp_txfc_new_credit_consumed = 0; + } + + /* + * If we no longer need to generate any flow control (MAX_STREAM_DATA), + * STOP_SENDING or RESET_STREAM frames, nor any STREAM frames (because + * the stream is drained of data or TXFC-blocked), we can mark the + * stream as inactive. + */ + ossl_quic_stream_map_update_state(txp->args.qsm, stream); + + if (ossl_quic_stream_has_send_buffer(stream) + && !ossl_quic_sstream_has_pending(stream->sstream) + && ossl_quic_sstream_get_final_size(stream->sstream, NULL)) + /* + * Transition to DATA_SENT if stream has a final size and we have + * sent all data. + */ + ossl_quic_stream_map_notify_all_data_sent(txp->args.qsm, stream); + } + + /* We have now sent the packet, so update state accordingly. */ + if (tpkt->ackm_pkt.is_ack_eliciting) + txp->force_ack_eliciting &= ~(1UL << pn_space); + + if (tpkt->had_handshake_done_frame) + txp->want_handshake_done = 0; + + if (tpkt->had_max_data_frame) { + txp->want_max_data = 0; + ossl_quic_rxfc_has_cwm_changed(txp->args.conn_rxfc, 1); + } + + if (tpkt->had_max_streams_bidi_frame) { + txp->want_max_streams_bidi = 0; + ossl_quic_rxfc_has_cwm_changed(txp->args.max_streams_bidi_rxfc, 1); + } + + if (tpkt->had_max_streams_uni_frame) { + txp->want_max_streams_uni = 0; + ossl_quic_rxfc_has_cwm_changed(txp->args.max_streams_uni_rxfc, 1); + } + + if (tpkt->had_ack_frame) + txp->want_ack &= ~(1UL << pn_space); + + if (tpkt->had_conn_close) + txp->want_conn_close = 0; + + /* + * Decrement probe request counts if we have sent a packet that meets + * the requirement of a probe, namely being ACK-eliciting. + */ + if (tpkt->ackm_pkt.is_ack_eliciting) { + OSSL_ACKM_PROBE_INFO *probe_info + = ossl_ackm_get0_probe_request(txp->args.ackm); + + if (enc_level == QUIC_ENC_LEVEL_INITIAL + && probe_info->anti_deadlock_initial > 0) + --probe_info->anti_deadlock_initial; + + if (enc_level == QUIC_ENC_LEVEL_HANDSHAKE + && probe_info->anti_deadlock_handshake > 0) + --probe_info->anti_deadlock_handshake; + + if (a.allow_force_ack_eliciting /* (i.e., not for 0-RTT) */ + && probe_info->pto[pn_space] > 0) + --probe_info->pto[pn_space]; + } + + ossl_quic_fifd_pkt_discard_unreliable(&txp->fifd, tpkt); + + return rc; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-63075-txp_pkt_commit/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-63075-txp_pkt_commit/vuln.c new file mode 100644 index 0000000..e33cab8 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-63075-txp_pkt_commit/vuln.c @@ -0,0 +1,182 @@ +/* Provenance: openssl/openssl txp_pkt_commit (vuln). + * repo: openssl/openssl + * commit: a1f348ccb328c3afbd4ba6883f9b7c813c043259 + * parent: a1f348ccb328c3afbd4ba6883f9b7c813c043259 + * commit_url: https://github.com/openssl/openssl/commit/c902e5f16d6a9e130e96d3ca6d8f64d71652e393 + * cve: CVE-2026-63075 + * license: Apache-2.0 + * function: txp_pkt_commit + * relpath: ssl/quic/quic_txp.c + */ + +static int txp_pkt_commit(OSSL_QUIC_TX_PACKETISER *txp, + struct txp_pkt *pkt, + uint32_t archetype, + int *txpim_pkt_reffed) +{ + int rc = 1; + uint32_t enc_level = pkt->h.enc_level; + uint32_t pn_space = ossl_quic_enc_level_to_pn_space(enc_level); + QUIC_TXPIM_PKT *tpkt = pkt->tpkt; + QUIC_STREAM *stream; + OSSL_QTX_PKT txpkt; + struct archetype_data a; + + *txpim_pkt_reffed = 0; + + /* Cannot send a packet with an empty payload. */ + if (pkt->h.bytes_appended == 0) + return 0; + + if (!txp_get_archetype_data(enc_level, archetype, &a)) + return 0; + + /* Packet Information for QTX */ + txpkt.hdr = &pkt->phdr; + txpkt.iovec = txp->el[enc_level].iovec; + txpkt.num_iovec = pkt->h.num_iovec; + txpkt.local = NULL; + txpkt.peer = BIO_ADDR_family(&txp->args.peer) == AF_UNSPEC + ? NULL + : &txp->args.peer; + txpkt.pn = txp->next_pn[pn_space]; + txpkt.flags = OSSL_QTX_PKT_FLAG_COALESCE; /* always try to coalesce */ + + /* Generate TXPIM chunks representing STOP_SENDING and RESET_STREAM frames. */ + for (stream = pkt->stream_head; stream != NULL; stream = stream->txp_next) + if (stream->txp_sent_stop_sending || stream->txp_sent_reset_stream) { + /* Log STOP_SENDING/RESET_STREAM chunk to TXPIM. */ + QUIC_TXPIM_CHUNK chunk; + + chunk.stream_id = stream->id; + chunk.start = UINT64_MAX; + chunk.end = 0; + chunk.has_fin = 0; + chunk.has_stop_sending = stream->txp_sent_stop_sending; + chunk.has_reset_stream = stream->txp_sent_reset_stream; + if (!ossl_quic_txpim_pkt_append_chunk(tpkt, &chunk)) + return 0; /* alloc error */ + } + + /* Dispatch to FIFD. */ + if (!ossl_quic_fifd_pkt_commit(&txp->fifd, tpkt)) + return 0; + + /* + * Transmission and Post-Packet Generation Bookkeeping + * =================================================== + * + * No backing out anymore - at this point the ACKM has recorded the packet + * as having been sent, so we need to increment our next PN counter, or + * the ACKM will complain when we try to record a duplicate packet with + * the same PN later. At this point actually sending the packet may still + * fail. In this unlikely event it will simply be handled as though it + * were a lost packet. + */ + ++txp->next_pn[pn_space]; + *txpim_pkt_reffed = 1; + + /* Send the packet. */ + if (!ossl_qtx_write_pkt(txp->args.qtx, &txpkt)) + return 0; + + /* + * Record FC and stream abort frames as sent; deactivate streams which no + * longer have anything to do. + */ + for (stream = pkt->stream_head; stream != NULL; stream = stream->txp_next) { + if (stream->txp_sent_fc) { + stream->want_max_stream_data = 0; + ossl_quic_rxfc_has_cwm_changed(&stream->rxfc, 1); + } + + if (stream->txp_sent_stop_sending) + stream->want_stop_sending = 0; + + if (stream->txp_sent_reset_stream) + stream->want_reset_stream = 0; + + if (stream->txp_txfc_new_credit_consumed > 0) { + if (!ossl_assert(ossl_quic_txfc_consume_credit(&stream->txfc, + stream->txp_txfc_new_credit_consumed))) + /* + * Should not be possible, but we should continue with our + * bookkeeping as we have already committed the packet to the + * FIFD. Just change the value we return. + */ + rc = 0; + + stream->txp_txfc_new_credit_consumed = 0; + } + + /* + * If we no longer need to generate any flow control (MAX_STREAM_DATA), + * STOP_SENDING or RESET_STREAM frames, nor any STREAM frames (because + * the stream is drained of data or TXFC-blocked), we can mark the + * stream as inactive. + */ + ossl_quic_stream_map_update_state(txp->args.qsm, stream); + + if (ossl_quic_stream_has_send_buffer(stream) + && !ossl_quic_sstream_has_pending(stream->sstream) + && ossl_quic_sstream_get_final_size(stream->sstream, NULL)) + /* + * Transition to DATA_SENT if stream has a final size and we have + * sent all data. + */ + ossl_quic_stream_map_notify_all_data_sent(txp->args.qsm, stream); + } + + /* We have now sent the packet, so update state accordingly. */ + if (tpkt->ackm_pkt.is_ack_eliciting) + txp->force_ack_eliciting &= ~(1UL << pn_space); + + if (tpkt->had_handshake_done_frame) + txp->want_handshake_done = 0; + + if (tpkt->had_max_data_frame) { + txp->want_max_data = 0; + ossl_quic_rxfc_has_cwm_changed(txp->args.conn_rxfc, 1); + } + + if (tpkt->had_max_streams_bidi_frame) { + txp->want_max_streams_bidi = 0; + ossl_quic_rxfc_has_cwm_changed(txp->args.max_streams_bidi_rxfc, 1); + } + + if (tpkt->had_max_streams_uni_frame) { + txp->want_max_streams_uni = 0; + ossl_quic_rxfc_has_cwm_changed(txp->args.max_streams_uni_rxfc, 1); + } + + if (tpkt->had_ack_frame) + txp->want_ack &= ~(1UL << pn_space); + + if (tpkt->had_conn_close) + txp->want_conn_close = 0; + + /* + * Decrement probe request counts if we have sent a packet that meets + * the requirement of a probe, namely being ACK-eliciting. + */ + if (tpkt->ackm_pkt.is_ack_eliciting) { + OSSL_ACKM_PROBE_INFO *probe_info + = ossl_ackm_get0_probe_request(txp->args.ackm); + + if (enc_level == QUIC_ENC_LEVEL_INITIAL + && probe_info->anti_deadlock_initial > 0) + --probe_info->anti_deadlock_initial; + + if (enc_level == QUIC_ENC_LEVEL_HANDSHAKE + && probe_info->anti_deadlock_handshake > 0) + --probe_info->anti_deadlock_handshake; + + if (a.allow_force_ack_eliciting /* (i.e., not for 0-RTT) */ + && probe_info->pto[pn_space] > 0) + --probe_info->pto[pn_space]; + } + + ossl_quic_fifd_pkt_discard_unreliable(&txp->fifd, tpkt); + + return rc; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-7383/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-7383/fixed.c new file mode 100644 index 0000000..465501a --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-7383/fixed.c @@ -0,0 +1,207 @@ +/* Provenance: openssl/openssl ASN1_mbstring_ncopy (fixed). + * repo: openssl/openssl + * commit: 97f6b621f7af2c4c4e162c75045a6e12a8fdf8d9 + * parent: cb005ceaaf1fb50722e0101762a3e266338c5bf9 + * commit_url: https://github.com/openssl/openssl/commit/97f6b621f7af2c4c4e162c75045a6e12a8fdf8d9 + * cve: CVE-2026-7383 + * license: Apache-2.0 + * function: ASN1_mbstring_ncopy + * relpath: crypto/asn1/a_mbstr.c + */ + +int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len, + int inform, unsigned long mask_in, + long minsize, long maxsize) +{ + int str_type; + int ret; + char free_out; + int outform, outlen = 0; + ASN1_STRING *dest; + unsigned char *p; + int nchar; + uint32_t mask = (uint32_t)mask_in; + int (*cpyfunc)(uint32_t, void *) = NULL; + if (len == -1) { + size_t len_s = strlen((const char *)in); + + if (len_s >= INT_MAX) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_STRING_TOO_LONG); + return -1; + } + len = (int)len_s; + } + if (!mask) + mask = DIRSTRING_TYPE; + if (len < 0) { + ERR_raise(ERR_LIB_ASN1, ERR_R_PASSED_INVALID_ARGUMENT); + return -1; + } + + /* First do a string check and work out the number of characters */ + switch (inform) { + + case MBSTRING_BMP: + if (len & 1) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_INVALID_BMPSTRING_LENGTH); + return -1; + } + nchar = len >> 1; + break; + + case MBSTRING_UNIV: + if (len & 3) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_INVALID_UNIVERSALSTRING_LENGTH); + return -1; + } + nchar = len >> 2; + break; + + case MBSTRING_UTF8: + nchar = 0; + /* This counts the characters and does utf8 syntax checking */ + ret = traverse_string(in, len, MBSTRING_UTF8, in_utf8, &nchar); + if (ret < 0) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_INVALID_UTF8STRING); + return -1; + } + break; + + case MBSTRING_ASC: + nchar = len; + break; + + default: + ERR_raise(ERR_LIB_ASN1, ASN1_R_UNKNOWN_FORMAT); + return -1; + } + + if ((minsize > 0) && (nchar < minsize)) { + ERR_raise_data(ERR_LIB_ASN1, ASN1_R_STRING_TOO_SHORT, + "minsize=%ld", minsize); + return -1; + } + + if ((maxsize > 0) && (nchar > maxsize)) { + ERR_raise_data(ERR_LIB_ASN1, ASN1_R_STRING_TOO_LONG, + "maxsize=%ld", maxsize); + return -1; + } + + /* Now work out minimal type (if any) */ + if (traverse_string(in, len, inform, type_str, &mask) < 0) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_CHARACTERS); + return -1; + } + + /* + * Now work out output format and string type. + * These checks should be in sync with the checks in type_str. + */ + outform = MBSTRING_ASC; + if (mask & B_ASN1_NUMERICSTRING) + str_type = V_ASN1_NUMERICSTRING; + else if (mask & B_ASN1_PRINTABLESTRING) + str_type = V_ASN1_PRINTABLESTRING; + else if (mask & B_ASN1_IA5STRING) + str_type = V_ASN1_IA5STRING; + else if (mask & B_ASN1_T61STRING) + str_type = V_ASN1_T61STRING; + else if (mask & B_ASN1_BMPSTRING) { + str_type = V_ASN1_BMPSTRING; + outform = MBSTRING_BMP; + } else if (mask & B_ASN1_UNIVERSALSTRING) { + str_type = V_ASN1_UNIVERSALSTRING; + outform = MBSTRING_UNIV; + } else { + str_type = V_ASN1_UTF8STRING; + outform = MBSTRING_UTF8; + } + if (!out) + return str_type; + if (*out) { + free_out = 0; + dest = *out; + ASN1_STRING_set0(dest, NULL, 0); + dest->type = str_type; + } else { + free_out = 1; + dest = ASN1_STRING_type_new(str_type); + if (dest == NULL) { + ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB); + return -1; + } + *out = dest; + } + /* If both the same type just copy across */ + if (inform == outform) { + if (!ASN1_STRING_set(dest, in, len)) { + if (free_out) { + ASN1_STRING_free(dest); + *out = NULL; + } + ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB); + return -1; + } + return str_type; + } + + /* Work out how much space the destination will need */ + switch (outform) { + case MBSTRING_ASC: + outlen = nchar; + cpyfunc = cpy_asc; + break; + + case MBSTRING_BMP: + if (nchar > INT_MAX / 2) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_STRING_TOO_LONG); + if (free_out) { + ASN1_STRING_free(dest); + *out = NULL; + } + return -1; + } + outlen = nchar << 1; + cpyfunc = cpy_bmp; + break; + + case MBSTRING_UNIV: + if (nchar > INT_MAX / 4) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_STRING_TOO_LONG); + if (free_out) { + ASN1_STRING_free(dest); + *out = NULL; + } + return -1; + } + outlen = nchar << 2; + cpyfunc = cpy_univ; + break; + + case MBSTRING_UTF8: + outlen = 0; + ret = traverse_string(in, len, inform, out_utf8, &outlen); + if (ret < 0) { /* error already raised in out_utf8() */ + if (free_out) { + ASN1_STRING_free(dest); + *out = NULL; + } + return -1; + } + cpyfunc = cpy_utf8; + break; + } + if ((p = OPENSSL_malloc(outlen + 1)) == NULL) { + if (free_out) { + ASN1_STRING_free(dest); + *out = NULL; + } + return -1; + } + dest->length = outlen; + dest->data = p; + p[outlen] = 0; + traverse_string(in, len, inform, cpyfunc, &p); + return str_type; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-7383/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-7383/vuln.c new file mode 100644 index 0000000..9cc8e11 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-7383/vuln.c @@ -0,0 +1,188 @@ +/* Provenance: openssl/openssl ASN1_mbstring_ncopy (vuln). + * repo: openssl/openssl + * commit: cb005ceaaf1fb50722e0101762a3e266338c5bf9 + * parent: cb005ceaaf1fb50722e0101762a3e266338c5bf9 + * commit_url: https://github.com/openssl/openssl/commit/97f6b621f7af2c4c4e162c75045a6e12a8fdf8d9 + * cve: CVE-2026-7383 + * license: Apache-2.0 + * function: ASN1_mbstring_ncopy + * relpath: crypto/asn1/a_mbstr.c + */ + +int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len, + int inform, unsigned long mask_in, + long minsize, long maxsize) +{ + int str_type; + int ret; + char free_out; + int outform, outlen = 0; + ASN1_STRING *dest; + unsigned char *p; + int nchar; + uint32_t mask = (uint32_t)mask_in; + int (*cpyfunc)(uint32_t, void *) = NULL; + if (len == -1) { + size_t len_s = strlen((const char *)in); + + if (len_s >= INT_MAX) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_STRING_TOO_LONG); + return -1; + } + len = (int)len_s; + } + if (!mask) + mask = DIRSTRING_TYPE; + if (len < 0) { + ERR_raise(ERR_LIB_ASN1, ERR_R_PASSED_INVALID_ARGUMENT); + return -1; + } + + /* First do a string check and work out the number of characters */ + switch (inform) { + + case MBSTRING_BMP: + if (len & 1) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_INVALID_BMPSTRING_LENGTH); + return -1; + } + nchar = len >> 1; + break; + + case MBSTRING_UNIV: + if (len & 3) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_INVALID_UNIVERSALSTRING_LENGTH); + return -1; + } + nchar = len >> 2; + break; + + case MBSTRING_UTF8: + nchar = 0; + /* This counts the characters and does utf8 syntax checking */ + ret = traverse_string(in, len, MBSTRING_UTF8, in_utf8, &nchar); + if (ret < 0) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_INVALID_UTF8STRING); + return -1; + } + break; + + case MBSTRING_ASC: + nchar = len; + break; + + default: + ERR_raise(ERR_LIB_ASN1, ASN1_R_UNKNOWN_FORMAT); + return -1; + } + + if ((minsize > 0) && (nchar < minsize)) { + ERR_raise_data(ERR_LIB_ASN1, ASN1_R_STRING_TOO_SHORT, + "minsize=%ld", minsize); + return -1; + } + + if ((maxsize > 0) && (nchar > maxsize)) { + ERR_raise_data(ERR_LIB_ASN1, ASN1_R_STRING_TOO_LONG, + "maxsize=%ld", maxsize); + return -1; + } + + /* Now work out minimal type (if any) */ + if (traverse_string(in, len, inform, type_str, &mask) < 0) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_CHARACTERS); + return -1; + } + + /* + * Now work out output format and string type. + * These checks should be in sync with the checks in type_str. + */ + outform = MBSTRING_ASC; + if (mask & B_ASN1_NUMERICSTRING) + str_type = V_ASN1_NUMERICSTRING; + else if (mask & B_ASN1_PRINTABLESTRING) + str_type = V_ASN1_PRINTABLESTRING; + else if (mask & B_ASN1_IA5STRING) + str_type = V_ASN1_IA5STRING; + else if (mask & B_ASN1_T61STRING) + str_type = V_ASN1_T61STRING; + else if (mask & B_ASN1_BMPSTRING) { + str_type = V_ASN1_BMPSTRING; + outform = MBSTRING_BMP; + } else if (mask & B_ASN1_UNIVERSALSTRING) { + str_type = V_ASN1_UNIVERSALSTRING; + outform = MBSTRING_UNIV; + } else { + str_type = V_ASN1_UTF8STRING; + outform = MBSTRING_UTF8; + } + if (!out) + return str_type; + if (*out) { + free_out = 0; + dest = *out; + ASN1_STRING_set0(dest, NULL, 0); + dest->type = str_type; + } else { + free_out = 1; + dest = ASN1_STRING_type_new(str_type); + if (dest == NULL) { + ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB); + return -1; + } + *out = dest; + } + /* If both the same type just copy across */ + if (inform == outform) { + if (!ASN1_STRING_set(dest, in, len)) { + if (free_out) { + ASN1_STRING_free(dest); + *out = NULL; + } + ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB); + return -1; + } + return str_type; + } + + /* Work out how much space the destination will need */ + switch (outform) { + case MBSTRING_ASC: + outlen = nchar; + cpyfunc = cpy_asc; + break; + + case MBSTRING_BMP: + outlen = nchar << 1; + cpyfunc = cpy_bmp; + break; + + case MBSTRING_UNIV: + outlen = nchar << 2; + cpyfunc = cpy_univ; + break; + + case MBSTRING_UTF8: + outlen = 0; + ret = traverse_string(in, len, inform, out_utf8, &outlen); + if (ret < 0) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_INVALID_UTF8STRING); + return -1; + } + cpyfunc = cpy_utf8; + break; + } + if ((p = OPENSSL_malloc(outlen + 1)) == NULL) { + if (free_out) { + ASN1_STRING_free(dest); + *out = NULL; + } + return -1; + } + dest->length = outlen; + dest->data = p; + p[outlen] = 0; + traverse_string(in, len, inform, cpyfunc, &p); + return str_type; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-75803-aes_gcm_siv_finish/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-75803-aes_gcm_siv_finish/fixed.c new file mode 100644 index 0000000..4b831da --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-75803-aes_gcm_siv_finish/fixed.c @@ -0,0 +1,29 @@ +/* Provenance: openssl/openssl aes_gcm_siv_finish (fixed). + * repo: openssl/openssl + * commit: bf95f5f772e9362f87b25cfa2f8cb15d984865b9 + * parent: de7d1871087fc1fa3e2c1db4b11275b68d72f416 + * commit_url: https://github.com/openssl/openssl/commit/bf95f5f772e9362f87b25cfa2f8cb15d984865b9 + * cve: CVE-2026-75803 + * license: Apache-2.0 + * function: aes_gcm_siv_finish + * relpath: providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c + */ + +static int aes_gcm_siv_finish(PROV_AES_GCM_SIV_CTX *ctx) +{ + int ret = 0; + + if (ctx->enc) { + /* Generate the tag when Final is the first empty-message operation. */ + if (ctx->generated_tag == 0 + && aes_gcm_siv_encrypt(ctx, NULL, NULL, 0) == 0) + return 0; + return ctx->generated_tag; + } + if (ctx->generated_tag == 0 + && aes_gcm_siv_decrypt(ctx, NULL, NULL, 0) == 0) + return 0; + ret = CRYPTO_memcmp(ctx->tag, ctx->user_tag, sizeof(ctx->tag)) == 0; + ret &= ctx->have_user_tag; + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-75803-aes_gcm_siv_finish/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-75803-aes_gcm_siv_finish/vuln.c new file mode 100644 index 0000000..af69e33 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-75803-aes_gcm_siv_finish/vuln.c @@ -0,0 +1,23 @@ +/* Provenance: openssl/openssl aes_gcm_siv_finish (vuln). + * repo: openssl/openssl + * commit: de7d1871087fc1fa3e2c1db4b11275b68d72f416 + * parent: de7d1871087fc1fa3e2c1db4b11275b68d72f416 + * commit_url: https://github.com/openssl/openssl/commit/bf95f5f772e9362f87b25cfa2f8cb15d984865b9 + * cve: CVE-2026-75803 + * license: Apache-2.0 + * function: aes_gcm_siv_finish + * relpath: providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c + */ + +static int aes_gcm_siv_finish(PROV_AES_GCM_SIV_CTX *ctx) +{ + int ret = 0; + + if (ctx->enc) + return ctx->generated_tag; + if (!ctx->generated_tag) + aes_gcm_siv_decrypt(ctx, NULL, NULL, 0); + ret = !CRYPTO_memcmp(ctx->tag, ctx->user_tag, sizeof(ctx->tag)); + ret &= ctx->have_user_tag; + return ret; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-75803-chacha20_poly1305_cipher/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-75803-chacha20_poly1305_cipher/fixed.c new file mode 100644 index 0000000..405176b --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-75803-chacha20_poly1305_cipher/fixed.c @@ -0,0 +1,31 @@ +/* Provenance: openssl/openssl chacha20_poly1305_cipher (fixed). + * repo: openssl/openssl + * commit: 119ab9555dc62275bbd71f6f49529b1a44feba42 + * parent: 39488cb863074d5b8ece833905f7ad2b357d44fe + * commit_url: https://github.com/openssl/openssl/commit/119ab9555dc62275bbd71f6f49529b1a44feba42 + * cve: CVE-2026-75803 + * license: Apache-2.0 + * function: chacha20_poly1305_cipher + * relpath: providers/implementations/ciphers/cipher_chacha20_poly1305.c + */ + +static int chacha20_poly1305_cipher(void *vctx, unsigned char *out, + size_t *outl, size_t outsize, + const unsigned char *in, size_t inl) +{ + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + PROV_CIPHER_HW_CHACHA20_POLY1305 *hw = (PROV_CIPHER_HW_CHACHA20_POLY1305 *)ctx->hw; + + if (!ossl_prov_is_running()) + return 0; + + if (outsize < inl) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + if (!hw->aead_cipher(ctx, out, outl, in, inl)) + return 0; + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-75803-chacha20_poly1305_cipher/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-75803-chacha20_poly1305_cipher/vuln.c new file mode 100644 index 0000000..9c0dc8a --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-75803-chacha20_poly1305_cipher/vuln.c @@ -0,0 +1,36 @@ +/* Provenance: openssl/openssl chacha20_poly1305_cipher (vuln). + * repo: openssl/openssl + * commit: 39488cb863074d5b8ece833905f7ad2b357d44fe + * parent: 39488cb863074d5b8ece833905f7ad2b357d44fe + * commit_url: https://github.com/openssl/openssl/commit/119ab9555dc62275bbd71f6f49529b1a44feba42 + * cve: CVE-2026-75803 + * license: Apache-2.0 + * function: chacha20_poly1305_cipher + * relpath: providers/implementations/ciphers/cipher_chacha20_poly1305.c + */ + +static int chacha20_poly1305_cipher(void *vctx, unsigned char *out, + size_t *outl, size_t outsize, + const unsigned char *in, size_t inl) +{ + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + PROV_CIPHER_HW_CHACHA20_POLY1305 *hw = (PROV_CIPHER_HW_CHACHA20_POLY1305 *)ctx->hw; + + if (!ossl_prov_is_running()) + return 0; + + if (inl == 0) { + *outl = 0; + return 1; + } + + if (outsize < inl) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + if (!hw->aead_cipher(ctx, out, outl, in, inl)) + return 0; + + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-75803/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-75803/fixed.c new file mode 100644 index 0000000..e211a34 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-75803/fixed.c @@ -0,0 +1,49 @@ +/* Provenance: openssl/openssl aes_ocb_cipher (fixed). + * repo: openssl/openssl + * commit: 119ab9555dc62275bbd71f6f49529b1a44feba42 + * parent: 39488cb863074d5b8ece833905f7ad2b357d44fe + * commit_url: https://github.com/openssl/openssl/commit/119ab9555dc62275bbd71f6f49529b1a44feba42 + * cve: CVE-2026-75803 + * license: Apache-2.0 + * function: aes_ocb_cipher + * relpath: providers/implementations/ciphers/cipher_aes_ocb.c + */ + +static int aes_ocb_cipher(void *vctx, unsigned char *out, size_t *outl, + size_t outsize, const unsigned char *in, size_t inl) +{ + PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx; + + if (!ossl_prov_is_running()) + return 0; + + /* NULL input indicates Final, which must generate or check the tag. */ + if (in == NULL) + return aes_ocb_block_final(vctx, out, outl, outsize); + + if (outsize < inl) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + /* + * Mirror the streaming handler: refuse if the key has not been set, + * and push the buffered IV into the OCB context before any data is + * processed. Without this, CRYPTO_ocb128_encrypt/decrypt runs with + * Offset_0 = 0 regardless of the caller's IV -- catastrophic + * (key, nonce) reuse, and a subsequent EVP_*Final_ex() emits a tag + * that is a function of (key, iv) only. + */ + if (!ctx->key_set || !update_iv(ctx)) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + + if (!aes_generic_ocb_cipher(ctx, in, out, inl)) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + + *outl = inl; + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-75803/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-75803/vuln.c new file mode 100644 index 0000000..68eac88 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-75803/vuln.c @@ -0,0 +1,45 @@ +/* Provenance: openssl/openssl aes_ocb_cipher (vuln). + * repo: openssl/openssl + * commit: 39488cb863074d5b8ece833905f7ad2b357d44fe + * parent: 39488cb863074d5b8ece833905f7ad2b357d44fe + * commit_url: https://github.com/openssl/openssl/commit/119ab9555dc62275bbd71f6f49529b1a44feba42 + * cve: CVE-2026-75803 + * license: Apache-2.0 + * function: aes_ocb_cipher + * relpath: providers/implementations/ciphers/cipher_aes_ocb.c + */ + +static int aes_ocb_cipher(void *vctx, unsigned char *out, size_t *outl, + size_t outsize, const unsigned char *in, size_t inl) +{ + PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx; + + if (!ossl_prov_is_running()) + return 0; + + if (outsize < inl) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + /* + * Mirror the streaming handler: refuse if the key has not been set, + * and push the buffered IV into the OCB context before any data is + * processed. Without this, CRYPTO_ocb128_encrypt/decrypt runs with + * Offset_0 = 0 regardless of the caller's IV -- catastrophic + * (key, nonce) reuse, and a subsequent EVP_*Final_ex() emits a tag + * that is a function of (key, iv) only. + */ + if (!ctx->key_set || !update_iv(ctx)) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + + if (!aes_generic_ocb_cipher(ctx, in, out, inl)) { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return 0; + } + + *outl = inl; + return 1; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-9076/fixed.c b/benchmarks/pairs/vfc/openssl-cve-2026-9076/fixed.c new file mode 100644 index 0000000..47d59e1 --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-9076/fixed.c @@ -0,0 +1,66 @@ +/* Provenance: openssl/openssl kek_unwrap_key (fixed). + * repo: openssl/openssl + * commit: 51d1800e95283a8beec85152e35e3634dab8dd82 + * parent: 97f6b621f7af2c4c4e162c75045a6e12a8fdf8d9 + * commit_url: https://github.com/openssl/openssl/commit/51d1800e95283a8beec85152e35e3634dab8dd82 + * cve: CVE-2026-9076 + * license: Apache-2.0 + * function: kek_unwrap_key + * relpath: crypto/cms/cms_pwri.c + */ + +static int kek_unwrap_key(unsigned char *out, size_t *outlen, + const unsigned char *in, size_t inlen, + EVP_CIPHER_CTX *ctx) +{ + int blocklen = EVP_CIPHER_CTX_get_block_size(ctx); + unsigned char *tmp; + int outl, rv = 0; + + if (blocklen < 4) + return 0; + + if (inlen < 2 * (size_t)blocklen) { + /* too small */ + return 0; + } + if (inlen > INT_MAX || inlen % blocklen) { + /* Invalid size */ + return 0; + } + if ((tmp = OPENSSL_malloc(inlen)) == NULL) + return 0; + /* setup IV by decrypting last two blocks */ + if (!EVP_DecryptUpdate(ctx, tmp + inlen - 2 * blocklen, &outl, + in + inlen - 2 * blocklen, blocklen * 2) + /* + * Do a decrypt of last decrypted block to set IV to correct value + * output it to start of buffer so we don't corrupt decrypted block + * this works because buffer is at least two block lengths long. + */ + || !EVP_DecryptUpdate(ctx, tmp, &outl, + tmp + inlen - blocklen, blocklen) + /* Can now decrypt first n - 1 blocks */ + || !EVP_DecryptUpdate(ctx, tmp, &outl, in, (int)(inlen - blocklen)) + + /* Reset IV to original value */ + || !EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, NULL) + /* Decrypt again */ + || !EVP_DecryptUpdate(ctx, tmp, &outl, tmp, (int)inlen)) + goto err; + /* Check check bytes */ + if (((tmp[1] ^ tmp[4]) & (tmp[2] ^ tmp[5]) & (tmp[3] ^ tmp[6])) != 0xff) { + /* Check byte failure */ + goto err; + } + if (inlen < 4 + (size_t)tmp[0]) { + /* Invalid length value */ + goto err; + } + *outlen = (size_t)tmp[0]; + memcpy(out, tmp + 4, *outlen); + rv = 1; +err: + OPENSSL_clear_free(tmp, inlen); + return rv; +} diff --git a/benchmarks/pairs/vfc/openssl-cve-2026-9076/vuln.c b/benchmarks/pairs/vfc/openssl-cve-2026-9076/vuln.c new file mode 100644 index 0000000..6b5d2ba --- /dev/null +++ b/benchmarks/pairs/vfc/openssl-cve-2026-9076/vuln.c @@ -0,0 +1,66 @@ +/* Provenance: openssl/openssl kek_unwrap_key (vuln). + * repo: openssl/openssl + * commit: 97f6b621f7af2c4c4e162c75045a6e12a8fdf8d9 + * parent: 97f6b621f7af2c4c4e162c75045a6e12a8fdf8d9 + * commit_url: https://github.com/openssl/openssl/commit/51d1800e95283a8beec85152e35e3634dab8dd82 + * cve: CVE-2026-9076 + * license: Apache-2.0 + * function: kek_unwrap_key + * relpath: crypto/cms/cms_pwri.c + */ + +static int kek_unwrap_key(unsigned char *out, size_t *outlen, + const unsigned char *in, size_t inlen, + EVP_CIPHER_CTX *ctx) +{ + int blocklen = EVP_CIPHER_CTX_get_block_size(ctx); + unsigned char *tmp; + int outl, rv = 0; + + if (blocklen <= 0) + return 0; + + if (inlen < 2 * (size_t)blocklen) { + /* too small */ + return 0; + } + if (inlen > INT_MAX || inlen % blocklen) { + /* Invalid size */ + return 0; + } + if ((tmp = OPENSSL_malloc(inlen)) == NULL) + return 0; + /* setup IV by decrypting last two blocks */ + if (!EVP_DecryptUpdate(ctx, tmp + inlen - 2 * blocklen, &outl, + in + inlen - 2 * blocklen, blocklen * 2) + /* + * Do a decrypt of last decrypted block to set IV to correct value + * output it to start of buffer so we don't corrupt decrypted block + * this works because buffer is at least two block lengths long. + */ + || !EVP_DecryptUpdate(ctx, tmp, &outl, + tmp + inlen - blocklen, blocklen) + /* Can now decrypt first n - 1 blocks */ + || !EVP_DecryptUpdate(ctx, tmp, &outl, in, (int)(inlen - blocklen)) + + /* Reset IV to original value */ + || !EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, NULL) + /* Decrypt again */ + || !EVP_DecryptUpdate(ctx, tmp, &outl, tmp, (int)inlen)) + goto err; + /* Check check bytes */ + if (((tmp[1] ^ tmp[4]) & (tmp[2] ^ tmp[5]) & (tmp[3] ^ tmp[6])) != 0xff) { + /* Check byte failure */ + goto err; + } + if (inlen < 4 + (size_t)tmp[0]) { + /* Invalid length value */ + goto err; + } + *outlen = (size_t)tmp[0]; + memcpy(out, tmp + 4, *outlen); + rv = 1; +err: + OPENSSL_clear_free(tmp, inlen); + return rv; +} diff --git a/benchmarks/pairs/vfc/recipes.toml b/benchmarks/pairs/vfc/recipes.toml new file mode 100644 index 0000000..55afee6 --- /dev/null +++ b/benchmarks/pairs/vfc/recipes.toml @@ -0,0 +1,3705 @@ +# Maintainer harvest recipes. CI does not fetch these. +# A recipe without parent+commit is advisory-only and must be rejected. +# year/cwe/class/sink/evidence drive catalog.toml and training/manifest.jsonl. + +[[recipe]] +name = "openssl-cve-2014-0160" +host = "github" +repo = "openssl/openssl" +parent = "0d7717fc9c83dafab8153cbd5e2180e6e04cc802" +commit = "96db9023b881d7cd9f379b0c154650d6c108e9a3" +path = "ssl/t1_lib.c" +function = "tls1_process_heartbeat" +cve = "CVE-2014-0160" +year = 2014 +license = "OpenSSL License" +relpath = "ssl/t1_lib.c" +language = "c" +cwe = "CWE-126" +class = "buffer over-read" +rule_id = "c-unsafe-memory-copy" +sink = "memcpy" +evidence = "memcpy copies heartbeat payload using an attacker-controlled length" +commit_url = "https://github.com/openssl/openssl/commit/96db9023b881d7cd9f379b0c154650d6c108e9a3" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "firefox-cve-2020-15667" +host = "phabricator" +repo = "mozilla-central" +parent = "0c0f777161a9499dd149853ff62d356f75d16c2a" +commit = "b79b6cc78248eea7fda10bfb76aa273c19c9fa65" +path = "modules/libmar/src/mar_read.c" +function = "mar_insert_item" +cve = "CVE-2020-15667" +year = 2020 +license = "MPL-2.0" +relpath = "modules/libmar/src/mar_read.c" +language = "c" +cwe = "CWE-119" +class = "buffer overflow" +rule_id = "c-unsafe-memory-copy" +sink = "memcpy" +evidence = "memcpy copies a MAR index name using a signed namelen that can wrap" +commit_url = "https://hg.mozilla.org/mozilla-central/rev/b79b6cc78248eea7fda10bfb76aa273c19c9fa65" +origin = "mozilla-central" +project = "firefox" + +[[recipe]] +name = "chromium-cve-2019-5786" +host = "github" +repo = "chromium/chromium" +parent = "9f3fccdba567f30ea39b08f57d8d5b49cd832b4a" +commit = "ba9748e78ec7e9c0d594e7edf7b2c07ea2a90449" +path = "third_party/blink/renderer/core/fileapi/file_reader_loader.cc" +function = "ArrayBufferResult" +cve = "CVE-2019-5786" +year = 2019 +license = "BSD-3-Clause" +relpath = "third_party/blink/renderer/core/fileapi/file_reader_loader.cc" +language = "cpp" +cwe = "CWE-416" +class = "use after free" +rule_id = "c-unsafe-memory-copy" +sink = "ToArrayBuffer" +evidence = "ArrayBufferResult can return two references to the same underlying ArrayBuffer" +commit_url = "https://github.com/chromium/chromium/commit/ba9748e78ec7e9c0d594e7edf7b2c07ea2a90449" +origin = "chromium" +project = "chromium" + +[[recipe]] +name = "openssl-cve-2020-1967" +host = "github" +repo = "openssl/openssl" +parent = "3656c08ab4b1b892730cb5e808b6f4298b08a2e6" +commit = "a87f3fe01a5a894aa27ccd6a239155fd129988e4" +path = "ssl/t1_lib.c" +function = "tls1_check_sig_alg" +cve = "CVE-2020-1967" +year = 2020 +license = "OpenSSL License" +relpath = "ssl/t1_lib.c" +language = "c" +cwe = "CWE-476" +class = "null pointer dereference" +sink = "tls1_check_sig_alg" +evidence = "SSL_check_chain / tls1_check_sig_alg can dereference NULL in TLS 1.3" +commit_url = "https://github.com/openssl/openssl/commit/a87f3fe01a5a894aa27ccd6a239155fd129988e4" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2020-1971" +host = "github" +repo = "openssl/openssl" +parent = "198b11683568452282bd48828fcf60d4835bf327" +commit = "b33c48b75aaf33c93aeda42d7138616b9e6a64cb" +path = "crypto/x509/v3_genn.c" +function = "GENERAL_NAME_cmp" +cve = "CVE-2020-1971" +year = 2020 +license = "OpenSSL License" +relpath = "crypto/x509/v3_genn.c" +language = "c" +cwe = "CWE-476" +class = "null pointer dereference" +sink = "GENERAL_NAME_cmp" +evidence = "GENERAL_NAME_cmp mishandles EdiPartyName comparison" +commit_url = "https://github.com/openssl/openssl/commit/b33c48b75aaf33c93aeda42d7138616b9e6a64cb" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2021-23840" +host = "github" +repo = "openssl/openssl" +parent = "c1ddd392cf9737c09c1f9bf690adfbe596403c5e" +commit = "c9fb704cf3af5524eb8e79961e31b60eee8c3c47" +path = "crypto/evp/evp_enc.c" +function = "evp_EncryptDecryptUpdate" +cve = "CVE-2021-23840" +year = 2021 +license = "OpenSSL License" +relpath = "crypto/evp/evp_enc.c" +language = "c" +cwe = "CWE-190" +class = "integer overflow" +sink = "EVP_CipherUpdate" +evidence = "EVP_CipherUpdate output length can overflow" +commit_url = "https://github.com/openssl/openssl/commit/c9fb704cf3af5524eb8e79961e31b60eee8c3c47" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2021-3711" +host = "github" +repo = "openssl/openssl" +parent = "8c74c9d1ade0fbdab5b815ddb747351b8b839641" +commit = "59f5e75f3bced8fc0e130d72a3f582cf7b480b46" +path = "crypto/sm2/sm2_crypt.c" +function = "sm2_plaintext_size" +cve = "CVE-2021-3711" +year = 2021 +license = "OpenSSL License" +relpath = "crypto/sm2/sm2_crypt.c" +language = "c" +cwe = "CWE-120" +class = "buffer overflow" +sink = "sm2_decrypt" +evidence = "SM2 plaintext size is underestimated so the second EVP_PKEY_decrypt overflows" +commit_url = "https://github.com/openssl/openssl/commit/59f5e75f3bced8fc0e130d72a3f582cf7b480b46" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2021-3712" +host = "github" +repo = "openssl/openssl" +parent = "1f365708a3318a5f1a395f90c38b584a58d37fb9" +commit = "98624776c4d501c8badd6f772ab7048ac9191cb9" +path = "crypto/x509/v3_utl.c" +function = "append_ia5" +cve = "CVE-2021-3712" +year = 2021 +license = "OpenSSL License" +relpath = "crypto/x509/v3_utl.c" +language = "c" +cwe = "CWE-125" +class = "buffer over-read" +sink = "append_ia5" +evidence = "append_ia5 assumes NUL-terminated ASN.1 strings" +commit_url = "https://github.com/openssl/openssl/commit/98624776c4d501c8badd6f772ab7048ac9191cb9" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2022-0778" +host = "github" +repo = "openssl/openssl" +parent = "1832bb0f02e519a48f06a10467c7ce5f7f3feeeb" +commit = "9eafb53614bf65797db25f467946e735e1b43dc9" +path = "crypto/bn/bn_sqrt.c" +function = "BN_mod_sqrt" +cve = "CVE-2022-0778" +year = 2022 +license = "Apache-2.0" +relpath = "crypto/bn/bn_sqrt.c" +language = "c" +cwe = "CWE-835" +class = "infinite loop" +sink = "BN_mod_sqrt" +evidence = "BN_mod_sqrt can loop forever on crafted moduli" +commit_url = "https://github.com/openssl/openssl/commit/9eafb53614bf65797db25f467946e735e1b43dc9" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2022-1292" +host = "github" +repo = "openssl/openssl" +parent = "7d56a74a96828985db7354a55227a511615f732b" +commit = "1ad73b4d27bd8c1b369a3cd453681d3a4f1bb9b2" +path = "tools/c_rehash.in" +function = "link_hash_cert" +cve = "CVE-2022-1292" +year = 2022 +license = "Apache-2.0" +relpath = "tools/c_rehash.in" +language = "perl" +cwe = "CWE-78" +class = "command injection" +sink = "backtick" +evidence = "c_rehash interpolates certificate filenames into a shell backtick command" +commit_url = "https://github.com/openssl/openssl/commit/1ad73b4d27bd8c1b369a3cd453681d3a4f1bb9b2" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2022-3602" +host = "github" +repo = "openssl/openssl" +parent = "89d72311327735ef15c804d2adea84a0fb1bfa0a" +commit = "3b421ebc64c7b52f1b9feb3812bdc7781c784332" +path = "crypto/punycode.c" +function = "ossl_punycode_decode" +cve = "CVE-2022-3602" +year = 2022 +license = "Apache-2.0" +relpath = "crypto/punycode.c" +language = "c" +cwe = "CWE-787" +class = "buffer overflow" +sink = "ossl_punycode_decode" +evidence = "punycode decoder can write past the output buffer" +commit_url = "https://github.com/openssl/openssl/commit/3b421ebc64c7b52f1b9feb3812bdc7781c784332" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2022-3786" +host = "github" +repo = "openssl/openssl" +parent = "3b421ebc64c7b52f1b9feb3812bdc7781c784332" +commit = "680e65b94c916af259bfdc2e25f1ab6e0c7a97d6" +path = "crypto/punycode.c" +function = "ossl_punycode_decode" +cve = "CVE-2022-3786" +year = 2022 +license = "Apache-2.0" +relpath = "crypto/punycode.c" +language = "c" +cwe = "CWE-787" +class = "buffer overflow" +sink = "ossl_punycode_decode" +evidence = "punycode decoder can overflow a stack buffer via a crafted email name" +commit_url = "https://github.com/openssl/openssl/commit/680e65b94c916af259bfdc2e25f1ab6e0c7a97d6" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2023-0286" +host = "github" +repo = "openssl/openssl" +parent = "adf77d6657e836fc87391fad53d857927a764297" +commit = "7880536fe17c2b5450e279155bedd51771d28c9f" +path = "crypto/x509/v3_genn.c" +function = "GENERAL_NAME_cmp" +cve = "CVE-2023-0286" +year = 2023 +license = "Apache-2.0" +relpath = "crypto/x509/v3_genn.c" +language = "c" +cwe = "CWE-843" +class = "type confusion" +sink = "GENERAL_NAME_cmp" +evidence = "GENERAL_NAME_cmp type-confuses x400Address" +commit_url = "https://github.com/openssl/openssl/commit/7880536fe17c2b5450e279155bedd51771d28c9f" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "curl-cve-2023-38545" +host = "github" +repo = "curl/curl" +parent = "09e25b9d94f4106eac8ca3a43b221bdc66f405e4" +commit = "fb4415d8aee6c1045be932a34fe6107c2f5ed147" +path = "lib/socks.c" +function = "do_SOCKS5" +cve = "CVE-2023-38545" +year = 2023 +license = "curl" +relpath = "lib/socks.c" +language = "c" +cwe = "CWE-122" +class = "heap buffer overflow" +rule_id = "c-unsafe-memory-copy" +sink = "memcpy" +evidence = "SOCKS5 remote-resolve copies a hostname that can exceed the local buffer" +commit_url = "https://github.com/curl/curl/commit/fb4415d8aee6c1045be932a34fe6107c2f5ed147" +origin = "curl" +project = "curl" + +[[recipe]] +name = "chromium-cve-2022-2162" +host = "github" +repo = "chromium/chromium" +parent = "a07d0ae0a7dc68686adca10dcf11138cb2f4ab6d" +commit = "22c61cfae5d1b37c773e638d342488ae11118b51" +path = "content/browser/file_system_access/file_system_chooser.cc" +function = "IsShellIntegratedExtension" +cve = "CVE-2022-2162" +year = 2022 +license = "BSD-3-Clause" +relpath = "content/browser/file_system_access/file_system_chooser.cc" +language = "cpp" +cwe = "CWE-20" +class = "insufficient input validation" +sink = "IsShellIntegratedExtension" +evidence = "File System Access suggested names did not sanitize Windows .url shell extensions" +commit_url = "https://github.com/chromium/chromium/commit/22c61cfae5d1b37c773e638d342488ae11118b51" +origin = "chromium" +project = "chromium" + +[[recipe]] +name = "openssl-cve-2025-69421" +host = "github" +repo = "openssl/openssl" +parent = "ea8fc4c345fbd749048809c9f7c881ea656b0b94" +commit = "2c13bf15286328641a805eb3b7c97e27d42881fb" +path = "crypto/pkcs12/p12_decr.c" +function = "PKCS12_item_decrypt_d2i_ex" +cve = "CVE-2025-69421" +year = 2025 +license = "Apache-2.0" +relpath = "crypto/pkcs12/p12_decr.c" +language = "c" +cwe = "CWE-476" +class = "null pointer dereference" +sink = "PKCS12_item_decrypt_d2i_ex" +evidence = "PKCS12_item_decrypt_d2i_ex did not check a NULL oct argument" +commit_url = "https://github.com/openssl/openssl/commit/2c13bf15286328641a805eb3b7c97e27d42881fb" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2025-66199" +host = "github" +repo = "openssl/openssl" +parent = "b21663c35a6f0ed4c8de06855bdc7a6a21f00c2f" +commit = "84f73f79af9f69c1527a9a372b7a9e771a394c2a" +path = "ssl/statem/statem_lib.c" +function = "tls13_process_compressed_certificate" +cve = "CVE-2025-66199" +year = 2025 +license = "Apache-2.0" +relpath = "ssl/statem/statem_lib.c" +language = "c" +cwe = "CWE-770" +class = "uncontrolled allocation" +sink = "tls13_process_compressed_certificate" +evidence = "TLS 1.3 compressed certificate length was trusted before allocation" +commit_url = "https://github.com/openssl/openssl/commit/84f73f79af9f69c1527a9a372b7a9e771a394c2a" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "firefox-bug-2058173" +host = "github" +repo = "mozilla-firefox/firefox" +parent = "eed0931f85474d0db6e2326dfd9718c6bf1cd418" +commit = "e46f28da1cd3a5d46a2680b3d87361e9e8de4ae6" +path = "modules/libmar/src/mar_read.c" +function = "mar_read_index" +cve = "BUG-2058173" +year = 2026 +license = "MPL-2.0" +relpath = "modules/libmar/src/mar_read.c" +language = "c" +cwe = "CWE-770" +class = "uncontrolled allocation" +sink = "malloc" +evidence = "mar_read_index malloc'd an untrusted MAR index size with no upper bound" +commit_url = "https://github.com/mozilla-firefox/firefox/commit/e46f28da1cd3a5d46a2680b3d87361e9e8de4ae6" +origin = "mozilla-firefox/firefox" +project = "firefox" + +# --- auto-harvested 2020-2026 (local git mine) --- + +[[recipe]] +name = "openssl-cve-2026-18798" +host = "github" +repo = "openssl/openssl" +parent = "48f5785425ee6b5316f8e5f921978397ba632cc6" +commit = "70cebd74d3592f5272945501b58a60374c4e13af" +path = "ssl/quic/quic_port.c" +function = "port_default_packet_handler" +cve = "CVE-2026-18798" +year = 2026 +license = "Apache-2.0" +relpath = "ssl/quic/quic_port.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Avoid double free of qrx in port_default_packet_handler()" +commit_url = "https://github.com/openssl/openssl/commit/70cebd74d3592f5272945501b58a60374c4e13af" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-54874" +host = "github" +repo = "openssl/openssl" +parent = "a0c8ec557d9cac078f032d76cdf684fe743eb382" +commit = "1ca5a124b48f1ffe6980ad33724b452fbd62da1e" +path = "ssl/record/rec_layer_d1.c" +function = "DTLS_RECORD_LAYER_clear" +cve = "CVE-2026-54874" +year = 2026 +license = "Apache-2.0" +relpath = "ssl/record/rec_layer_d1.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Avoid full read buffer allocation when buffering DTLS records" +commit_url = "https://github.com/openssl/openssl/commit/1ca5a124b48f1ffe6980ad33724b452fbd62da1e" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-54874-dtls1_process_record" +host = "github" +repo = "openssl/openssl" +parent = "a0c8ec557d9cac078f032d76cdf684fe743eb382" +commit = "1ca5a124b48f1ffe6980ad33724b452fbd62da1e" +path = "ssl/record/ssl3_record.c" +function = "dtls1_process_record" +cve = "CVE-2026-54874" +year = 2026 +license = "Apache-2.0" +relpath = "ssl/record/ssl3_record.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Avoid full read buffer allocation when buffering DTLS records" +commit_url = "https://github.com/openssl/openssl/commit/1ca5a124b48f1ffe6980ad33724b452fbd62da1e" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-54874-dtls_rlayer_buffer_recor" +host = "github" +repo = "openssl/openssl" +parent = "9ec2f6d2ae2bcad907cf7ee38584855bafe4979a" +commit = "7110cb2f75806d0bf809eb2f90790d477900be40" +path = "ssl/record/methods/dtls_meth.c" +function = "dtls_rlayer_buffer_record" +cve = "CVE-2026-54874" +year = 2026 +license = "Apache-2.0" +relpath = "ssl/record/methods/dtls_meth.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Avoid full read buffer allocation when buffering DTLS next-epoch records" +commit_url = "https://github.com/openssl/openssl/commit/7110cb2f75806d0bf809eb2f90790d477900be40" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-63072" +host = "github" +repo = "openssl/openssl" +parent = "d307f61f1b341b6eb7d5d07bd6902a939c709bc6" +commit = "a0c8ec557d9cac078f032d76cdf684fe743eb382" +path = "crypto/cms/cms_kari.c" +function = "cms_kek_cipher" +cve = "CVE-2026-63072" +year = 2026 +license = "Apache-2.0" +relpath = "crypto/cms/cms_kari.c" +language = "c" +cwe = "CWE-119" +class = "buffer overflow" +sink = "memcpy" +evidence = "Fix heap buffer overflow (8-byte OOB write) in AES-WRAP-PAD unwrap" +commit_url = "https://github.com/openssl/openssl/commit/a0c8ec557d9cac078f032d76cdf684fe743eb382" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-63072-cms_kek_cipher" +host = "github" +repo = "openssl/openssl" +parent = "1951c3cbd9d5101e027a1eb126f26c3c758f6cc0" +commit = "2a3dac874c8057c1f0186849bf1ede1ae7b6b756" +path = "crypto/cms/cms_kemri.c" +function = "cms_kek_cipher" +cve = "CVE-2026-63072" +year = 2026 +license = "Apache-2.0" +relpath = "crypto/cms/cms_kemri.c" +language = "c" +cwe = "CWE-119" +class = "buffer overflow" +sink = "memcpy" +evidence = "Fix heap buffer overflow (8-byte OOB write) in AES-WRAP-PAD unwrap" +commit_url = "https://github.com/openssl/openssl/commit/2a3dac874c8057c1f0186849bf1ede1ae7b6b756" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-63073" +host = "github" +repo = "openssl/openssl" +parent = "1e8c398db67404babd3e5af999bb6bd86f720c76" +commit = "a7e5a6eea8fd3ccca6b6fbba031a5fbf8a3d93b4" +path = "crypto/cmp/cmp_vfy.c" +function = "ossl_cmp_msg_check_update" +cve = "CVE-2026-63073" +year = 2026 +license = "Apache-2.0" +relpath = "crypto/cmp/cmp_vfy.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "CMP unexpected sender DN used as format string in ERR_raise_data()" +commit_url = "https://github.com/openssl/openssl/commit/a7e5a6eea8fd3ccca6b6fbba031a5fbf8a3d93b4" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-14457" +host = "github" +repo = "openssl/openssl" +parent = "f636f9ca0fa1bae5b42f9e787f025c96fb09c43a" +commit = "1e8c398db67404babd3e5af999bb6bd86f720c76" +path = "ssl/t1_lib.c" +function = "check_cert_usable" +cve = "CVE-2026-14457" +year = 2026 +license = "Apache-2.0" +relpath = "ssl/t1_lib.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Handle signature_algorithms_cert extension in key-only context" +commit_url = "https://github.com/openssl/openssl/commit/1e8c398db67404babd3e5af999bb6bd86f720c76" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-63074" +host = "github" +repo = "openssl/openssl" +parent = "9f2b8522d39ff869fac2ff7c3f20609b54843188" +commit = "21a5d9658b0c66daace60e10ea18ff32a448de9f" +path = "crypto/cmp/cmp_vfy.c" +function = "ossl_cmp_msg_check_update" +cve = "CVE-2026-63074" +year = 2026 +license = "Apache-2.0" +relpath = "crypto/cmp/cmp_vfy.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Fix unbounded cert cache growth in cmp" +commit_url = "https://github.com/openssl/openssl/commit/21a5d9658b0c66daace60e10ea18ff32a448de9f" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-63075-txp_pkt_commit" +host = "github" +repo = "openssl/openssl" +parent = "a1f348ccb328c3afbd4ba6883f9b7c813c043259" +commit = "c902e5f16d6a9e130e96d3ca6d8f64d71652e393" +path = "ssl/quic/quic_txp.c" +function = "txp_pkt_commit" +cve = "CVE-2026-63075" +year = 2026 +license = "Apache-2.0" +relpath = "ssl/quic/quic_txp.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Don't store ACK-only frames in TX history for QUIC." +commit_url = "https://github.com/openssl/openssl/commit/c902e5f16d6a9e130e96d3ca6d8f64d71652e393" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-75803" +host = "github" +repo = "openssl/openssl" +parent = "39488cb863074d5b8ece833905f7ad2b357d44fe" +commit = "119ab9555dc62275bbd71f6f49529b1a44feba42" +path = "providers/implementations/ciphers/cipher_aes_ocb.c" +function = "aes_ocb_cipher" +cve = "CVE-2026-75803" +year = 2026 +license = "Apache-2.0" +relpath = "providers/implementations/ciphers/cipher_aes_ocb.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Check the tag on EVP_Cipher() finalize: Poly1305 and OCB AEADs" +commit_url = "https://github.com/openssl/openssl/commit/119ab9555dc62275bbd71f6f49529b1a44feba42" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-75803-chacha20_poly1305_cipher" +host = "github" +repo = "openssl/openssl" +parent = "39488cb863074d5b8ece833905f7ad2b357d44fe" +commit = "119ab9555dc62275bbd71f6f49529b1a44feba42" +path = "providers/implementations/ciphers/cipher_chacha20_poly1305.c" +function = "chacha20_poly1305_cipher" +cve = "CVE-2026-75803" +year = 2026 +license = "Apache-2.0" +relpath = "providers/implementations/ciphers/cipher_chacha20_poly1305.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Check the tag on EVP_Cipher() finalize: Poly1305 and OCB AEADs" +commit_url = "https://github.com/openssl/openssl/commit/119ab9555dc62275bbd71f6f49529b1a44feba42" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-75803-aes_gcm_siv_finish" +host = "github" +repo = "openssl/openssl" +parent = "de7d1871087fc1fa3e2c1db4b11275b68d72f416" +commit = "bf95f5f772e9362f87b25cfa2f8cb15d984865b9" +path = "providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c" +function = "aes_gcm_siv_finish" +cve = "CVE-2026-75803" +year = 2026 +license = "Apache-2.0" +relpath = "providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Check the tag on EVP_Cipher() finalize: Poly1305 and OCB AEADs" +commit_url = "https://github.com/openssl/openssl/commit/bf95f5f772e9362f87b25cfa2f8cb15d984865b9" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-14456-port_default_packet_hand" +host = "github" +repo = "openssl/openssl" +parent = "2dacccc943b47b8dc1ce8f7109c9852391b5a0d8" +commit = "08e7756c3900bcfd77a720e7b74e27d6e4ed01a9" +path = "ssl/quic/quic_port.c" +function = "port_default_packet_handler" +cve = "CVE-2026-14456" +year = 2026 +license = "Apache-2.0" +relpath = "ssl/quic/quic_port.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "QUIC server: limit number of pending QUIC channels/connections" +commit_url = "https://github.com/openssl/openssl/commit/08e7756c3900bcfd77a720e7b74e27d6e4ed01a9" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-14456-expect_quic_for_value" +host = "github" +repo = "openssl/openssl" +parent = "2c9a078b6030444ed868a3943991f42b35cd49dc" +commit = "9416706d408bb84deb7cee4647bff3045d2dc7ba" +path = "ssl/quic/quic_impl.c" +function = "expect_quic_for_value" +cve = "CVE-2026-14456" +year = 2026 +license = "Apache-2.0" +relpath = "ssl/quic/quic_impl.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "QUIC server: limit number of pending QUIC channels/connections" +commit_url = "https://github.com/openssl/openssl/commit/9416706d408bb84deb7cee4647bff3045d2dc7ba" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-45447" +host = "github" +repo = "openssl/openssl" +parent = "609bcb24866d64f1fc49d38b852edbb39057d721" +commit = "f4129fbe3cde786d363510069fe297234f99be8f" +path = "crypto/pkcs7/pk7_smime.c" +function = "PKCS7_verify" +cve = "CVE-2026-45447" +year = 2026 +license = "Apache-2.0" +relpath = "crypto/pkcs7/pk7_smime.c" +language = "c" +cwe = "CWE-416" +class = "use after free" +sink = "free" +evidence = "Fix possible use-after-free in OpenSSL PKCS7_verify()" +commit_url = "https://github.com/openssl/openssl/commit/f4129fbe3cde786d363510069fe297234f99be8f" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-45446" +host = "github" +repo = "openssl/openssl" +parent = "f87f0b6a8e04bcdeb98afc82b0da06a2d537f399" +commit = "609bcb24866d64f1fc49d38b852edbb39057d721" +path = "providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c" +function = "aes_gcm_siv_initkey" +cve = "CVE-2026-45446" +year = 2026 +license = "Apache-2.0" +relpath = "providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Fix handling of empty-ciphertext messages in AES-GCM-SIV and AES-SIV" +commit_url = "https://github.com/openssl/openssl/commit/609bcb24866d64f1fc49d38b852edbb39057d721" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-45446-aes_siv_set_ctx_params" +host = "github" +repo = "openssl/openssl" +parent = "f87f0b6a8e04bcdeb98afc82b0da06a2d537f399" +commit = "609bcb24866d64f1fc49d38b852edbb39057d721" +path = "providers/implementations/ciphers/cipher_aes_siv.c" +function = "aes_siv_set_ctx_params" +cve = "CVE-2026-45446" +year = 2026 +license = "Apache-2.0" +relpath = "providers/implementations/ciphers/cipher_aes_siv.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Fix handling of empty-ciphertext messages in AES-GCM-SIV and AES-SIV" +commit_url = "https://github.com/openssl/openssl/commit/609bcb24866d64f1fc49d38b852edbb39057d721" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-45445" +host = "github" +repo = "openssl/openssl" +parent = "5f489043b662fed32fbf7eb7442c479568eb43fd" +commit = "f87f0b6a8e04bcdeb98afc82b0da06a2d537f399" +path = "providers/implementations/ciphers/cipher_aes_ocb.c" +function = "aes_ocb_cipher" +cve = "CVE-2026-45445" +year = 2026 +license = "Apache-2.0" +relpath = "providers/implementations/ciphers/cipher_aes_ocb.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Apply the buffered IV on the AES-OCB EVP_Cipher() path" +commit_url = "https://github.com/openssl/openssl/commit/f87f0b6a8e04bcdeb98afc82b0da06a2d537f399" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-42771" +host = "github" +repo = "openssl/openssl" +parent = "0f3fab2eccc7c3417093a8243dd15d95b6cb472d" +commit = "b3a555a0a7aa0028887149f6f973af89a4937bea" +path = "crypto/x509/x509_vpm.c" +function = "validate_hostname_part" +cve = "CVE-2026-42771" +year = 2026 +license = "Apache-2.0" +relpath = "crypto/x509/x509_vpm.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Fix length miscalculation in validate_email" +commit_url = "https://github.com/openssl/openssl/commit/b3a555a0a7aa0028887149f6f973af89a4937bea" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-42769" +host = "github" +repo = "openssl/openssl" +parent = "d5030cdf32d6cd27bd964a0cb7aed2b7cb713369" +commit = "c2765d53c2649b56bc1ca1bb799e42002953056a" +path = "crypto/cmp/cmp_genm.c" +function = "selfsigned_verify_cb" +cve = "CVE-2026-42769" +year = 2026 +license = "Apache-2.0" +relpath = "crypto/cmp/cmp_genm.c" +language = "c" +cwe = "CWE-476" +class = "null pointer dereference" +sink = "NULL" +evidence = "Use the correct issuer when validating rootCAKeyUpdate" +commit_url = "https://github.com/openssl/openssl/commit/c2765d53c2649b56bc1ca1bb799e42002953056a" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-42768" +host = "github" +repo = "openssl/openssl" +parent = "f04d65692dd8109be9f387ce2ddd9fb1ab612b6b" +commit = "d5030cdf32d6cd27bd964a0cb7aed2b7cb713369" +path = "crypto/cms/cms_env.c" +function = "cms_RecipientInfo_ktri_decrypt" +cve = "CVE-2026-42768" +year = 2026 +license = "Apache-2.0" +relpath = "crypto/cms/cms_env.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Enforce implicit rejection for CMS/PKCS#7 decryption" +commit_url = "https://github.com/openssl/openssl/commit/d5030cdf32d6cd27bd964a0cb7aed2b7cb713369" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-42768-pkcs7_decrypt_rinfo" +host = "github" +repo = "openssl/openssl" +parent = "f04d65692dd8109be9f387ce2ddd9fb1ab612b6b" +commit = "d5030cdf32d6cd27bd964a0cb7aed2b7cb713369" +path = "crypto/pkcs7/pk7_doit.c" +function = "pkcs7_decrypt_rinfo" +cve = "CVE-2026-42768" +year = 2026 +license = "Apache-2.0" +relpath = "crypto/pkcs7/pk7_doit.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Enforce implicit rejection for CMS/PKCS#7 decryption" +commit_url = "https://github.com/openssl/openssl/commit/d5030cdf32d6cd27bd964a0cb7aed2b7cb713369" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-42766" +host = "github" +repo = "openssl/openssl" +parent = "a9af3442290e8a04706a3cd5f284ffd5b486e3f6" +commit = "74245170b5a64b234ac4af27c86a25ec251c8b2a" +path = "crypto/cms/cms_pwri.c" +function = "ossl_cms_RecipientInfo_pwri_crypt" +cve = "CVE-2026-42766" +year = 2026 +license = "Apache-2.0" +relpath = "crypto/cms/cms_pwri.c" +language = "c" +cwe = "CWE-476" +class = "null pointer dereference" +sink = "NULL" +evidence = "Fix potential NULL dereference processing CMS PasswordRecipientInfo" +commit_url = "https://github.com/openssl/openssl/commit/74245170b5a64b234ac4af27c86a25ec251c8b2a" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-42765" +host = "github" +repo = "openssl/openssl" +parent = "5097ec4dae239112498abb722e255ea60ef7ac48" +commit = "a9af3442290e8a04706a3cd5f284ffd5b486e3f6" +path = "crypto/x509/x509_vfy.c" +function = "check_revocation" +cve = "CVE-2026-42765" +year = 2026 +license = "Apache-2.0" +relpath = "crypto/x509/x509_vfy.c" +language = "c" +cwe = "CWE-476" +class = "null pointer dereference" +sink = "NULL" +evidence = "Fix NULL Dereference in Certificate Verification with OCSP Checking" +commit_url = "https://github.com/openssl/openssl/commit/a9af3442290e8a04706a3cd5f284ffd5b486e3f6" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-42764" +host = "github" +repo = "openssl/openssl" +parent = "58633b658fe74095c8cdde191e4ce1bf94f8c5f9" +commit = "5097ec4dae239112498abb722e255ea60ef7ac48" +path = "ssl/quic/quic_port.c" +function = "port_default_packet_handler" +cve = "CVE-2026-42764" +year = 2026 +license = "Apache-2.0" +relpath = "ssl/quic/quic_port.c" +language = "c" +cwe = "CWE-476" +class = "null pointer dereference" +sink = "NULL" +evidence = "Fix NULL dereference in QUIC address validation" +commit_url = "https://github.com/openssl/openssl/commit/5097ec4dae239112498abb722e255ea60ef7ac48" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-35188" +host = "github" +repo = "openssl/openssl" +parent = "68ef88913e321bdb47eee88118ceba18ed2388cd" +commit = "58633b658fe74095c8cdde191e4ce1bf94f8c5f9" +path = "crypto/x509/x509_vfy.c" +function = "check_cert_ocsp_resp" +cve = "CVE-2026-35188" +year = 2026 +license = "Apache-2.0" +relpath = "crypto/x509/x509_vfy.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Fix Double-free When Checking OCSP Stapled Response" +commit_url = "https://github.com/openssl/openssl/commit/58633b658fe74095c8cdde191e4ce1bf94f8c5f9" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-34181" +host = "github" +repo = "openssl/openssl" +parent = "fcb23806047f5afbe55d5d601a527fc24bf7ca2c" +commit = "5a0230b6cc95a576b0c2b7b5b2ba7c74232e7b7c" +path = "crypto/pkcs12/p12_mutl.c" +function = "PBMAC1_PBKDF2_HMAC" +cve = "CVE-2026-34181" +year = 2026 +license = "Apache-2.0" +relpath = "crypto/pkcs12/p12_mutl.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "pkcs12: verify that the pbmac1 key length is safe" +commit_url = "https://github.com/openssl/openssl/commit/5a0230b6cc95a576b0c2b7b5b2ba7c74232e7b7c" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-9076" +host = "github" +repo = "openssl/openssl" +parent = "97f6b621f7af2c4c4e162c75045a6e12a8fdf8d9" +commit = "51d1800e95283a8beec85152e35e3634dab8dd82" +path = "crypto/cms/cms_pwri.c" +function = "kek_unwrap_key" +cve = "CVE-2026-9076" +year = 2026 +license = "Apache-2.0" +relpath = "crypto/cms/cms_pwri.c" +language = "c" +cwe = "CWE-119" +class = "buffer overflow" +sink = "memcpy" +evidence = "cms: kek_unwrap_key: Fix out-of-bounds read in check-byte validation" +commit_url = "https://github.com/openssl/openssl/commit/51d1800e95283a8beec85152e35e3634dab8dd82" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-7383" +host = "github" +repo = "openssl/openssl" +parent = "cb005ceaaf1fb50722e0101762a3e266338c5bf9" +commit = "97f6b621f7af2c4c4e162c75045a6e12a8fdf8d9" +path = "crypto/asn1/a_mbstr.c" +function = "ASN1_mbstring_ncopy" +cve = "CVE-2026-7383" +year = 2026 +license = "Apache-2.0" +relpath = "crypto/asn1/a_mbstr.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Reject oversized inputs in ASN1_mbstring_ncopy()" +commit_url = "https://github.com/openssl/openssl/commit/97f6b621f7af2c4c4e162c75045a6e12a8fdf8d9" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-31790" +host = "github" +repo = "openssl/openssl" +parent = "a91e537d16d74050dbde50bb0dfb1fe9930f0521" +commit = "eed200f58cd8645ed77e46b7e9f764e284df379e" +path = "providers/implementations/kem/rsa_kem.c" +function = "rsasve_generate" +cve = "CVE-2026-31790" +year = 2026 +license = "Apache-2.0" +relpath = "providers/implementations/kem/rsa_kem.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "rsa_kem: validate RSA_public_encrypt() result in RSASVE" +commit_url = "https://github.com/openssl/openssl/commit/eed200f58cd8645ed77e46b7e9f764e284df379e" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-31790-rsasve_generate" +host = "github" +repo = "openssl/openssl" +parent = "a24216018e1ede8ff01a4ff5afff7dfbd443e2f9" +commit = "abd8b2eec7e3f3fda60ecfb68498b246b52af482" +path = "providers/implementations/kem/rsa_kem.c.in" +function = "rsasve_generate" +cve = "CVE-2026-31790" +year = 2026 +license = "Apache-2.0" +relpath = "providers/implementations/kem/rsa_kem.c.in" +language = "perl" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "rsa_kem: validate RSA_public_encrypt() result in RSASVE" +commit_url = "https://github.com/openssl/openssl/commit/abd8b2eec7e3f3fda60ecfb68498b246b52af482" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-31789" +host = "github" +repo = "openssl/openssl" +parent = "b7ae7a093997b5cd549bc21cccd715510fef86c0" +commit = "a91e537d16d74050dbde50bb0dfb1fe9930f0521" +path = "crypto/o_str.c" +function = "buf2hexstr_sep" +cve = "CVE-2026-31789" +year = 2026 +license = "Apache-2.0" +relpath = "crypto/o_str.c" +language = "c" +cwe = "CWE-119" +class = "buffer overflow" +sink = "memcpy" +evidence = "Avoid possible buffer overflow in buf2hex conversion" +commit_url = "https://github.com/openssl/openssl/commit/a91e537d16d74050dbde50bb0dfb1fe9930f0521" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-28388" +host = "github" +repo = "openssl/openssl" +parent = "d044f9252fe9a54001986fb4eb4e32076a056527" +commit = "59c3b3158553ab53275bbbccca5cb305d591cf2e" +path = "crypto/x509/x509_vfy.c" +function = "check_delta_base" +cve = "CVE-2026-28388" +year = 2026 +license = "Apache-2.0" +relpath = "crypto/x509/x509_vfy.c" +language = "c" +cwe = "CWE-476" +class = "null pointer dereference" +sink = "NULL" +evidence = "Fix NULL Dereference When Delta CRL Lacks CRL Number Extension" +commit_url = "https://github.com/openssl/openssl/commit/59c3b3158553ab53275bbbccca5cb305d591cf2e" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-28389" +host = "github" +repo = "openssl/openssl" +parent = "6e74b1275cbc1fd1cf7ba32f662602d68501f6ca" +commit = "af2a5fecd3e71a29e7568f9c1453dec5cebbaff4" +path = "crypto/cms/cms_rsa.c" +function = "rsa_cms_decrypt" +cve = "CVE-2026-28389" +year = 2026 +license = "Apache-2.0" +relpath = "crypto/cms/cms_rsa.c" +language = "c" +cwe = "CWE-476" +class = "null pointer dereference" +sink = "NULL" +evidence = "Fix NULL deref in rsa_cms_decrypt" +commit_url = "https://github.com/openssl/openssl/commit/af2a5fecd3e71a29e7568f9c1453dec5cebbaff4" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-28389-dh_cms_set_shared_info" +host = "github" +repo = "openssl/openssl" +parent = "72ec3e38c87f71f5c50ae3b16cc34d8371c71bb9" +commit = "7b5274e812400cacb6f3be4c2df5340923fa807f" +path = "crypto/cms/cms_dh.c" +function = "dh_cms_set_shared_info" +cve = "CVE-2026-28389" +year = 2026 +license = "Apache-2.0" +relpath = "crypto/cms/cms_dh.c" +language = "c" +cwe = "CWE-476" +class = "null pointer dereference" +sink = "NULL" +evidence = "Fix NULL deref in [ec]dh_cms_set_shared_info" +commit_url = "https://github.com/openssl/openssl/commit/7b5274e812400cacb6f3be4c2df5340923fa807f" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-28389-ecdh_cms_set_shared_info" +host = "github" +repo = "openssl/openssl" +parent = "72ec3e38c87f71f5c50ae3b16cc34d8371c71bb9" +commit = "7b5274e812400cacb6f3be4c2df5340923fa807f" +path = "crypto/cms/cms_ec.c" +function = "ecdh_cms_set_shared_info" +cve = "CVE-2026-28389" +year = 2026 +license = "Apache-2.0" +relpath = "crypto/cms/cms_ec.c" +language = "c" +cwe = "CWE-476" +class = "null pointer dereference" +sink = "NULL" +evidence = "Fix NULL deref in [ec]dh_cms_set_shared_info" +commit_url = "https://github.com/openssl/openssl/commit/7b5274e812400cacb6f3be4c2df5340923fa807f" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2026-2673" +host = "github" +repo = "openssl/openssl" +parent = "21d525dc846aed171fc886f3da614a6645948f13" +commit = "85977e013f32ceb96aa034c0e741adddc1a05e34" +path = "ssl/t1_lib.c" +function = "gid_cb" +cve = "CVE-2026-2673" +year = 2026 +license = "Apache-2.0" +relpath = "ssl/t1_lib.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Fix group tuple handling in DEFAULT expansion" +commit_url = "https://github.com/openssl/openssl/commit/85977e013f32ceb96aa034c0e741adddc1a05e34" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2025-69419" +host = "github" +repo = "openssl/openssl" +parent = "7565bb46fa2979511cb27aad1c2bd6b80adf7352" +commit = "4191043c36f1a50c717a2d0075fc6f3b9bc0afc5" +path = "crypto/pkcs12/p12_utl.c" +function = "bmp_to_utf8" +cve = "CVE-2025-69419" +year = 2025 +license = "Apache-2.0" +relpath = "crypto/pkcs12/p12_utl.c" +language = "c" +cwe = "CWE-119" +class = "buffer overflow" +sink = "memcpy" +evidence = "Alternate fix for CVE-2025-69419" +commit_url = "https://github.com/openssl/openssl/commit/4191043c36f1a50c717a2d0075fc6f3b9bc0afc5" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2025-69418" +host = "github" +repo = "openssl/openssl" +parent = "475c466ef2fbd8fc1df6fae1c3eed9c813fc8ff6" +commit = "52d23c86a54adab5ee9f80e48b242b52c4cc2347" +path = "crypto/modes/ocb128.c" +function = "CRYPTO_ocb128_encrypt" +cve = "CVE-2025-69418" +year = 2025 +license = "Apache-2.0" +relpath = "crypto/modes/ocb128.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Fix OCB AES-NI/HW stream path unauthenticated/unencrypted trailing bytes" +commit_url = "https://github.com/openssl/openssl/commit/52d23c86a54adab5ee9f80e48b242b52c4cc2347" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2025-66199-tls13_process_compressed" +host = "github" +repo = "openssl/openssl" +parent = "384011202af92605d926fafe4a0bcd6b65d162ad" +commit = "3ed1f75249932b155eef993a8e66a99cb98bfef4" +path = "ssl/statem/statem_lib.c" +function = "tls13_process_compressed_certificate" +cve = "CVE-2025-66199" +year = 2025 +license = "Apache-2.0" +relpath = "ssl/statem/statem_lib.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Check the received uncompressed certificate length to prevent excessive pre-decompression allocation." +commit_url = "https://github.com/openssl/openssl/commit/3ed1f75249932b155eef993a8e66a99cb98bfef4" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2025-68160" +host = "github" +repo = "openssl/openssl" +parent = "e0666f72294691a808443970b654412a6d92fa0f" +commit = "475c466ef2fbd8fc1df6fae1c3eed9c813fc8ff6" +path = "crypto/bio/bf_lbuf.c" +function = "linebuffer_write" +cve = "CVE-2025-68160" +year = 2025 +license = "Apache-2.0" +relpath = "crypto/bio/bf_lbuf.c" +language = "c" +cwe = "CWE-119" +class = "buffer overflow" +sink = "memcpy" +evidence = "Fix heap buffer overflow in BIO_f_linebuffer" +commit_url = "https://github.com/openssl/openssl/commit/475c466ef2fbd8fc1df6fae1c3eed9c813fc8ff6" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2025-15469" +host = "github" +repo = "openssl/openssl" +parent = "1f08e54bad32843044fe8a675948d65e3b4ece65" +commit = "a7936fa4bd23c906e1955a16a0a0ab39a4953a61" +path = "apps/dgst.c" +function = "do_fp_oneshot_sign" +cve = "CVE-2025-15469" +year = 2025 +license = "Apache-2.0" +relpath = "apps/dgst.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Report truncation in oneshot `openssl dgst -sign`" +commit_url = "https://github.com/openssl/openssl/commit/a7936fa4bd23c906e1955a16a0a0ab39a4953a61" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2025-15467" +host = "github" +repo = "openssl/openssl" +parent = "3250efdfe99d2d7fe4fb05231add7fba864b7653" +commit = "ce39170276daec87f55c39dad1f629b56344429e" +path = "crypto/evp/evp_lib.c" +function = "evp_cipher_get_asn1_aead_params" +cve = "CVE-2025-15467" +year = 2025 +license = "Apache-2.0" +relpath = "crypto/evp/evp_lib.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Correct handling of AEAD-encrypted CMS with inadmissibly long IV" +commit_url = "https://github.com/openssl/openssl/commit/ce39170276daec87f55c39dad1f629b56344429e" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2025-11187" +host = "github" +repo = "openssl/openssl" +parent = "b8654779e3b3b4eb0bda7623c0891d394e068187" +commit = "205e3a55e16e4bd08c12fdbd3416ab829c0f6206" +path = "crypto/pkcs12/p12_mutl.c" +function = "PBMAC1_PBKDF2_HMAC" +cve = "CVE-2025-11187" +year = 2025 +license = "Apache-2.0" +relpath = "crypto/pkcs12/p12_mutl.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "pkcs12: Validate salt and keylength in PBMAC1" +commit_url = "https://github.com/openssl/openssl/commit/205e3a55e16e4bd08c12fdbd3416ab829c0f6206" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2025-9232" +host = "github" +repo = "openssl/openssl" +parent = "a79c4ce559c6a3a8fd4109e9f33c1185d5bf2def" +commit = "654dc11d23468a74fc8ea4672b702dd3feb7be4b" +path = "crypto/http/http_lib.c" +function = "use_proxy" +cve = "CVE-2025-9232" +year = 2025 +license = "Apache-2.0" +relpath = "crypto/http/http_lib.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "use_proxy(): Add missing terminating NUL byte" +commit_url = "https://github.com/openssl/openssl/commit/654dc11d23468a74fc8ea4672b702dd3feb7be4b" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2025-9230" +host = "github" +repo = "openssl/openssl" +parent = "7e0fc054a08706d194d3355aba4a06003cadfb29" +commit = "a79c4ce559c6a3a8fd4109e9f33c1185d5bf2def" +path = "crypto/cms/cms_pwri.c" +function = "kek_unwrap_key" +cve = "CVE-2025-9230" +year = 2025 +license = "Apache-2.0" +relpath = "crypto/cms/cms_pwri.c" +language = "c" +cwe = "CWE-119" +class = "buffer overflow" +sink = "memcpy" +evidence = "kek_unwrap_key(): Fix incorrect check of unwrapped key size" +commit_url = "https://github.com/openssl/openssl/commit/a79c4ce559c6a3a8fd4109e9f33c1185d5bf2def" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2024-12797" +host = "github" +repo = "openssl/openssl" +parent = "0db27ec7f8abd258d2e8849ac555ca26ba0cd8d6" +commit = "798779d43494549b611233f92652f0da5328fbe7" +path = "ssl/statem/statem_clnt.c" +function = "tls_post_process_server_rpk" +cve = "CVE-2024-12797" +year = 2024 +license = "Apache-2.0" +relpath = "ssl/statem/statem_clnt.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "With SSL_VERIFY_PEER client RPK should abort on X509 error" +commit_url = "https://github.com/openssl/openssl/commit/798779d43494549b611233f92652f0da5328fbe7" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2024-13176-ec_field_inverse_mod_ord" +host = "github" +repo = "openssl/openssl" +parent = "643de602771f6b38ad7823e26d5a63c669eb185b" +commit = "07272b05b04836a762b4baa874958af51d513844" +path = "crypto/ec/ec_lib.c" +function = "ec_field_inverse_mod_ord" +cve = "CVE-2024-13176" +year = 2024 +license = "Apache-2.0" +relpath = "crypto/ec/ec_lib.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Fix timing side-channel in ECDSA signature computation" +commit_url = "https://github.com/openssl/openssl/commit/07272b05b04836a762b4baa874958af51d513844" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2024-6119" +host = "github" +repo = "openssl/openssl" +parent = "9aae56395aa8e77c44a9df83fd395a644d016635" +commit = "06d1dc3fa96a2ba5a3e22735a033012aadc9f0d6" +path = "crypto/x509/v3_utl.c" +function = "do_x509_check" +cve = "CVE-2024-6119" +year = 2024 +license = "Apache-2.0" +relpath = "crypto/x509/v3_utl.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Avoid type errors in EAI-related name check logic." +commit_url = "https://github.com/openssl/openssl/commit/06d1dc3fa96a2ba5a3e22735a033012aadc9f0d6" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2024-5535" +host = "github" +repo = "openssl/openssl" +parent = "189a7ed3e380e34ea38fe4190a7c9396bace0fb7" +commit = "4b375b998798dd516d367036773073e1b88e6433" +path = "ssl/statem/extensions_clnt.c" +function = "tls_parse_stoc_alpn" +cve = "CVE-2024-5535" +year = 2024 +license = "Apache-2.0" +relpath = "ssl/statem/extensions_clnt.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Add ALPN validation in the client" +commit_url = "https://github.com/openssl/openssl/commit/4b375b998798dd516d367036773073e1b88e6433" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2024-5535-tls_construct_stoc_next_" +host = "github" +repo = "openssl/openssl" +parent = "72394c9a1a6a6b07edf43eb2ad7e95e1093ada1b" +commit = "189a7ed3e380e34ea38fe4190a7c9396bace0fb7" +path = "ssl/statem/extensions_srvr.c" +function = "tls_construct_stoc_next_proto_neg" +cve = "CVE-2024-5535" +year = 2024 +license = "Apache-2.0" +relpath = "ssl/statem/extensions_srvr.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Correct return values for tls_construct_stoc_next_proto_neg" +commit_url = "https://github.com/openssl/openssl/commit/189a7ed3e380e34ea38fe4190a7c9396bace0fb7" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2024-5535-tls_parse_stoc_npn" +host = "github" +repo = "openssl/openssl" +parent = "cf6f91f6121f4db167405db2f0de410a456f260c" +commit = "159921152fd4aa91e4c849fd281ad93ac0d0d0ba" +path = "ssl/statem/extensions_clnt.c" +function = "tls_parse_stoc_npn" +cve = "CVE-2024-5535" +year = 2024 +license = "Apache-2.0" +relpath = "ssl/statem/extensions_clnt.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "More correctly handle a selected_len of 0 when processing NPN" +commit_url = "https://github.com/openssl/openssl/commit/159921152fd4aa91e4c849fd281ad93ac0d0d0ba" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2024-5535-ssl_select_next_proto" +host = "github" +repo = "openssl/openssl" +parent = "a6facb1042adda2394dc5c98fbceb7625eef141a" +commit = "cf6f91f6121f4db167405db2f0de410a456f260c" +path = "ssl/ssl_lib.c" +function = "SSL_select_next_proto" +cve = "CVE-2024-5535" +year = 2024 +license = "Apache-2.0" +relpath = "ssl/ssl_lib.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Fix SSL_select_next_proto" +commit_url = "https://github.com/openssl/openssl/commit/cf6f91f6121f4db167405db2f0de410a456f260c" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2024-5535-alpn_select_cb" +host = "github" +repo = "openssl/openssl" +parent = "015255851371757d54c2560643eb3b3a88123cf1" +commit = "6cc511826f09e513b4ec066d9b95acaf4f86d991" +path = "ssl/quic/quic_tserver.c" +function = "alpn_select_cb" +cve = "CVE-2024-5535" +year = 2024 +license = "Apache-2.0" +relpath = "ssl/quic/quic_tserver.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Use correctly formatted ALPN data in tserver" +commit_url = "https://github.com/openssl/openssl/commit/6cc511826f09e513b4ec066d9b95acaf4f86d991" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2024-4741" +host = "github" +repo = "openssl/openssl" +parent = "b3f0eb0a295f58f16ba43ba99dad70d4ee5c437d" +commit = "2d05959073c4bf8803401668b9df85931a08e020" +path = "ssl/record/rec_layer_s3.c" +function = "ssl3_read_n" +cve = "CVE-2024-4741" +year = 2024 +license = "Apache-2.0" +relpath = "ssl/record/rec_layer_s3.c" +language = "c" +cwe = "CWE-416" +class = "use after free" +sink = "free" +evidence = "Set rlayer.packet to NULL after we've finished using it" +commit_url = "https://github.com/openssl/openssl/commit/2d05959073c4bf8803401668b9df85931a08e020" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2024-4741-ssl3_release_read_buffer" +host = "github" +repo = "openssl/openssl" +parent = "b3f0eb0a295f58f16ba43ba99dad70d4ee5c437d" +commit = "2d05959073c4bf8803401668b9df85931a08e020" +path = "ssl/record/ssl3_buffer.c" +function = "ssl3_release_read_buffer" +cve = "CVE-2024-4741" +year = 2024 +license = "Apache-2.0" +relpath = "ssl/record/ssl3_buffer.c" +language = "c" +cwe = "CWE-416" +class = "use after free" +sink = "free" +evidence = "Set rlayer.packet to NULL after we've finished using it" +commit_url = "https://github.com/openssl/openssl/commit/2d05959073c4bf8803401668b9df85931a08e020" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2024-4741-ssl_free_buffers" +host = "github" +repo = "openssl/openssl" +parent = "ec559c2a6cca3fd4cedae5c47f2dfa38e5e24865" +commit = "b3f0eb0a295f58f16ba43ba99dad70d4ee5c437d" +path = "ssl/ssl_lib.c" +function = "SSL_free_buffers" +cve = "CVE-2024-4741" +year = 2024 +license = "Apache-2.0" +relpath = "ssl/ssl_lib.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Only free the read buffers if we're not using them" +commit_url = "https://github.com/openssl/openssl/commit/b3f0eb0a295f58f16ba43ba99dad70d4ee5c437d" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2024-4741-tls_release_read_buffer" +host = "github" +repo = "openssl/openssl" +parent = "c88c3de51020c37e8706bf7a682a162593053aac" +commit = "10171e5b511b700c5ecd4fd3e1086b19c34b1ae3" +path = "ssl/record/methods/tls_common.c" +function = "tls_release_read_buffer" +cve = "CVE-2024-4741" +year = 2024 +license = "Apache-2.0" +relpath = "ssl/record/methods/tls_common.c" +language = "c" +cwe = "CWE-416" +class = "use after free" +sink = "free" +evidence = "Set rl->packet to NULL after we've finished using it" +commit_url = "https://github.com/openssl/openssl/commit/10171e5b511b700c5ecd4fd3e1086b19c34b1ae3" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2024-4741-tls_free_buffers" +host = "github" +repo = "openssl/openssl" +parent = "17765d9cefed8b4ada6548719beb98e22672a9bd" +commit = "c88c3de51020c37e8706bf7a682a162593053aac" +path = "ssl/record/methods/tls_common.c" +function = "tls_free_buffers" +cve = "CVE-2024-4741" +year = 2024 +license = "Apache-2.0" +relpath = "ssl/record/methods/tls_common.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Only free the read buffers if we're not using them" +commit_url = "https://github.com/openssl/openssl/commit/c88c3de51020c37e8706bf7a682a162593053aac" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2024-4603" +host = "github" +repo = "openssl/openssl" +parent = "d4b119c567cb5dcaf83add7ca2ea1d646eb3ef9f" +commit = "3559e868e58005d15c6013a0c1fd832e51c73397" +path = "crypto/dsa/dsa_check.c" +function = "ossl_dsa_check_params" +cve = "CVE-2024-4603" +year = 2024 +license = "Apache-2.0" +relpath = "crypto/dsa/dsa_check.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Check DSA parameters for excessive sizes before validating" +commit_url = "https://github.com/openssl/openssl/commit/3559e868e58005d15c6013a0c1fd832e51c73397" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2024-2511" +host = "github" +repo = "openssl/openssl" +parent = "c1e462ee4bd61867ee391fc13110ca41e4889535" +commit = "b52867a9f618bb955bed2a3ce3db4d4f97ed8e5d" +path = "ssl/ssl_lib.c" +function = "ssl_update_cache" +cve = "CVE-2024-2511" +year = 2024 +license = "Apache-2.0" +relpath = "ssl/ssl_lib.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Fix unconstrained session cache growth in TLSv1.3" +commit_url = "https://github.com/openssl/openssl/commit/b52867a9f618bb955bed2a3ce3db4d4f97ed8e5d" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2024-2511-tls_construct_server_hel" +host = "github" +repo = "openssl/openssl" +parent = "c1e462ee4bd61867ee391fc13110ca41e4889535" +commit = "b52867a9f618bb955bed2a3ce3db4d4f97ed8e5d" +path = "ssl/statem/statem_srvr.c" +function = "tls_construct_server_hello" +cve = "CVE-2024-2511" +year = 2024 +license = "Apache-2.0" +relpath = "ssl/statem/statem_srvr.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Fix unconstrained session cache growth in TLSv1.3" +commit_url = "https://github.com/openssl/openssl/commit/b52867a9f618bb955bed2a3ce3db4d4f97ed8e5d" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2024-0727" +host = "github" +repo = "openssl/openssl" +parent = "6c70934a46eaa1734c2efbe9d7baac51c607062e" +commit = "09df4395b5071217b76dc7d3d2e630eb8c5a79c2" +path = "crypto/pkcs12/p12_mutl.c" +function = "pkcs12_gen_mac" +cve = "CVE-2024-0727" +year = 2024 +license = "Apache-2.0" +relpath = "crypto/pkcs12/p12_mutl.c" +language = "c" +cwe = "CWE-476" +class = "null pointer dereference" +sink = "NULL" +evidence = "Add NULL checks where ContentInfo data can be NULL" +commit_url = "https://github.com/openssl/openssl/commit/09df4395b5071217b76dc7d3d2e630eb8c5a79c2" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2024-0727-smime_write_pkcs7" +host = "github" +repo = "openssl/openssl" +parent = "6c70934a46eaa1734c2efbe9d7baac51c607062e" +commit = "09df4395b5071217b76dc7d3d2e630eb8c5a79c2" +path = "crypto/pkcs7/pk7_mime.c" +function = "SMIME_write_PKCS7" +cve = "CVE-2024-0727" +year = 2024 +license = "Apache-2.0" +relpath = "crypto/pkcs7/pk7_mime.c" +language = "c" +cwe = "CWE-476" +class = "null pointer dereference" +sink = "NULL" +evidence = "Add NULL checks where ContentInfo data can be NULL" +commit_url = "https://github.com/openssl/openssl/commit/09df4395b5071217b76dc7d3d2e630eb8c5a79c2" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2023-5363" +host = "github" +repo = "openssl/openssl" +parent = "23d21359e35536a4ee8f7be0b245ddbfac909bff" +commit = "0df40630850fb2740e6be6890bb905d3fc623b2d" +path = "crypto/evp/evp_enc.c" +function = "evp_cipher_init_internal" +cve = "CVE-2023-5363" +year = 2023 +license = "Apache-2.0" +relpath = "crypto/evp/evp_enc.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "evp: process key length and iv length early if present" +commit_url = "https://github.com/openssl/openssl/commit/0df40630850fb2740e6be6890bb905d3fc623b2d" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2023-3817-dh_check" +host = "github" +repo = "openssl/openssl" +parent = "e648db50d9a63f71cab5cb78424c2932d019a744" +commit = "9002fd07327a91f35ba6c1307e71fa6fd4409b7f" +path = "crypto/dh/dh_check.c" +function = "DH_check" +cve = "CVE-2023-3817" +year = 2023 +license = "Apache-2.0" +relpath = "crypto/dh/dh_check.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "DH_check(): Do not try checking q properties if it is obviously invalid" +commit_url = "https://github.com/openssl/openssl/commit/9002fd07327a91f35ba6c1307e71fa6fd4409b7f" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2023-3446" +host = "github" +repo = "openssl/openssl" +parent = "fe824ce0c5d51e7e7cf36c31db6c49c1c0c04a25" +commit = "8780a896543a654e757db1b9396383f9d8095528" +path = "crypto/dh/dh_check.c" +function = "DH_check" +cve = "CVE-2023-3446" +year = 2023 +license = "Apache-2.0" +relpath = "crypto/dh/dh_check.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Fix DH_check() excessive time with over sized modulus" +commit_url = "https://github.com/openssl/openssl/commit/8780a896543a654e757db1b9396383f9d8095528" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2023-2975" +host = "github" +repo = "openssl/openssl" +parent = "175fa8469fc78f6cf35dfb87d26899e60e9ff1d4" +commit = "00e2f5eea29994d19293ec4e8c8775ba73678598" +path = "providers/implementations/ciphers/cipher_aes_siv.c" +function = "siv_cipher" +cve = "CVE-2023-2975" +year = 2023 +license = "Apache-2.0" +relpath = "providers/implementations/ciphers/cipher_aes_siv.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Do not ignore empty associated data with AES-SIV mode" +commit_url = "https://github.com/openssl/openssl/commit/00e2f5eea29994d19293ec4e8c8775ba73678598" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2023-2650" +host = "github" +repo = "openssl/openssl" +parent = "3ca28c9e81fae36b0b44dc39beecd2b5a7561975" +commit = "d63b3e7959e79f98d60760a739f7876dc5adc838" +path = "crypto/objects/obj_dat.c" +function = "OBJ_obj2txt" +cve = "CVE-2023-2650" +year = 2023 +license = "Apache-2.0" +relpath = "crypto/objects/obj_dat.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Restrict the size of OBJECT IDENTIFIERs that OBJ_obj2txt will translate" +commit_url = "https://github.com/openssl/openssl/commit/d63b3e7959e79f98d60760a739f7876dc5adc838" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2022-37454" +host = "github" +repo = "openssl/openssl" +parent = "5d6f13d90d5c4212737002bcd54871cf236a1220" +commit = "d12cde7fc5561d463badcd8a73079cf92864c31e" +path = "providers/implementations/kdfs/hkdf.c" +function = "HKDF_Expand" +cve = "CVE-2022-37454" +year = 2022 +license = "Apache-2.0" +relpath = "providers/implementations/kdfs/hkdf.c" +language = "c" +cwe = "CWE-119" +class = "buffer overflow" +sink = "memcpy" +evidence = "Update hkdf.c to avoid potentially vulnerable code pattern" +commit_url = "https://github.com/openssl/openssl/commit/d12cde7fc5561d463badcd8a73079cf92864c31e" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2022-4304" +host = "github" +repo = "openssl/openssl" +parent = "908eaceb62624f5b5c505b286d904bd3a4e8a64a" +commit = "a00d757d9ca212994625d1a02c81cc5edd27e13b" +path = "crypto/bn/bn_asm.c" +function = "bn_sub_words" +cve = "CVE-2022-4304" +year = 2022 +license = "Apache-2.0" +relpath = "crypto/bn/bn_asm.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Alternative fix for CVE-2022-4304" +commit_url = "https://github.com/openssl/openssl/commit/a00d757d9ca212994625d1a02c81cc5edd27e13b" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2022-4304-bn_blinding_invert_ex" +host = "github" +repo = "openssl/openssl" +parent = "908eaceb62624f5b5c505b286d904bd3a4e8a64a" +commit = "a00d757d9ca212994625d1a02c81cc5edd27e13b" +path = "crypto/bn/bn_blind.c" +function = "BN_BLINDING_invert_ex" +cve = "CVE-2022-4304" +year = 2022 +license = "Apache-2.0" +relpath = "crypto/bn/bn_blind.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Alternative fix for CVE-2022-4304" +commit_url = "https://github.com/openssl/openssl/commit/a00d757d9ca212994625d1a02c81cc5edd27e13b" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2022-4304-rsa_blinding_invert" +host = "github" +repo = "openssl/openssl" +parent = "908eaceb62624f5b5c505b286d904bd3a4e8a64a" +commit = "a00d757d9ca212994625d1a02c81cc5edd27e13b" +path = "crypto/rsa/rsa_ossl.c" +function = "rsa_blinding_invert" +cve = "CVE-2022-4304" +year = 2022 +license = "Apache-2.0" +relpath = "crypto/rsa/rsa_ossl.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Alternative fix for CVE-2022-4304" +commit_url = "https://github.com/openssl/openssl/commit/a00d757d9ca212994625d1a02c81cc5edd27e13b" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2023-0465" +host = "github" +repo = "openssl/openssl" +parent = "f675d164e5d9648c3537a0f5efe1cc2fd232b4a9" +commit = "b013765abfa80036dc779dd0e50602c57bb3bf95" +path = "crypto/x509/x509_vfy.c" +function = "check_policy" +cve = "CVE-2023-0465" +year = 2023 +license = "Apache-2.0" +relpath = "crypto/x509/x509_vfy.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Ensure that EXFLAG_INVALID_POLICY is checked even in leaf certs" +commit_url = "https://github.com/openssl/openssl/commit/b013765abfa80036dc779dd0e50602c57bb3bf95" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2023-0464" +host = "github" +repo = "openssl/openssl" +parent = "969327390220aee7515a4054d5189186402d6687" +commit = "879f7080d7e141f415c79eaa3a8ac4a3dad0348b" +path = "crypto/x509v3/pcy_tree.c" +function = "tree_init" +cve = "CVE-2023-0464" +year = 2023 +license = "Apache-2.0" +relpath = "crypto/x509v3/pcy_tree.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "x509: excessive resource use verifying policy constraints" +commit_url = "https://github.com/openssl/openssl/commit/879f7080d7e141f415c79eaa3a8ac4a3dad0348b" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2023-0464-tree_init" +host = "github" +repo = "openssl/openssl" +parent = "c309c4dce742c3eeb393a0f03f9c567d0e368ccc" +commit = "959c59c7a0164117e7f8366466a32bb1f8d77ff1" +path = "crypto/x509/pcy_tree.c" +function = "tree_init" +cve = "CVE-2023-0464" +year = 2023 +license = "Apache-2.0" +relpath = "crypto/x509/pcy_tree.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "x509: excessive resource use verifying policy constraints" +commit_url = "https://github.com/openssl/openssl/commit/959c59c7a0164117e7f8366466a32bb1f8d77ff1" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2021-3449" +host = "github" +repo = "openssl/openssl" +parent = "7b2625274f5d5ec90aee522ec4e4f3aa08fa5b70" +commit = "2b9e2afc382490592078cdb69d06f54f0fefd4c6" +path = "ssl/record/methods/tls_common.c" +function = "tls_get_more_records" +cve = "CVE-2021-3449" +year = 2021 +license = "OpenSSL License" +relpath = "ssl/record/methods/tls_common.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "fuzz: make post handshake reachable" +commit_url = "https://github.com/openssl/openssl/commit/2b9e2afc382490592078cdb69d06f54f0fefd4c6" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2021-3449-def_generate_session_id" +host = "github" +repo = "openssl/openssl" +parent = "7b2625274f5d5ec90aee522ec4e4f3aa08fa5b70" +commit = "2b9e2afc382490592078cdb69d06f54f0fefd4c6" +path = "ssl/ssl_sess.c" +function = "def_generate_session_id" +cve = "CVE-2021-3449" +year = 2021 +license = "OpenSSL License" +relpath = "ssl/ssl_sess.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "fuzz: make post handshake reachable" +commit_url = "https://github.com/openssl/openssl/commit/2b9e2afc382490592078cdb69d06f54f0fefd4c6" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2021-3449-tls_parse_ctos_renegotia" +host = "github" +repo = "openssl/openssl" +parent = "7b2625274f5d5ec90aee522ec4e4f3aa08fa5b70" +commit = "2b9e2afc382490592078cdb69d06f54f0fefd4c6" +path = "ssl/statem/extensions_srvr.c" +function = "tls_parse_ctos_renegotiate" +cve = "CVE-2021-3449" +year = 2021 +license = "OpenSSL License" +relpath = "ssl/statem/extensions_srvr.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "fuzz: make post handshake reachable" +commit_url = "https://github.com/openssl/openssl/commit/2b9e2afc382490592078cdb69d06f54f0fefd4c6" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2021-3449-tls_process_finished" +host = "github" +repo = "openssl/openssl" +parent = "7b2625274f5d5ec90aee522ec4e4f3aa08fa5b70" +commit = "2b9e2afc382490592078cdb69d06f54f0fefd4c6" +path = "ssl/statem/statem_lib.c" +function = "tls_process_finished" +cve = "CVE-2021-3449" +year = 2021 +license = "OpenSSL License" +relpath = "ssl/statem/statem_lib.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "fuzz: make post handshake reachable" +commit_url = "https://github.com/openssl/openssl/commit/2b9e2afc382490592078cdb69d06f54f0fefd4c6" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2023-0401" +host = "github" +repo = "openssl/openssl" +parent = "7880536fe17c2b5450e279155bedd51771d28c9f" +commit = "6eebe6c0238178356114a96a7858f36b24172847" +path = "crypto/pkcs7/pk7_doit.c" +function = "pkcs7_bio_add_digest" +cve = "CVE-2023-0401" +year = 2023 +license = "Apache-2.0" +relpath = "crypto/pkcs7/pk7_doit.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "pk7_doit.c: Check return of BIO_set_md() calls" +commit_url = "https://github.com/openssl/openssl/commit/6eebe6c0238178356114a96a7858f36b24172847" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2023-0286-general_name_cmp" +host = "github" +repo = "openssl/openssl" +parent = "adf77d6657e836fc87391fad53d857927a764297" +commit = "7880536fe17c2b5450e279155bedd51771d28c9f" +path = "crypto/x509/v3_genn.c" +function = "GENERAL_NAME_cmp" +cve = "CVE-2023-0286" +year = 2023 +license = "Apache-2.0" +relpath = "crypto/x509/v3_genn.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Fix GENERAL_NAME_cmp for x400Address (master)" +commit_url = "https://github.com/openssl/openssl/commit/7880536fe17c2b5450e279155bedd51771d28c9f" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2023-0217" +host = "github" +repo = "openssl/openssl" +parent = "3436f9c24ab90c1661e4798e7944f028d5d251ce" +commit = "bcec03c33cc00a7b5eb89ebeeee59e604570a86a" +path = "crypto/ffc/ffc_key_validate.c" +function = "ossl_ffc_validate_public_key_partial" +cve = "CVE-2023-0217" +year = 2023 +license = "Apache-2.0" +relpath = "crypto/ffc/ffc_key_validate.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Fix NULL deference when validating FFC public key." +commit_url = "https://github.com/openssl/openssl/commit/bcec03c33cc00a7b5eb89ebeeee59e604570a86a" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2023-0216" +host = "github" +repo = "openssl/openssl" +parent = "625faca931957719c76fb16094cf5b6e0debe23f" +commit = "80253dbdc92bec584f4a9866b43f8674156d838a" +path = "crypto/pkcs7/pk7_lib.c" +function = "STACK_OF" +cve = "CVE-2023-0216" +year = 2023 +license = "Apache-2.0" +relpath = "crypto/pkcs7/pk7_lib.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Do not dereference PKCS7 object data if not set" +commit_url = "https://github.com/openssl/openssl/commit/80253dbdc92bec584f4a9866b43f8674156d838a" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2022-4304-rsa_ossl_private_decrypt" +host = "github" +repo = "openssl/openssl" +parent = "e2d0a3b5f559e23f11e4d4687b2889b483afb22a" +commit = "8022a4799fe884b3bf8d538e2b4c4ec323663118" +path = "crypto/rsa/rsa_ossl.c" +function = "rsa_ossl_private_decrypt" +cve = "CVE-2022-4304" +year = 2022 +license = "Apache-2.0" +relpath = "crypto/rsa/rsa_ossl.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Fix Timing Oracle in RSA decryption" +commit_url = "https://github.com/openssl/openssl/commit/8022a4799fe884b3bf8d538e2b4c4ec323663118" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2020-25659" +host = "github" +repo = "openssl/openssl" +parent = "1ca61aa56090356bbdbb16cf48916fbd9886c78d" +commit = "7fc67e0a33102aa47bbaa56533eeecb98c0450f7" +path = "crypto/rsa/rsa_ossl.c" +function = "rsa_ossl_private_decrypt" +cve = "CVE-2020-25659" +year = 2020 +license = "OpenSSL License" +relpath = "crypto/rsa/rsa_ossl.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "rsa: add implicit rejection in PKCS#1 v1.5" +commit_url = "https://github.com/openssl/openssl/commit/7fc67e0a33102aa47bbaa56533eeecb98c0450f7" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2022-3996" +host = "github" +repo = "openssl/openssl" +parent = "9a5c884999a55595e376083b3a165515c8123049" +commit = "7725e7bfe6f2ce8146b6552b44e0d226be7638e7" +path = "crypto/x509/pcy_map.c" +function = "ossl_policy_cache_set_mapping" +cve = "CVE-2022-3996" +year = 2022 +license = "Apache-2.0" +relpath = "crypto/x509/pcy_map.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "x509: fix double locking problem" +commit_url = "https://github.com/openssl/openssl/commit/7725e7bfe6f2ce8146b6552b44e0d226be7638e7" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2022-3786-ossl_punycode_decode" +host = "github" +repo = "openssl/openssl" +parent = "3b421ebc64c7b52f1b9feb3812bdc7781c784332" +commit = "680e65b94c916af259bfdc2e25f1ab6e0c7a97d6" +path = "crypto/punycode.c" +function = "ossl_punycode_decode" +cve = "CVE-2022-3786" +year = 2022 +license = "Apache-2.0" +relpath = "crypto/punycode.c" +language = "c" +cwe = "CWE-119" +class = "buffer overflow" +sink = "memcpy" +evidence = "Fix CVE-2022-3786 in punycode decoder." +commit_url = "https://github.com/openssl/openssl/commit/680e65b94c916af259bfdc2e25f1ab6e0c7a97d6" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2022-3602-ossl_punycode_decode" +host = "github" +repo = "openssl/openssl" +parent = "89d72311327735ef15c804d2adea84a0fb1bfa0a" +commit = "3b421ebc64c7b52f1b9feb3812bdc7781c784332" +path = "crypto/punycode.c" +function = "ossl_punycode_decode" +cve = "CVE-2022-3602" +year = 2022 +license = "Apache-2.0" +relpath = "crypto/punycode.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Fix CVE-2022-3602 in punycode decoder." +commit_url = "https://github.com/openssl/openssl/commit/3b421ebc64c7b52f1b9feb3812bdc7781c784332" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2022-3358" +host = "github" +repo = "openssl/openssl" +parent = "9f0867da4cbf77ed642717b5e703e09ab2c087a0" +commit = "5485c56679d7c49b96e8fc8ca708b0b7e7c03c4b" +path = "crypto/evp/digest.c" +function = "evp_md_init_internal" +cve = "CVE-2022-3358" +year = 2022 +license = "Apache-2.0" +relpath = "crypto/evp/digest.c" +language = "c" +cwe = "CWE-476" +class = "null pointer dereference" +sink = "NULL" +evidence = "Fix usage of custom EVP_CIPHER objects" +commit_url = "https://github.com/openssl/openssl/commit/5485c56679d7c49b96e8fc8ca708b0b7e7c03c4b" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2022-3358-evp_cipher_init_internal" +host = "github" +repo = "openssl/openssl" +parent = "9f0867da4cbf77ed642717b5e703e09ab2c087a0" +commit = "5485c56679d7c49b96e8fc8ca708b0b7e7c03c4b" +path = "crypto/evp/evp_enc.c" +function = "evp_cipher_init_internal" +cve = "CVE-2022-3358" +year = 2022 +license = "Apache-2.0" +relpath = "crypto/evp/evp_enc.c" +language = "c" +cwe = "CWE-476" +class = "null pointer dereference" +sink = "NULL" +evidence = "Fix usage of custom EVP_CIPHER objects" +commit_url = "https://github.com/openssl/openssl/commit/5485c56679d7c49b96e8fc8ca708b0b7e7c03c4b" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2022-2068-hash_dir" +host = "github" +repo = "openssl/openssl" +parent = "abebcec7b1a30fbb1fd5c5cbbe8817690c139163" +commit = "2c9c35870601b4a44d86ddbf512b38df38285cfa" +path = "tools/c_rehash.in" +function = "hash_dir" +cve = "CVE-2022-2068" +year = 2022 +license = "Apache-2.0" +relpath = "tools/c_rehash.in" +language = "perl" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Fix file operations in c_rehash." +commit_url = "https://github.com/openssl/openssl/commit/2c9c35870601b4a44d86ddbf512b38df38285cfa" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2022-29242" +host = "github" +repo = "openssl/openssl" +parent = "3be529cd2eb4eb3eaaa7913af619fb9c918d4581" +commit = "373de40f3f76c63e4f2684abd86706f3863347ca" +path = "ssl/statem/statem_clnt.c" +function = "tls_construct_cke_gost18" +cve = "CVE-2022-29242" +year = 2022 +license = "Apache-2.0" +relpath = "ssl/statem/statem_clnt.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Use safe pattern for buffer size determining in case of GOST key exchange" +commit_url = "https://github.com/openssl/openssl/commit/373de40f3f76c63e4f2684abd86706f3863347ca" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2022-1434" +host = "github" +repo = "openssl/openssl" +parent = "55c80c222293a972587004c185dc5653ae207a0e" +commit = "7d56a74a96828985db7354a55227a511615f732b" +path = "providers/implementations/ciphers/cipher_rc4_hmac_md5.c" +function = "rc4_hmac_md5_set_ctx_params" +cve = "CVE-2022-1434" +year = 2022 +license = "Apache-2.0" +relpath = "providers/implementations/ciphers/cipher_rc4_hmac_md5.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Fix the RC4-MD5 cipher" +commit_url = "https://github.com/openssl/openssl/commit/7d56a74a96828985db7354a55227a511615f732b" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2022-1343" +host = "github" +repo = "openssl/openssl" +parent = "ae3ece03a61e8822fd7ea58f44812871efba82d1" +commit = "2eda98790c5c2741d76d23cc1e74b0dc4f4b391a" +path = "crypto/ocsp/ocsp_vfy.c" +function = "ocsp_verify_signer" +cve = "CVE-2022-1343" +year = 2022 +license = "Apache-2.0" +relpath = "crypto/ocsp/ocsp_vfy.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Fix OCSP_basic_verify signer certificate validation" +commit_url = "https://github.com/openssl/openssl/commit/2eda98790c5c2741d76d23cc1e74b0dc4f4b391a" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2021-4044" +host = "github" +repo = "openssl/openssl" +parent = "758754966791c537ea95241438454aa86f91f256" +commit = "d69ae8a93bfc0f2489c008fcf303a98d77a6df4d" +path = "crypto/x509/x509_vfy.c" +function = "has_san_id" +cve = "CVE-2021-4044" +year = 2021 +license = "OpenSSL License" +relpath = "crypto/x509/x509_vfy.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Fix infinite verification loops due to has_san_id" +commit_url = "https://github.com/openssl/openssl/commit/d69ae8a93bfc0f2489c008fcf303a98d77a6df4d" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2021-4044-tls_post_process_server_" +host = "github" +repo = "openssl/openssl" +parent = "8e78289c4e6f4c9f2fec073b78443736e689854d" +commit = "758754966791c537ea95241438454aa86f91f256" +path = "ssl/statem/statem_clnt.c" +function = "tls_post_process_server_certificate" +cve = "CVE-2021-4044" +year = 2021 +license = "OpenSSL License" +relpath = "ssl/statem/statem_clnt.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Fix invalid handling of verify errors in libssl" +commit_url = "https://github.com/openssl/openssl/commit/758754966791c537ea95241438454aa86f91f256" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2021-3711-sm2_asym_decrypt" +host = "github" +repo = "openssl/openssl" +parent = "4b8a8bb75229b64d1c7598d845fdc3c7e7d7eee2" +commit = "36cf45ef3ba71e44a8be06ee81cb31aa02cb0010" +path = "providers/implementations/asymciphers/sm2_enc.c" +function = "sm2_asym_decrypt" +cve = "CVE-2021-3711" +year = 2021 +license = "OpenSSL License" +relpath = "providers/implementations/asymciphers/sm2_enc.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Correctly calculate the length of SM2 plaintext given the ciphertext" +commit_url = "https://github.com/openssl/openssl/commit/36cf45ef3ba71e44a8be06ee81cb31aa02cb0010" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2021-3712-netscape_spki_print" +host = "github" +repo = "openssl/openssl" +parent = "98624776c4d501c8badd6f772ab7048ac9191cb9" +commit = "7c038a6bcd98d4bbfd2c2892a87a1138d2f7c5f3" +path = "crypto/asn1/t_spki.c" +function = "NETSCAPE_SPKI_print" +cve = "CVE-2021-3712" +year = 2021 +license = "OpenSSL License" +relpath = "crypto/asn1/t_spki.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Fix NETSCAPE_SPKI_print function to not assume NUL terminated strings" +commit_url = "https://github.com/openssl/openssl/commit/7c038a6bcd98d4bbfd2c2892a87a1138d2f7c5f3" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2021-3712-append_ia5" +host = "github" +repo = "openssl/openssl" +parent = "1f365708a3318a5f1a395f90c38b584a58d37fb9" +commit = "98624776c4d501c8badd6f772ab7048ac9191cb9" +path = "crypto/x509/v3_utl.c" +function = "append_ia5" +cve = "CVE-2021-3712" +year = 2021 +license = "OpenSSL License" +relpath = "crypto/x509/v3_utl.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Fix append_ia5 function to not assume NUL terminated strings" +commit_url = "https://github.com/openssl/openssl/commit/98624776c4d501c8badd6f772ab7048ac9191cb9" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2021-3712-ossl_cmp_hdr_push1_freet" +host = "github" +repo = "openssl/openssl" +parent = "d2015a783e64613d8e4a142fa05048d1863df944" +commit = "95f8c1e142df835d03b5b62521383a462fc5470d" +path = "crypto/cmp/cmp_hdr.c" +function = "ossl_cmp_hdr_push1_freeText" +cve = "CVE-2021-3712" +year = 2021 +license = "OpenSSL License" +relpath = "crypto/cmp/cmp_hdr.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Fix CMP code to not assume NUL terminated strings" +commit_url = "https://github.com/openssl/openssl/commit/95f8c1e142df835d03b5b62521383a462fc5470d" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2021-3712-ia5ncasecmp" +host = "github" +repo = "openssl/openssl" +parent = "918430ba80d94ec8f05383b43b1872b1ebb13e1a" +commit = "d2015a783e64613d8e4a142fa05048d1863df944" +path = "crypto/x509/v3_ncons.c" +function = "ia5ncasecmp" +cve = "CVE-2021-3712" +year = 2021 +license = "OpenSSL License" +relpath = "crypto/x509/v3_ncons.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Fix the name constraints code to not assume NUL terminated strings" +commit_url = "https://github.com/openssl/openssl/commit/d2015a783e64613d8e4a142fa05048d1863df944" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2021-3712-i2r_pci" +host = "github" +repo = "openssl/openssl" +parent = "b2b3b9c9936b91315adc0f3254879cb2fd5ca2bd" +commit = "918430ba80d94ec8f05383b43b1872b1ebb13e1a" +path = "crypto/x509/v3_pci.c" +function = "i2r_pci" +cve = "CVE-2021-3712" +year = 2021 +license = "OpenSSL License" +relpath = "crypto/x509/v3_pci.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Fix printing of PROXY_CERT_INFO_EXTENSION to not assume NUL terminated strings" +commit_url = "https://github.com/openssl/openssl/commit/918430ba80d94ec8f05383b43b1872b1ebb13e1a" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2021-3712-general_name_print" +host = "github" +repo = "openssl/openssl" +parent = "1747d4658b3830951068a6a6c1fa2b45c4731fb3" +commit = "b2b3b9c9936b91315adc0f3254879cb2fd5ca2bd" +path = "crypto/x509/v3_san.c" +function = "GENERAL_NAME_print" +cve = "CVE-2021-3712" +year = 2021 +license = "OpenSSL License" +relpath = "crypto/x509/v3_san.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Fix GENERAL_NAME_print to not assume NUL terminated strings" +commit_url = "https://github.com/openssl/openssl/commit/b2b3b9c9936b91315adc0f3254879cb2fd5ca2bd" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2021-3712-print_qualifiers" +host = "github" +repo = "openssl/openssl" +parent = "ad6ac17489241574136b7d035f01f6175dd9c941" +commit = "1747d4658b3830951068a6a6c1fa2b45c4731fb3" +path = "crypto/x509/v3_cpols.c" +function = "print_qualifiers" +cve = "CVE-2021-3712" +year = 2021 +license = "OpenSSL License" +relpath = "crypto/x509/v3_cpols.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Fix POLICYINFO printing to not assume NUL terminated strings" +commit_url = "https://github.com/openssl/openssl/commit/1747d4658b3830951068a6a6c1fa2b45c4731fb3" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2021-3711-pkey_sm2_decrypt" +host = "github" +repo = "openssl/openssl" +parent = "8c74c9d1ade0fbdab5b815ddb747351b8b839641" +commit = "59f5e75f3bced8fc0e130d72a3f582cf7b480b46" +path = "crypto/sm2/sm2_pmeth.c" +function = "pkey_sm2_decrypt" +cve = "CVE-2021-3711" +year = 2021 +license = "OpenSSL License" +relpath = "crypto/sm2/sm2_pmeth.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Correctly calculate the length of SM2 plaintext given the ciphertext" +commit_url = "https://github.com/openssl/openssl/commit/59f5e75f3bced8fc0e130d72a3f582cf7b480b46" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2021-3449-ssl_generate_master_secr" +host = "github" +repo = "openssl/openssl" +parent = "02b1636fe3db274497304a3e95a4e32ced7e841b" +commit = "39a140597d874e554b736885ac4dea16ac40a87a" +path = "ssl/s3_lib.c" +function = "ssl_generate_master_secret" +cve = "CVE-2021-3449" +year = 2021 +license = "OpenSSL License" +relpath = "ssl/s3_lib.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Ensure buffer/length pairs are always in sync" +commit_url = "https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2021-3449-ssl_ctx_set_alpn_protos" +host = "github" +repo = "openssl/openssl" +parent = "02b1636fe3db274497304a3e95a4e32ced7e841b" +commit = "39a140597d874e554b736885ac4dea16ac40a87a" +path = "ssl/ssl_lib.c" +function = "SSL_CTX_set_alpn_protos" +cve = "CVE-2021-3449" +year = 2021 +license = "OpenSSL License" +relpath = "ssl/ssl_lib.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Ensure buffer/length pairs are always in sync" +commit_url = "https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2021-3449-init_sig_algs_cert" +host = "github" +repo = "openssl/openssl" +parent = "02b1636fe3db274497304a3e95a4e32ced7e841b" +commit = "39a140597d874e554b736885ac4dea16ac40a87a" +path = "ssl/statem/extensions.c" +function = "init_sig_algs_cert" +cve = "CVE-2021-3449" +year = 2021 +license = "OpenSSL License" +relpath = "ssl/statem/extensions.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Ensure buffer/length pairs are always in sync" +commit_url = "https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2021-3449-tls_construct_ctos_early" +host = "github" +repo = "openssl/openssl" +parent = "02b1636fe3db274497304a3e95a4e32ced7e841b" +commit = "39a140597d874e554b736885ac4dea16ac40a87a" +path = "ssl/statem/extensions_clnt.c" +function = "tls_construct_ctos_early_data" +cve = "CVE-2021-3449" +year = 2021 +license = "OpenSSL License" +relpath = "ssl/statem/extensions_clnt.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Ensure buffer/length pairs are always in sync" +commit_url = "https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2021-3449-tls_process_certificate_" +host = "github" +repo = "openssl/openssl" +parent = "02b1636fe3db274497304a3e95a4e32ced7e841b" +commit = "39a140597d874e554b736885ac4dea16ac40a87a" +path = "ssl/statem/statem_clnt.c" +function = "tls_process_certificate_request" +cve = "CVE-2021-3449" +year = 2021 +license = "OpenSSL License" +relpath = "ssl/statem/statem_clnt.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Ensure buffer/length pairs are always in sync" +commit_url = "https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2021-3449-tls_handle_alpn" +host = "github" +repo = "openssl/openssl" +parent = "02b1636fe3db274497304a3e95a4e32ced7e841b" +commit = "39a140597d874e554b736885ac4dea16ac40a87a" +path = "ssl/statem/statem_srvr.c" +function = "tls_handle_alpn" +cve = "CVE-2021-3449" +year = 2021 +license = "OpenSSL License" +relpath = "ssl/statem/statem_srvr.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Ensure buffer/length pairs are always in sync" +commit_url = "https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2021-3449-init_sig_algs" +host = "github" +repo = "openssl/openssl" +parent = "112580c27b829b0ac0874d5c5787195f27c7952c" +commit = "02b1636fe3db274497304a3e95a4e32ced7e841b" +path = "ssl/statem/extensions.c" +function = "init_sig_algs" +cve = "CVE-2021-3449" +year = 2021 +license = "OpenSSL License" +relpath = "ssl/statem/extensions.c" +language = "c" +cwe = "CWE-476" +class = "null pointer dereference" +sink = "NULL" +evidence = "ssl sigalg extension: fix NULL pointer dereference" +commit_url = "https://github.com/openssl/openssl/commit/02b1636fe3db274497304a3e95a4e32ced7e841b" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2021-3450" +host = "github" +repo = "openssl/openssl" +parent = "cfd74383d9b06f85cb1e166180346115a3f9a452" +commit = "2a40b7bc7b94dd7de897a74571e7024f0cf0d63b" +path = "crypto/x509/x509_vfy.c" +function = "check_chain_extensions" +cve = "CVE-2021-3450" +year = 2021 +license = "OpenSSL License" +relpath = "crypto/x509/x509_vfy.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "check_chain_extensions: Do not override error return value by check_curve" +commit_url = "https://github.com/openssl/openssl/commit/2a40b7bc7b94dd7de897a74571e7024f0cf0d63b" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2021-23840-evp_encryptdecryptupdate" +host = "github" +repo = "openssl/openssl" +parent = "481a88f13c44996a008195791ea0dc076b968774" +commit = "6a51b9e1d0cf0bf8515f7201b68fb0a3482b3dc1" +path = "crypto/evp/evp_enc.c" +function = "evp_EncryptDecryptUpdate" +cve = "CVE-2021-23840" +year = 2021 +license = "OpenSSL License" +relpath = "crypto/evp/evp_enc.c" +language = "c" +cwe = "CWE-119" +class = "buffer overflow" +sink = "memcpy" +evidence = "Don't overflow the output length in EVP_CipherUpdate calls" +commit_url = "https://github.com/openssl/openssl/commit/6a51b9e1d0cf0bf8515f7201b68fb0a3482b3dc1" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2021-23841" +host = "github" +repo = "openssl/openssl" +parent = "c8c6e7438c03b2fc24e7ead460feeaef04911fb4" +commit = "122a19ab48091c657f7cb1fb3af9fc07bd557bbf" +path = "crypto/x509/x509_cmp.c" +function = "X509_issuer_and_serial_hash" +cve = "CVE-2021-23841" +year = 2021 +license = "OpenSSL License" +relpath = "crypto/x509/x509_cmp.c" +language = "c" +cwe = "CWE-476" +class = "null pointer dereference" +sink = "NULL" +evidence = "Fix Null pointer deref in X509_issuer_and_serial_hash()" +commit_url = "https://github.com/openssl/openssl/commit/122a19ab48091c657f7cb1fb3af9fc07bd557bbf" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2020-1971-general_name_cmp" +host = "github" +repo = "openssl/openssl" +parent = "aa0ad2011d3e7ad8a611da274ef7d9c7706e289b" +commit = "f960d81215ebf3f65e03d4d5d857fb9b666d6920" +path = "crypto/x509v3/v3_genn.c" +function = "GENERAL_NAME_cmp" +cve = "CVE-2020-1971" +year = 2020 +license = "OpenSSL License" +relpath = "crypto/x509v3/v3_genn.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Correctly compare EdiPartyName in GENERAL_NAME_cmp()" +commit_url = "https://github.com/openssl/openssl/commit/f960d81215ebf3f65e03d4d5d857fb9b666d6920" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "openssl-cve-2020-1967-tls1_check_sig_alg" +host = "github" +repo = "openssl/openssl" +parent = "3656c08ab4b1b892730cb5e808b6f4298b08a2e6" +commit = "a87f3fe01a5a894aa27ccd6a239155fd129988e4" +path = "ssl/t1_lib.c" +function = "tls1_check_sig_alg" +cve = "CVE-2020-1967" +year = 2020 +license = "OpenSSL License" +relpath = "ssl/t1_lib.c" +language = "c" +cwe = "CWE-476" +class = "null pointer dereference" +sink = "NULL" +evidence = "Fix NULL dereference in SSL_check_chain() for TLS 1.3" +commit_url = "https://github.com/openssl/openssl/commit/a87f3fe01a5a894aa27ccd6a239155fd129988e4" +origin = "openssl" +project = "openssl" + +[[recipe]] +name = "curl-cve-2026-9080" +host = "github" +repo = "curl/curl" +parent = "f746780a1e548b4b93790b58d70c3b22fde5360d" +commit = "e9a2b0dc72dd3a9aa3a5210e89079a3b719475dc" +path = "lib/multi_ev.c" +function = "mev_forget_socket" +cve = "CVE-2026-9080" +year = 2026 +license = "curl" +relpath = "lib/multi_ev.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "multi_ev: refresh sock entry after remove callback" +commit_url = "https://github.com/curl/curl/commit/e9a2b0dc72dd3a9aa3a5210e89079a3b719475dc" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2023-38545-do_socks5" +host = "github" +repo = "curl/curl" +parent = "09e25b9d94f4106eac8ca3a43b221bdc66f405e4" +commit = "fb4415d8aee6c1045be932a34fe6107c2f5ed147" +path = "lib/socks.c" +function = "do_SOCKS5" +cve = "CVE-2023-38545" +year = 2023 +license = "curl" +relpath = "lib/socks.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "socks: return error if hostname too long for remote resolve" +commit_url = "https://github.com/curl/curl/commit/fb4415d8aee6c1045be932a34fe6107c2f5ed147" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2022-32207" +host = "github" +repo = "curl/curl" +parent = "46f8911d3942dc06fdd67e9f6f3908982e5d2fb4" +commit = "20f9dd6bae50b7223171b17ba7798946e74f877f" +path = "lib/cookie.c" +function = "cookie_output" +cve = "CVE-2022-32207" +year = 2022 +license = "curl" +relpath = "lib/cookie.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "fopen: add Curl_fopen() for better overwriting of files" +commit_url = "https://github.com/curl/curl/commit/20f9dd6bae50b7223171b17ba7798946e74f877f" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2022-32206" +host = "github" +repo = "curl/curl" +parent = "6ecdf5136b52af747e7bda08db9a748256b1cd09" +commit = "3a09fbb7f264c67c438d01a30669ce325aa508e2" +path = "lib/content_encoding.c" +function = "Curl_build_unencoding_stack" +cve = "CVE-2022-32206" +year = 2022 +license = "curl" +relpath = "lib/content_encoding.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "content_encoding: return error on too many compression steps" +commit_url = "https://github.com/curl/curl/commit/3a09fbb7f264c67c438d01a30669ce325aa508e2" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2022-32208" +host = "github" +repo = "curl/curl" +parent = "2b67a0a1129b20a56ed04859fec8999f5c0c4280" +commit = "6ecdf5136b52af747e7bda08db9a748256b1cd09" +path = "lib/krb5.c" +function = "read_data" +cve = "CVE-2022-32208" +year = 2022 +license = "curl" +relpath = "lib/krb5.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "krb5: return error properly on decode errors" +commit_url = "https://github.com/curl/curl/commit/6ecdf5136b52af747e7bda08db9a748256b1cd09" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2022-27782-curl_init_userdefined" +host = "github" +repo = "curl/curl" +parent = "7e92d12b4e6911f424678a133b19de670e183a59" +commit = "f18af4f874cecab82a9797e8c7541e0990c7a64c" +path = "lib/url.c" +function = "Curl_init_userdefined" +cve = "CVE-2022-27782" +year = 2022 +license = "curl" +relpath = "lib/url.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "tls: check more TLS details for connection reuse" +commit_url = "https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2022-27782-gtls_shutdown" +host = "github" +repo = "curl/curl" +parent = "7e92d12b4e6911f424678a133b19de670e183a59" +commit = "f18af4f874cecab82a9797e8c7541e0990c7a64c" +path = "lib/vtls/gtls.c" +function = "gtls_shutdown" +cve = "CVE-2022-27782" +year = 2022 +license = "curl" +relpath = "lib/vtls/gtls.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "tls: check more TLS details for connection reuse" +commit_url = "https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2022-27782-nss_setup_connect" +host = "github" +repo = "curl/curl" +parent = "7e92d12b4e6911f424678a133b19de670e183a59" +commit = "f18af4f874cecab82a9797e8c7541e0990c7a64c" +path = "lib/vtls/nss.c" +function = "nss_setup_connect" +cve = "CVE-2022-27782" +year = 2022 +license = "curl" +relpath = "lib/vtls/nss.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "tls: check more TLS details for connection reuse" +commit_url = "https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2022-27782-ossl_connect_step1" +host = "github" +repo = "curl/curl" +parent = "7e92d12b4e6911f424678a133b19de670e183a59" +commit = "f18af4f874cecab82a9797e8c7541e0990c7a64c" +path = "lib/vtls/openssl.c" +function = "ossl_connect_step1" +cve = "CVE-2022-27782" +year = 2022 +license = "curl" +relpath = "lib/vtls/openssl.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "tls: check more TLS details for connection reuse" +commit_url = "https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2022-27782-curl_free_primary_ssl_co" +host = "github" +repo = "curl/curl" +parent = "7e92d12b4e6911f424678a133b19de670e183a59" +commit = "f18af4f874cecab82a9797e8c7541e0990c7a64c" +path = "lib/vtls/vtls.c" +function = "Curl_free_primary_ssl_config" +cve = "CVE-2022-27782" +year = 2022 +license = "curl" +relpath = "lib/vtls/vtls.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "tls: check more TLS details for connection reuse" +commit_url = "https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2022-27778" +host = "github" +repo = "curl/curl" +parent = "fae6fea209a2d4db1582f608bd8cc8000721733a" +commit = "8c7ee9083d0d719d0a77ab20d9cc2ae84eeea7f3" +path = "src/tool_operate.c" +function = "post_per_transfer" +cve = "CVE-2022-27778" +year = 2022 +license = "curl" +relpath = "src/tool_operate.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "post_per_transfer: remove the updated file name" +commit_url = "https://github.com/curl/curl/commit/8c7ee9083d0d719d0a77ab20d9cc2ae84eeea7f3" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2022-30115" +host = "github" +repo = "curl/curl" +parent = "ff3ee510c328db03bf171cae6179bb9463fb054f" +commit = "fae6fea209a2d4db1582f608bd8cc8000721733a" +path = "lib/hsts.c" +function = "hsts_create" +cve = "CVE-2022-30115" +year = 2022 +license = "curl" +relpath = "lib/hsts.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "hsts: ignore trailing dots when comparing hosts names" +commit_url = "https://github.com/curl/curl/commit/fae6fea209a2d4db1582f608bd8cc8000721733a" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2022-27780" +host = "github" +repo = "curl/curl" +parent = "5c7da89d404bf59c8dd82a001119a16d18365917" +commit = "914aaab9153764ef8fa4178215b8ad89d3ac263a" +path = "lib/urlapi.c" +function = "hostname_check" +cve = "CVE-2022-27780" +year = 2022 +license = "curl" +relpath = "lib/urlapi.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "urlapi: reject percent-decoding host name into separator bytes" +commit_url = "https://github.com/curl/curl/commit/914aaab9153764ef8fa4178215b8ad89d3ac263a" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2022-27774" +host = "github" +repo = "curl/curl" +parent = "08b8ef4e726ba10f45081ecda5b3cea788d3c839" +commit = "620ea21410030a9977396b4661806bc187231b79" +path = "lib/transfer.c" +function = "Curl_follow" +cve = "CVE-2022-27774" +year = 2022 +license = "curl" +relpath = "lib/transfer.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "transfer: redirects to other protocols or ports clear auth" +commit_url = "https://github.com/curl/curl/commit/620ea21410030a9977396b4661806bc187231b79" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2022-27776" +host = "github" +repo = "curl/curl" +parent = "8f2079154f80561ccffcaa954268798b658e66b6" +commit = "6e659993952aa5f90f48864be84a1bbb047fc258" +path = "lib/http.c" +function = "Curl_add_custom_headers" +cve = "CVE-2022-27776" +year = 2022 +license = "curl" +relpath = "lib/http.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "http: avoid auth/cookie on redirects same host diff port" +commit_url = "https://github.com/curl/curl/commit/6e659993952aa5f90f48864be84a1bbb047fc258" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2022-27775" +host = "github" +repo = "curl/curl" +parent = "852aa5ad351ea53e5f01d2f44b5b4370c2bf5425" +commit = "058f98dc3fe595f21dc26a5b9b1699e519ba5705" +path = "lib/conncache.c" +function = "hashkey" +cve = "CVE-2022-27775" +year = 2022 +license = "curl" +relpath = "lib/conncache.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "conncache: include the zone id in the \"bundle\" hashkey" +commit_url = "https://github.com/curl/curl/commit/058f98dc3fe595f21dc26a5b9b1699e519ba5705" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2022-22576-conn_free" +host = "github" +repo = "curl/curl" +parent = "ff2f3e836702daa82e2356195482fcc95f4257dc" +commit = "852aa5ad351ea53e5f01d2f44b5b4370c2bf5425" +path = "lib/url.c" +function = "conn_free" +cve = "CVE-2022-22576" +year = 2022 +license = "curl" +relpath = "lib/url.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "url: check sasl additional parameters for connection reuse." +commit_url = "https://github.com/curl/curl/commit/852aa5ad351ea53e5f01d2f44b5b4370c2bf5425" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2021-22947" +host = "github" +repo = "curl/curl" +parent = "364f174724ef115c63d5e5dc1d3342c8a43b1cca" +commit = "8ef147c43646e91fdaad5d0e7b60351f842e5c68" +path = "lib/ftp.c" +function = "ftp_statemachine" +cve = "CVE-2021-22947" +year = 2021 +license = "curl" +relpath = "lib/ftp.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "ftp,imap,pop3,smtp: reject STARTTLS server response pipelining" +commit_url = "https://github.com/curl/curl/commit/8ef147c43646e91fdaad5d0e7b60351f842e5c68" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2021-22947-imap_state_starttls_resp" +host = "github" +repo = "curl/curl" +parent = "364f174724ef115c63d5e5dc1d3342c8a43b1cca" +commit = "8ef147c43646e91fdaad5d0e7b60351f842e5c68" +path = "lib/imap.c" +function = "imap_state_starttls_resp" +cve = "CVE-2021-22947" +year = 2021 +license = "curl" +relpath = "lib/imap.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "ftp,imap,pop3,smtp: reject STARTTLS server response pipelining" +commit_url = "https://github.com/curl/curl/commit/8ef147c43646e91fdaad5d0e7b60351f842e5c68" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2021-22947-pop3_state_starttls_resp" +host = "github" +repo = "curl/curl" +parent = "364f174724ef115c63d5e5dc1d3342c8a43b1cca" +commit = "8ef147c43646e91fdaad5d0e7b60351f842e5c68" +path = "lib/pop3.c" +function = "pop3_state_starttls_resp" +cve = "CVE-2021-22947" +year = 2021 +license = "curl" +relpath = "lib/pop3.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "ftp,imap,pop3,smtp: reject STARTTLS server response pipelining" +commit_url = "https://github.com/curl/curl/commit/8ef147c43646e91fdaad5d0e7b60351f842e5c68" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2021-22947-smtp_state_starttls_resp" +host = "github" +repo = "curl/curl" +parent = "364f174724ef115c63d5e5dc1d3342c8a43b1cca" +commit = "8ef147c43646e91fdaad5d0e7b60351f842e5c68" +path = "lib/smtp.c" +function = "smtp_state_starttls_resp" +cve = "CVE-2021-22947" +year = 2021 +license = "curl" +relpath = "lib/smtp.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "ftp,imap,pop3,smtp: reject STARTTLS server response pipelining" +commit_url = "https://github.com/curl/curl/commit/8ef147c43646e91fdaad5d0e7b60351f842e5c68" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2021-22946" +host = "github" +repo = "curl/curl" +parent = "43157490a5054bd24256fe12876931e8abc9df49" +commit = "364f174724ef115c63d5e5dc1d3342c8a43b1cca" +path = "lib/ftp.c" +function = "ftp_statemachine" +cve = "CVE-2021-22946" +year = 2021 +license = "curl" +relpath = "lib/ftp.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "ftp,imap,pop3: do not ignore --ssl-reqd" +commit_url = "https://github.com/curl/curl/commit/364f174724ef115c63d5e5dc1d3342c8a43b1cca" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2021-22946-imap_state_capability_re" +host = "github" +repo = "curl/curl" +parent = "43157490a5054bd24256fe12876931e8abc9df49" +commit = "364f174724ef115c63d5e5dc1d3342c8a43b1cca" +path = "lib/imap.c" +function = "imap_state_capability_resp" +cve = "CVE-2021-22946" +year = 2021 +license = "curl" +relpath = "lib/imap.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "ftp,imap,pop3: do not ignore --ssl-reqd" +commit_url = "https://github.com/curl/curl/commit/364f174724ef115c63d5e5dc1d3342c8a43b1cca" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2021-22946-pop3_state_capa_resp" +host = "github" +repo = "curl/curl" +parent = "43157490a5054bd24256fe12876931e8abc9df49" +commit = "364f174724ef115c63d5e5dc1d3342c8a43b1cca" +path = "lib/pop3.c" +function = "pop3_state_capa_resp" +cve = "CVE-2021-22946" +year = 2021 +license = "curl" +relpath = "lib/pop3.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "ftp,imap,pop3: do not ignore --ssl-reqd" +commit_url = "https://github.com/curl/curl/commit/364f174724ef115c63d5e5dc1d3342c8a43b1cca" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2021-22945" +host = "github" +repo = "curl/curl" +parent = "409a4412409371db00af0a3fe987e517bfab3d19" +commit = "43157490a5054bd24256fe12876931e8abc9df49" +path = "lib/mqtt.c" +function = "mqtt_send" +cve = "CVE-2021-22945" +year = 2021 +license = "curl" +relpath = "lib/mqtt.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "mqtt: clear the leftovers pointer when sending succeeds" +commit_url = "https://github.com/curl/curl/commit/43157490a5054bd24256fe12876931e8abc9df49" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2021-22924" +host = "github" +repo = "curl/curl" +parent = "fd9b40bf8dfd43edcbc0d254d613d95a11061c05" +commit = "5ea3145850ebff1dc2b13d17440300a01ca38161" +path = "lib/url.c" +function = "create_conn" +cve = "CVE-2021-22924" +year = 2021 +license = "curl" +relpath = "lib/url.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "vtls: fix connection reuse checks for issuer cert and case sensitivity" +commit_url = "https://github.com/curl/curl/commit/5ea3145850ebff1dc2b13d17440300a01ca38161" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2021-22924-nss_do_connect" +host = "github" +repo = "curl/curl" +parent = "fd9b40bf8dfd43edcbc0d254d613d95a11061c05" +commit = "5ea3145850ebff1dc2b13d17440300a01ca38161" +path = "lib/vtls/nss.c" +function = "nss_do_connect" +cve = "CVE-2021-22924" +year = 2021 +license = "curl" +relpath = "lib/vtls/nss.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "vtls: fix connection reuse checks for issuer cert and case sensitivity" +commit_url = "https://github.com/curl/curl/commit/5ea3145850ebff1dc2b13d17440300a01ca38161" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2021-22924-servercert" +host = "github" +repo = "curl/curl" +parent = "fd9b40bf8dfd43edcbc0d254d613d95a11061c05" +commit = "5ea3145850ebff1dc2b13d17440300a01ca38161" +path = "lib/vtls/openssl.c" +function = "servercert" +cve = "CVE-2021-22924" +year = 2021 +license = "curl" +relpath = "lib/vtls/openssl.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "vtls: fix connection reuse checks for issuer cert and case sensitivity" +commit_url = "https://github.com/curl/curl/commit/5ea3145850ebff1dc2b13d17440300a01ca38161" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2021-22925" +host = "github" +repo = "curl/curl" +parent = "12284e008bad5156b67d0ac253331a96d77201d1" +commit = "894f6ec730597eb243618d33cc84d71add8d6a8a" +path = "lib/telnet.c" +function = "suboption" +cve = "CVE-2021-22925" +year = 2021 +license = "curl" +relpath = "lib/telnet.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "telnet: fix option parser to not send uninitialized contents" +commit_url = "https://github.com/curl/curl/commit/894f6ec730597eb243618d33cc84d71add8d6a8a" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2021-22901-ossl_connect_step1" +host = "github" +repo = "curl/curl" +parent = "39ce47f219b09c380b81f89fe54ac586c8db6bde" +commit = "7f4a9a9b2a49547eae24d2e19bc5c346e9026479" +path = "lib/vtls/openssl.c" +function = "ossl_connect_step1" +cve = "CVE-2021-22901" +year = 2021 +license = "curl" +relpath = "lib/vtls/openssl.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "openssl: associate/detach the transfer from connection" +commit_url = "https://github.com/curl/curl/commit/7f4a9a9b2a49547eae24d2e19bc5c346e9026479" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2021-22898" +host = "github" +repo = "curl/curl" +parent = "bbb71507b7bab52002f9b1e0880bed6a32834511" +commit = "39ce47f219b09c380b81f89fe54ac586c8db6bde" +path = "lib/telnet.c" +function = "suboption" +cve = "CVE-2021-22898" +year = 2021 +license = "curl" +relpath = "lib/telnet.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "telnet: check sscanf() for correct number of matches" +commit_url = "https://github.com/curl/curl/commit/39ce47f219b09c380b81f89fe54ac586c8db6bde" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2021-22890" +host = "github" +repo = "curl/curl" +parent = "7214288898f5625a6cc196e22a74232eada7861c" +commit = "b09c8ee15771c614c4bf3ddac893cdb12187c844" +path = "lib/vtls/bearssl.c" +function = "bearssl_connect_step1" +cve = "CVE-2021-22890" +year = 2021 +license = "curl" +relpath = "lib/vtls/bearssl.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "vtls: add 'isproxy' argument to Curl_ssl_get/addsessionid()" +commit_url = "https://github.com/curl/curl/commit/b09c8ee15771c614c4bf3ddac893cdb12187c844" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2021-22876" +host = "github" +repo = "curl/curl" +parent = "184ffc0bdfcab17eb96d1dd64f9c0cecc139e3e9" +commit = "7214288898f5625a6cc196e22a74232eada7861c" +path = "lib/transfer.c" +function = "Curl_follow" +cve = "CVE-2021-22876" +year = 2021 +license = "curl" +relpath = "lib/transfer.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "transfer: strip credentials from the auto-referer header field" +commit_url = "https://github.com/curl/curl/commit/7214288898f5625a6cc196e22a74232eada7861c" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2020-8286" +host = "github" +repo = "curl/curl" +parent = "69a358f2186e04cf44698b5100332cbf1ee7f01d" +commit = "d9d01672785b8ac04aab1abb6de95fe3072ae199" +path = "lib/vtls/openssl.c" +function = "verifystatus" +cve = "CVE-2020-8286" +year = 2020 +license = "curl" +relpath = "lib/vtls/openssl.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "openssl: make the OCSP verification verify the certificate id" +commit_url = "https://github.com/curl/curl/commit/d9d01672785b8ac04aab1abb6de95fe3072ae199" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2020-8284" +host = "github" +repo = "curl/curl" +parent = "abd846c374c5269809ce11740754bc6f00a0b193" +commit = "ec9cc725d598ac77de7b6df8afeec292b3c8ad46" +path = "lib/url.c" +function = "Curl_init_userdefined" +cve = "CVE-2020-8284" +year = 2020 +license = "curl" +relpath = "lib/url.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "ftp: CURLOPT_FTP_SKIP_PASV_IP by default" +commit_url = "https://github.com/curl/curl/commit/ec9cc725d598ac77de7b6df8afeec292b3c8ad46" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2020-8284-config_init" +host = "github" +repo = "curl/curl" +parent = "abd846c374c5269809ce11740754bc6f00a0b193" +commit = "ec9cc725d598ac77de7b6df8afeec292b3c8ad46" +path = "src/tool_cfgable.c" +function = "config_init" +cve = "CVE-2020-8284" +year = 2020 +license = "curl" +relpath = "src/tool_cfgable.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "ftp: CURLOPT_FTP_SKIP_PASV_IP by default" +commit_url = "https://github.com/curl/curl/commit/ec9cc725d598ac77de7b6df8afeec292b3c8ad46" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2020-8231-curl_multi_add_handle" +host = "github" +repo = "curl/curl" +parent = "687908c6e6332b2bf4ba74b271e795f9c65a5a61" +commit = "3c9e021f86872baae412a427e807fbfa2f3e8a22" +path = "lib/multi.c" +function = "curl_multi_add_handle" +cve = "CVE-2020-8231" +year = 2020 +license = "curl" +relpath = "lib/multi.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Curl_easy: remember last connection by id, not by pointer" +commit_url = "https://github.com/curl/curl/commit/3c9e021f86872baae412a427e807fbfa2f3e8a22" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2020-8231-curl_open" +host = "github" +repo = "curl/curl" +parent = "687908c6e6332b2bf4ba74b271e795f9c65a5a61" +commit = "3c9e021f86872baae412a427e807fbfa2f3e8a22" +path = "lib/url.c" +function = "Curl_open" +cve = "CVE-2020-8231" +year = 2020 +license = "curl" +relpath = "lib/url.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "Curl_easy: remember last connection by id, not by pointer" +commit_url = "https://github.com/curl/curl/commit/3c9e021f86872baae412a427e807fbfa2f3e8a22" +origin = "curl" +project = "curl" + +[[recipe]] +name = "curl-cve-2020-8177" +host = "github" +repo = "curl/curl" +parent = "26d2755d7c3181e90e46014778941bff53d2309f" +commit = "8236aba58542c5f89f1d41ca09d84579efb05e22" +path = "src/tool_cb_hdr.c" +function = "tool_header_cb" +cve = "CVE-2020-8177" +year = 2020 +license = "curl" +relpath = "src/tool_cb_hdr.c" +language = "c" +cwe = "CWE-119" +class = "security fix" +sink = "unknown" +evidence = "tool_getparam: -i is not OK if -J is used" +commit_url = "https://github.com/curl/curl/commit/8236aba58542c5f89f1d41ca09d84579efb05e22" +origin = "curl" +project = "curl" diff --git a/benchmarks/pairs/vfc/training/README.md b/benchmarks/pairs/vfc/training/README.md new file mode 100644 index 0000000..ab6f37d --- /dev/null +++ b/benchmarks/pairs/vfc/training/README.md @@ -0,0 +1,22 @@ +# VFC training catalog + +Each JSONL row is one isolated snapshot: **vuln** (positive) or **fixed** (negative). + +```bash +python3 benchmarks/pairs/vfc/generate_catalog.py +``` + +`manifest.jsonl` fields: `id`, `pair`, `label` (`vuln`|`fixed`), `cve`, `year`, `cwe`, `project`, `file`, `relpath`, `license`, `commit`, `commit_url`. + +The JSONL is the training index. Pair eval (`ousast pairs --slice vfc`) is the honesty dashboard, not a merge gate. + +Filter 2020–2026: + +```python +import json +from pathlib import Path +rows = [json.loads(line) for line in Path("benchmarks/pairs/vfc/training/manifest.jsonl").read_text().splitlines()] +recent = [row for row in rows if 2020 <= row["year"] <= 2026] +``` + +Do not treat this slice as a merge gate. Memory-safety pairs often LEAK after the fix; UAF/type-confusion often MISS inventory. diff --git a/benchmarks/pairs/vfc/training/manifest.jsonl b/benchmarks/pairs/vfc/training/manifest.jsonl new file mode 100644 index 0000000..6313772 --- /dev/null +++ b/benchmarks/pairs/vfc/training/manifest.jsonl @@ -0,0 +1,352 @@ +{"class": "buffer over-read", "commit": "0d7717fc9c83dafab8153cbd5e2180e6e04cc802", "commit_url": "https://github.com/openssl/openssl/commit/96db9023b881d7cd9f379b0c154650d6c108e9a3", "cve": "CVE-2014-0160", "cwe": "CWE-126", "file": "openssl-cve-2014-0160/vuln.c", "function": "tls1_process_heartbeat", "id": "openssl-cve-2014-0160:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2014-0160", "project": "openssl", "relpath": "ssl/t1_lib.c", "repo": "openssl/openssl", "year": 2014} +{"class": "buffer over-read", "commit": "96db9023b881d7cd9f379b0c154650d6c108e9a3", "commit_url": "https://github.com/openssl/openssl/commit/96db9023b881d7cd9f379b0c154650d6c108e9a3", "cve": "CVE-2014-0160", "cwe": "CWE-126", "file": "openssl-cve-2014-0160/fixed.c", "function": "tls1_process_heartbeat", "id": "openssl-cve-2014-0160:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2014-0160", "project": "openssl", "relpath": "ssl/t1_lib.c", "repo": "openssl/openssl", "year": 2014} +{"class": "buffer overflow", "commit": "0c0f777161a9499dd149853ff62d356f75d16c2a", "commit_url": "https://hg.mozilla.org/mozilla-central/rev/b79b6cc78248eea7fda10bfb76aa273c19c9fa65", "cve": "CVE-2020-15667", "cwe": "CWE-119", "file": "firefox-cve-2020-15667/vuln.c", "function": "mar_insert_item", "id": "firefox-cve-2020-15667:vuln", "label": "vuln", "license": "MPL-2.0", "pair": "firefox-cve-2020-15667", "project": "firefox", "relpath": "modules/libmar/src/mar_read.c", "repo": "mozilla-central", "year": 2020} +{"class": "buffer overflow", "commit": "b79b6cc78248eea7fda10bfb76aa273c19c9fa65", "commit_url": "https://hg.mozilla.org/mozilla-central/rev/b79b6cc78248eea7fda10bfb76aa273c19c9fa65", "cve": "CVE-2020-15667", "cwe": "CWE-119", "file": "firefox-cve-2020-15667/fixed.c", "function": "mar_insert_item", "id": "firefox-cve-2020-15667:fixed", "label": "fixed", "license": "MPL-2.0", "pair": "firefox-cve-2020-15667", "project": "firefox", "relpath": "modules/libmar/src/mar_read.c", "repo": "mozilla-central", "year": 2020} +{"class": "use after free", "commit": "9f3fccdba567f30ea39b08f57d8d5b49cd832b4a", "commit_url": "https://github.com/chromium/chromium/commit/ba9748e78ec7e9c0d594e7edf7b2c07ea2a90449", "cve": "CVE-2019-5786", "cwe": "CWE-416", "file": "chromium-cve-2019-5786/vuln.cc", "function": "ArrayBufferResult", "id": "chromium-cve-2019-5786:vuln", "label": "vuln", "license": "BSD-3-Clause", "pair": "chromium-cve-2019-5786", "project": "chromium", "relpath": "third_party/blink/renderer/core/fileapi/file_reader_loader.cc", "repo": "chromium/chromium", "year": 2019} +{"class": "use after free", "commit": "ba9748e78ec7e9c0d594e7edf7b2c07ea2a90449", "commit_url": "https://github.com/chromium/chromium/commit/ba9748e78ec7e9c0d594e7edf7b2c07ea2a90449", "cve": "CVE-2019-5786", "cwe": "CWE-416", "file": "chromium-cve-2019-5786/fixed.cc", "function": "ArrayBufferResult", "id": "chromium-cve-2019-5786:fixed", "label": "fixed", "license": "BSD-3-Clause", "pair": "chromium-cve-2019-5786", "project": "chromium", "relpath": "third_party/blink/renderer/core/fileapi/file_reader_loader.cc", "repo": "chromium/chromium", "year": 2019} +{"class": "null pointer dereference", "commit": "3656c08ab4b1b892730cb5e808b6f4298b08a2e6", "commit_url": "https://github.com/openssl/openssl/commit/a87f3fe01a5a894aa27ccd6a239155fd129988e4", "cve": "CVE-2020-1967", "cwe": "CWE-476", "file": "openssl-cve-2020-1967/vuln.c", "function": "tls1_check_sig_alg", "id": "openssl-cve-2020-1967:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2020-1967", "project": "openssl", "relpath": "ssl/t1_lib.c", "repo": "openssl/openssl", "year": 2020} +{"class": "null pointer dereference", "commit": "a87f3fe01a5a894aa27ccd6a239155fd129988e4", "commit_url": "https://github.com/openssl/openssl/commit/a87f3fe01a5a894aa27ccd6a239155fd129988e4", "cve": "CVE-2020-1967", "cwe": "CWE-476", "file": "openssl-cve-2020-1967/fixed.c", "function": "tls1_check_sig_alg", "id": "openssl-cve-2020-1967:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2020-1967", "project": "openssl", "relpath": "ssl/t1_lib.c", "repo": "openssl/openssl", "year": 2020} +{"class": "null pointer dereference", "commit": "198b11683568452282bd48828fcf60d4835bf327", "commit_url": "https://github.com/openssl/openssl/commit/b33c48b75aaf33c93aeda42d7138616b9e6a64cb", "cve": "CVE-2020-1971", "cwe": "CWE-476", "file": "openssl-cve-2020-1971/vuln.c", "function": "GENERAL_NAME_cmp", "id": "openssl-cve-2020-1971:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2020-1971", "project": "openssl", "relpath": "crypto/x509/v3_genn.c", "repo": "openssl/openssl", "year": 2020} +{"class": "null pointer dereference", "commit": "b33c48b75aaf33c93aeda42d7138616b9e6a64cb", "commit_url": "https://github.com/openssl/openssl/commit/b33c48b75aaf33c93aeda42d7138616b9e6a64cb", "cve": "CVE-2020-1971", "cwe": "CWE-476", "file": "openssl-cve-2020-1971/fixed.c", "function": "GENERAL_NAME_cmp", "id": "openssl-cve-2020-1971:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2020-1971", "project": "openssl", "relpath": "crypto/x509/v3_genn.c", "repo": "openssl/openssl", "year": 2020} +{"class": "integer overflow", "commit": "c1ddd392cf9737c09c1f9bf690adfbe596403c5e", "commit_url": "https://github.com/openssl/openssl/commit/c9fb704cf3af5524eb8e79961e31b60eee8c3c47", "cve": "CVE-2021-23840", "cwe": "CWE-190", "file": "openssl-cve-2021-23840/vuln.c", "function": "evp_EncryptDecryptUpdate", "id": "openssl-cve-2021-23840:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2021-23840", "project": "openssl", "relpath": "crypto/evp/evp_enc.c", "repo": "openssl/openssl", "year": 2021} +{"class": "integer overflow", "commit": "c9fb704cf3af5524eb8e79961e31b60eee8c3c47", "commit_url": "https://github.com/openssl/openssl/commit/c9fb704cf3af5524eb8e79961e31b60eee8c3c47", "cve": "CVE-2021-23840", "cwe": "CWE-190", "file": "openssl-cve-2021-23840/fixed.c", "function": "evp_EncryptDecryptUpdate", "id": "openssl-cve-2021-23840:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2021-23840", "project": "openssl", "relpath": "crypto/evp/evp_enc.c", "repo": "openssl/openssl", "year": 2021} +{"class": "buffer overflow", "commit": "8c74c9d1ade0fbdab5b815ddb747351b8b839641", "commit_url": "https://github.com/openssl/openssl/commit/59f5e75f3bced8fc0e130d72a3f582cf7b480b46", "cve": "CVE-2021-3711", "cwe": "CWE-120", "file": "openssl-cve-2021-3711/vuln.c", "function": "sm2_plaintext_size", "id": "openssl-cve-2021-3711:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2021-3711", "project": "openssl", "relpath": "crypto/sm2/sm2_crypt.c", "repo": "openssl/openssl", "year": 2021} +{"class": "buffer overflow", "commit": "59f5e75f3bced8fc0e130d72a3f582cf7b480b46", "commit_url": "https://github.com/openssl/openssl/commit/59f5e75f3bced8fc0e130d72a3f582cf7b480b46", "cve": "CVE-2021-3711", "cwe": "CWE-120", "file": "openssl-cve-2021-3711/fixed.c", "function": "sm2_plaintext_size", "id": "openssl-cve-2021-3711:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2021-3711", "project": "openssl", "relpath": "crypto/sm2/sm2_crypt.c", "repo": "openssl/openssl", "year": 2021} +{"class": "buffer over-read", "commit": "1f365708a3318a5f1a395f90c38b584a58d37fb9", "commit_url": "https://github.com/openssl/openssl/commit/98624776c4d501c8badd6f772ab7048ac9191cb9", "cve": "CVE-2021-3712", "cwe": "CWE-125", "file": "openssl-cve-2021-3712/vuln.c", "function": "append_ia5", "id": "openssl-cve-2021-3712:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2021-3712", "project": "openssl", "relpath": "crypto/x509/v3_utl.c", "repo": "openssl/openssl", "year": 2021} +{"class": "buffer over-read", "commit": "98624776c4d501c8badd6f772ab7048ac9191cb9", "commit_url": "https://github.com/openssl/openssl/commit/98624776c4d501c8badd6f772ab7048ac9191cb9", "cve": "CVE-2021-3712", "cwe": "CWE-125", "file": "openssl-cve-2021-3712/fixed.c", "function": "append_ia5", "id": "openssl-cve-2021-3712:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2021-3712", "project": "openssl", "relpath": "crypto/x509/v3_utl.c", "repo": "openssl/openssl", "year": 2021} +{"class": "infinite loop", "commit": "1832bb0f02e519a48f06a10467c7ce5f7f3feeeb", "commit_url": "https://github.com/openssl/openssl/commit/9eafb53614bf65797db25f467946e735e1b43dc9", "cve": "CVE-2022-0778", "cwe": "CWE-835", "file": "openssl-cve-2022-0778/vuln.c", "function": "BN_mod_sqrt", "id": "openssl-cve-2022-0778:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2022-0778", "project": "openssl", "relpath": "crypto/bn/bn_sqrt.c", "repo": "openssl/openssl", "year": 2022} +{"class": "infinite loop", "commit": "9eafb53614bf65797db25f467946e735e1b43dc9", "commit_url": "https://github.com/openssl/openssl/commit/9eafb53614bf65797db25f467946e735e1b43dc9", "cve": "CVE-2022-0778", "cwe": "CWE-835", "file": "openssl-cve-2022-0778/fixed.c", "function": "BN_mod_sqrt", "id": "openssl-cve-2022-0778:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2022-0778", "project": "openssl", "relpath": "crypto/bn/bn_sqrt.c", "repo": "openssl/openssl", "year": 2022} +{"class": "command injection", "commit": "7d56a74a96828985db7354a55227a511615f732b", "commit_url": "https://github.com/openssl/openssl/commit/1ad73b4d27bd8c1b369a3cd453681d3a4f1bb9b2", "cve": "CVE-2022-1292", "cwe": "CWE-78", "file": "openssl-cve-2022-1292/vuln.in", "function": "link_hash_cert", "id": "openssl-cve-2022-1292:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2022-1292", "project": "openssl", "relpath": "tools/c_rehash.in", "repo": "openssl/openssl", "year": 2022} +{"class": "command injection", "commit": "1ad73b4d27bd8c1b369a3cd453681d3a4f1bb9b2", "commit_url": "https://github.com/openssl/openssl/commit/1ad73b4d27bd8c1b369a3cd453681d3a4f1bb9b2", "cve": "CVE-2022-1292", "cwe": "CWE-78", "file": "openssl-cve-2022-1292/fixed.in", "function": "link_hash_cert", "id": "openssl-cve-2022-1292:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2022-1292", "project": "openssl", "relpath": "tools/c_rehash.in", "repo": "openssl/openssl", "year": 2022} +{"class": "buffer overflow", "commit": "89d72311327735ef15c804d2adea84a0fb1bfa0a", "commit_url": "https://github.com/openssl/openssl/commit/3b421ebc64c7b52f1b9feb3812bdc7781c784332", "cve": "CVE-2022-3602", "cwe": "CWE-787", "file": "openssl-cve-2022-3602/vuln.c", "function": "ossl_punycode_decode", "id": "openssl-cve-2022-3602:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2022-3602", "project": "openssl", "relpath": "crypto/punycode.c", "repo": "openssl/openssl", "year": 2022} +{"class": "buffer overflow", "commit": "3b421ebc64c7b52f1b9feb3812bdc7781c784332", "commit_url": "https://github.com/openssl/openssl/commit/3b421ebc64c7b52f1b9feb3812bdc7781c784332", "cve": "CVE-2022-3602", "cwe": "CWE-787", "file": "openssl-cve-2022-3602/fixed.c", "function": "ossl_punycode_decode", "id": "openssl-cve-2022-3602:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2022-3602", "project": "openssl", "relpath": "crypto/punycode.c", "repo": "openssl/openssl", "year": 2022} +{"class": "buffer overflow", "commit": "3b421ebc64c7b52f1b9feb3812bdc7781c784332", "commit_url": "https://github.com/openssl/openssl/commit/680e65b94c916af259bfdc2e25f1ab6e0c7a97d6", "cve": "CVE-2022-3786", "cwe": "CWE-787", "file": "openssl-cve-2022-3786/vuln.c", "function": "ossl_punycode_decode", "id": "openssl-cve-2022-3786:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2022-3786", "project": "openssl", "relpath": "crypto/punycode.c", "repo": "openssl/openssl", "year": 2022} +{"class": "buffer overflow", "commit": "680e65b94c916af259bfdc2e25f1ab6e0c7a97d6", "commit_url": "https://github.com/openssl/openssl/commit/680e65b94c916af259bfdc2e25f1ab6e0c7a97d6", "cve": "CVE-2022-3786", "cwe": "CWE-787", "file": "openssl-cve-2022-3786/fixed.c", "function": "ossl_punycode_decode", "id": "openssl-cve-2022-3786:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2022-3786", "project": "openssl", "relpath": "crypto/punycode.c", "repo": "openssl/openssl", "year": 2022} +{"class": "type confusion", "commit": "adf77d6657e836fc87391fad53d857927a764297", "commit_url": "https://github.com/openssl/openssl/commit/7880536fe17c2b5450e279155bedd51771d28c9f", "cve": "CVE-2023-0286", "cwe": "CWE-843", "file": "openssl-cve-2023-0286/vuln.c", "function": "GENERAL_NAME_cmp", "id": "openssl-cve-2023-0286:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2023-0286", "project": "openssl", "relpath": "crypto/x509/v3_genn.c", "repo": "openssl/openssl", "year": 2023} +{"class": "type confusion", "commit": "7880536fe17c2b5450e279155bedd51771d28c9f", "commit_url": "https://github.com/openssl/openssl/commit/7880536fe17c2b5450e279155bedd51771d28c9f", "cve": "CVE-2023-0286", "cwe": "CWE-843", "file": "openssl-cve-2023-0286/fixed.c", "function": "GENERAL_NAME_cmp", "id": "openssl-cve-2023-0286:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2023-0286", "project": "openssl", "relpath": "crypto/x509/v3_genn.c", "repo": "openssl/openssl", "year": 2023} +{"class": "heap buffer overflow", "commit": "09e25b9d94f4106eac8ca3a43b221bdc66f405e4", "commit_url": "https://github.com/curl/curl/commit/fb4415d8aee6c1045be932a34fe6107c2f5ed147", "cve": "CVE-2023-38545", "cwe": "CWE-122", "file": "curl-cve-2023-38545/vuln.c", "function": "do_SOCKS5", "id": "curl-cve-2023-38545:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2023-38545", "project": "curl", "relpath": "lib/socks.c", "repo": "curl/curl", "year": 2023} +{"class": "heap buffer overflow", "commit": "fb4415d8aee6c1045be932a34fe6107c2f5ed147", "commit_url": "https://github.com/curl/curl/commit/fb4415d8aee6c1045be932a34fe6107c2f5ed147", "cve": "CVE-2023-38545", "cwe": "CWE-122", "file": "curl-cve-2023-38545/fixed.c", "function": "do_SOCKS5", "id": "curl-cve-2023-38545:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2023-38545", "project": "curl", "relpath": "lib/socks.c", "repo": "curl/curl", "year": 2023} +{"class": "insufficient input validation", "commit": "a07d0ae0a7dc68686adca10dcf11138cb2f4ab6d", "commit_url": "https://github.com/chromium/chromium/commit/22c61cfae5d1b37c773e638d342488ae11118b51", "cve": "CVE-2022-2162", "cwe": "CWE-20", "file": "chromium-cve-2022-2162/vuln.cc", "function": "IsShellIntegratedExtension", "id": "chromium-cve-2022-2162:vuln", "label": "vuln", "license": "BSD-3-Clause", "pair": "chromium-cve-2022-2162", "project": "chromium", "relpath": "content/browser/file_system_access/file_system_chooser.cc", "repo": "chromium/chromium", "year": 2022} +{"class": "insufficient input validation", "commit": "22c61cfae5d1b37c773e638d342488ae11118b51", "commit_url": "https://github.com/chromium/chromium/commit/22c61cfae5d1b37c773e638d342488ae11118b51", "cve": "CVE-2022-2162", "cwe": "CWE-20", "file": "chromium-cve-2022-2162/fixed.cc", "function": "IsShellIntegratedExtension", "id": "chromium-cve-2022-2162:fixed", "label": "fixed", "license": "BSD-3-Clause", "pair": "chromium-cve-2022-2162", "project": "chromium", "relpath": "content/browser/file_system_access/file_system_chooser.cc", "repo": "chromium/chromium", "year": 2022} +{"class": "null pointer dereference", "commit": "ea8fc4c345fbd749048809c9f7c881ea656b0b94", "commit_url": "https://github.com/openssl/openssl/commit/2c13bf15286328641a805eb3b7c97e27d42881fb", "cve": "CVE-2025-69421", "cwe": "CWE-476", "file": "openssl-cve-2025-69421/vuln.c", "function": "PKCS12_item_decrypt_d2i_ex", "id": "openssl-cve-2025-69421:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2025-69421", "project": "openssl", "relpath": "crypto/pkcs12/p12_decr.c", "repo": "openssl/openssl", "year": 2025} +{"class": "null pointer dereference", "commit": "2c13bf15286328641a805eb3b7c97e27d42881fb", "commit_url": "https://github.com/openssl/openssl/commit/2c13bf15286328641a805eb3b7c97e27d42881fb", "cve": "CVE-2025-69421", "cwe": "CWE-476", "file": "openssl-cve-2025-69421/fixed.c", "function": "PKCS12_item_decrypt_d2i_ex", "id": "openssl-cve-2025-69421:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2025-69421", "project": "openssl", "relpath": "crypto/pkcs12/p12_decr.c", "repo": "openssl/openssl", "year": 2025} +{"class": "uncontrolled allocation", "commit": "b21663c35a6f0ed4c8de06855bdc7a6a21f00c2f", "commit_url": "https://github.com/openssl/openssl/commit/84f73f79af9f69c1527a9a372b7a9e771a394c2a", "cve": "CVE-2025-66199", "cwe": "CWE-770", "file": "openssl-cve-2025-66199/vuln.c", "function": "tls13_process_compressed_certificate", "id": "openssl-cve-2025-66199:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2025-66199", "project": "openssl", "relpath": "ssl/statem/statem_lib.c", "repo": "openssl/openssl", "year": 2025} +{"class": "uncontrolled allocation", "commit": "84f73f79af9f69c1527a9a372b7a9e771a394c2a", "commit_url": "https://github.com/openssl/openssl/commit/84f73f79af9f69c1527a9a372b7a9e771a394c2a", "cve": "CVE-2025-66199", "cwe": "CWE-770", "file": "openssl-cve-2025-66199/fixed.c", "function": "tls13_process_compressed_certificate", "id": "openssl-cve-2025-66199:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2025-66199", "project": "openssl", "relpath": "ssl/statem/statem_lib.c", "repo": "openssl/openssl", "year": 2025} +{"class": "uncontrolled allocation", "commit": "eed0931f85474d0db6e2326dfd9718c6bf1cd418", "commit_url": "https://github.com/mozilla-firefox/firefox/commit/e46f28da1cd3a5d46a2680b3d87361e9e8de4ae6", "cve": "BUG-2058173", "cwe": "CWE-770", "file": "firefox-bug-2058173/vuln.c", "function": "mar_read_index", "id": "firefox-bug-2058173:vuln", "label": "vuln", "license": "MPL-2.0", "pair": "firefox-bug-2058173", "project": "firefox", "relpath": "modules/libmar/src/mar_read.c", "repo": "mozilla-firefox/firefox", "year": 2026} +{"class": "uncontrolled allocation", "commit": "e46f28da1cd3a5d46a2680b3d87361e9e8de4ae6", "commit_url": "https://github.com/mozilla-firefox/firefox/commit/e46f28da1cd3a5d46a2680b3d87361e9e8de4ae6", "cve": "BUG-2058173", "cwe": "CWE-770", "file": "firefox-bug-2058173/fixed.c", "function": "mar_read_index", "id": "firefox-bug-2058173:fixed", "label": "fixed", "license": "MPL-2.0", "pair": "firefox-bug-2058173", "project": "firefox", "relpath": "modules/libmar/src/mar_read.c", "repo": "mozilla-firefox/firefox", "year": 2026} +{"class": "security fix", "commit": "48f5785425ee6b5316f8e5f921978397ba632cc6", "commit_url": "https://github.com/openssl/openssl/commit/70cebd74d3592f5272945501b58a60374c4e13af", "cve": "CVE-2026-18798", "cwe": "CWE-119", "file": "openssl-cve-2026-18798/vuln.c", "function": "port_default_packet_handler", "id": "openssl-cve-2026-18798:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-18798", "project": "openssl", "relpath": "ssl/quic/quic_port.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "70cebd74d3592f5272945501b58a60374c4e13af", "commit_url": "https://github.com/openssl/openssl/commit/70cebd74d3592f5272945501b58a60374c4e13af", "cve": "CVE-2026-18798", "cwe": "CWE-119", "file": "openssl-cve-2026-18798/fixed.c", "function": "port_default_packet_handler", "id": "openssl-cve-2026-18798:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-18798", "project": "openssl", "relpath": "ssl/quic/quic_port.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "a0c8ec557d9cac078f032d76cdf684fe743eb382", "commit_url": "https://github.com/openssl/openssl/commit/1ca5a124b48f1ffe6980ad33724b452fbd62da1e", "cve": "CVE-2026-54874", "cwe": "CWE-119", "file": "openssl-cve-2026-54874/vuln.c", "function": "DTLS_RECORD_LAYER_clear", "id": "openssl-cve-2026-54874:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-54874", "project": "openssl", "relpath": "ssl/record/rec_layer_d1.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "1ca5a124b48f1ffe6980ad33724b452fbd62da1e", "commit_url": "https://github.com/openssl/openssl/commit/1ca5a124b48f1ffe6980ad33724b452fbd62da1e", "cve": "CVE-2026-54874", "cwe": "CWE-119", "file": "openssl-cve-2026-54874/fixed.c", "function": "DTLS_RECORD_LAYER_clear", "id": "openssl-cve-2026-54874:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-54874", "project": "openssl", "relpath": "ssl/record/rec_layer_d1.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "a0c8ec557d9cac078f032d76cdf684fe743eb382", "commit_url": "https://github.com/openssl/openssl/commit/1ca5a124b48f1ffe6980ad33724b452fbd62da1e", "cve": "CVE-2026-54874", "cwe": "CWE-119", "file": "openssl-cve-2026-54874-dtls1_process_record/vuln.c", "function": "dtls1_process_record", "id": "openssl-cve-2026-54874-dtls1_process_record:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-54874-dtls1_process_record", "project": "openssl", "relpath": "ssl/record/ssl3_record.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "1ca5a124b48f1ffe6980ad33724b452fbd62da1e", "commit_url": "https://github.com/openssl/openssl/commit/1ca5a124b48f1ffe6980ad33724b452fbd62da1e", "cve": "CVE-2026-54874", "cwe": "CWE-119", "file": "openssl-cve-2026-54874-dtls1_process_record/fixed.c", "function": "dtls1_process_record", "id": "openssl-cve-2026-54874-dtls1_process_record:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-54874-dtls1_process_record", "project": "openssl", "relpath": "ssl/record/ssl3_record.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "9ec2f6d2ae2bcad907cf7ee38584855bafe4979a", "commit_url": "https://github.com/openssl/openssl/commit/7110cb2f75806d0bf809eb2f90790d477900be40", "cve": "CVE-2026-54874", "cwe": "CWE-119", "file": "openssl-cve-2026-54874-dtls_rlayer_buffer_recor/vuln.c", "function": "dtls_rlayer_buffer_record", "id": "openssl-cve-2026-54874-dtls_rlayer_buffer_recor:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-54874-dtls_rlayer_buffer_recor", "project": "openssl", "relpath": "ssl/record/methods/dtls_meth.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "7110cb2f75806d0bf809eb2f90790d477900be40", "commit_url": "https://github.com/openssl/openssl/commit/7110cb2f75806d0bf809eb2f90790d477900be40", "cve": "CVE-2026-54874", "cwe": "CWE-119", "file": "openssl-cve-2026-54874-dtls_rlayer_buffer_recor/fixed.c", "function": "dtls_rlayer_buffer_record", "id": "openssl-cve-2026-54874-dtls_rlayer_buffer_recor:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-54874-dtls_rlayer_buffer_recor", "project": "openssl", "relpath": "ssl/record/methods/dtls_meth.c", "repo": "openssl/openssl", "year": 2026} +{"class": "buffer overflow", "commit": "d307f61f1b341b6eb7d5d07bd6902a939c709bc6", "commit_url": "https://github.com/openssl/openssl/commit/a0c8ec557d9cac078f032d76cdf684fe743eb382", "cve": "CVE-2026-63072", "cwe": "CWE-119", "file": "openssl-cve-2026-63072/vuln.c", "function": "cms_kek_cipher", "id": "openssl-cve-2026-63072:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-63072", "project": "openssl", "relpath": "crypto/cms/cms_kari.c", "repo": "openssl/openssl", "year": 2026} +{"class": "buffer overflow", "commit": "a0c8ec557d9cac078f032d76cdf684fe743eb382", "commit_url": "https://github.com/openssl/openssl/commit/a0c8ec557d9cac078f032d76cdf684fe743eb382", "cve": "CVE-2026-63072", "cwe": "CWE-119", "file": "openssl-cve-2026-63072/fixed.c", "function": "cms_kek_cipher", "id": "openssl-cve-2026-63072:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-63072", "project": "openssl", "relpath": "crypto/cms/cms_kari.c", "repo": "openssl/openssl", "year": 2026} +{"class": "buffer overflow", "commit": "1951c3cbd9d5101e027a1eb126f26c3c758f6cc0", "commit_url": "https://github.com/openssl/openssl/commit/2a3dac874c8057c1f0186849bf1ede1ae7b6b756", "cve": "CVE-2026-63072", "cwe": "CWE-119", "file": "openssl-cve-2026-63072-cms_kek_cipher/vuln.c", "function": "cms_kek_cipher", "id": "openssl-cve-2026-63072-cms_kek_cipher:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-63072-cms_kek_cipher", "project": "openssl", "relpath": "crypto/cms/cms_kemri.c", "repo": "openssl/openssl", "year": 2026} +{"class": "buffer overflow", "commit": "2a3dac874c8057c1f0186849bf1ede1ae7b6b756", "commit_url": "https://github.com/openssl/openssl/commit/2a3dac874c8057c1f0186849bf1ede1ae7b6b756", "cve": "CVE-2026-63072", "cwe": "CWE-119", "file": "openssl-cve-2026-63072-cms_kek_cipher/fixed.c", "function": "cms_kek_cipher", "id": "openssl-cve-2026-63072-cms_kek_cipher:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-63072-cms_kek_cipher", "project": "openssl", "relpath": "crypto/cms/cms_kemri.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "1e8c398db67404babd3e5af999bb6bd86f720c76", "commit_url": "https://github.com/openssl/openssl/commit/a7e5a6eea8fd3ccca6b6fbba031a5fbf8a3d93b4", "cve": "CVE-2026-63073", "cwe": "CWE-119", "file": "openssl-cve-2026-63073/vuln.c", "function": "ossl_cmp_msg_check_update", "id": "openssl-cve-2026-63073:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-63073", "project": "openssl", "relpath": "crypto/cmp/cmp_vfy.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "a7e5a6eea8fd3ccca6b6fbba031a5fbf8a3d93b4", "commit_url": "https://github.com/openssl/openssl/commit/a7e5a6eea8fd3ccca6b6fbba031a5fbf8a3d93b4", "cve": "CVE-2026-63073", "cwe": "CWE-119", "file": "openssl-cve-2026-63073/fixed.c", "function": "ossl_cmp_msg_check_update", "id": "openssl-cve-2026-63073:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-63073", "project": "openssl", "relpath": "crypto/cmp/cmp_vfy.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "f636f9ca0fa1bae5b42f9e787f025c96fb09c43a", "commit_url": "https://github.com/openssl/openssl/commit/1e8c398db67404babd3e5af999bb6bd86f720c76", "cve": "CVE-2026-14457", "cwe": "CWE-119", "file": "openssl-cve-2026-14457/vuln.c", "function": "check_cert_usable", "id": "openssl-cve-2026-14457:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-14457", "project": "openssl", "relpath": "ssl/t1_lib.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "1e8c398db67404babd3e5af999bb6bd86f720c76", "commit_url": "https://github.com/openssl/openssl/commit/1e8c398db67404babd3e5af999bb6bd86f720c76", "cve": "CVE-2026-14457", "cwe": "CWE-119", "file": "openssl-cve-2026-14457/fixed.c", "function": "check_cert_usable", "id": "openssl-cve-2026-14457:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-14457", "project": "openssl", "relpath": "ssl/t1_lib.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "9f2b8522d39ff869fac2ff7c3f20609b54843188", "commit_url": "https://github.com/openssl/openssl/commit/21a5d9658b0c66daace60e10ea18ff32a448de9f", "cve": "CVE-2026-63074", "cwe": "CWE-119", "file": "openssl-cve-2026-63074/vuln.c", "function": "ossl_cmp_msg_check_update", "id": "openssl-cve-2026-63074:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-63074", "project": "openssl", "relpath": "crypto/cmp/cmp_vfy.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "21a5d9658b0c66daace60e10ea18ff32a448de9f", "commit_url": "https://github.com/openssl/openssl/commit/21a5d9658b0c66daace60e10ea18ff32a448de9f", "cve": "CVE-2026-63074", "cwe": "CWE-119", "file": "openssl-cve-2026-63074/fixed.c", "function": "ossl_cmp_msg_check_update", "id": "openssl-cve-2026-63074:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-63074", "project": "openssl", "relpath": "crypto/cmp/cmp_vfy.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "a1f348ccb328c3afbd4ba6883f9b7c813c043259", "commit_url": "https://github.com/openssl/openssl/commit/c902e5f16d6a9e130e96d3ca6d8f64d71652e393", "cve": "CVE-2026-63075", "cwe": "CWE-119", "file": "openssl-cve-2026-63075-txp_pkt_commit/vuln.c", "function": "txp_pkt_commit", "id": "openssl-cve-2026-63075-txp_pkt_commit:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-63075-txp_pkt_commit", "project": "openssl", "relpath": "ssl/quic/quic_txp.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "c902e5f16d6a9e130e96d3ca6d8f64d71652e393", "commit_url": "https://github.com/openssl/openssl/commit/c902e5f16d6a9e130e96d3ca6d8f64d71652e393", "cve": "CVE-2026-63075", "cwe": "CWE-119", "file": "openssl-cve-2026-63075-txp_pkt_commit/fixed.c", "function": "txp_pkt_commit", "id": "openssl-cve-2026-63075-txp_pkt_commit:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-63075-txp_pkt_commit", "project": "openssl", "relpath": "ssl/quic/quic_txp.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "39488cb863074d5b8ece833905f7ad2b357d44fe", "commit_url": "https://github.com/openssl/openssl/commit/119ab9555dc62275bbd71f6f49529b1a44feba42", "cve": "CVE-2026-75803", "cwe": "CWE-119", "file": "openssl-cve-2026-75803/vuln.c", "function": "aes_ocb_cipher", "id": "openssl-cve-2026-75803:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-75803", "project": "openssl", "relpath": "providers/implementations/ciphers/cipher_aes_ocb.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "119ab9555dc62275bbd71f6f49529b1a44feba42", "commit_url": "https://github.com/openssl/openssl/commit/119ab9555dc62275bbd71f6f49529b1a44feba42", "cve": "CVE-2026-75803", "cwe": "CWE-119", "file": "openssl-cve-2026-75803/fixed.c", "function": "aes_ocb_cipher", "id": "openssl-cve-2026-75803:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-75803", "project": "openssl", "relpath": "providers/implementations/ciphers/cipher_aes_ocb.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "39488cb863074d5b8ece833905f7ad2b357d44fe", "commit_url": "https://github.com/openssl/openssl/commit/119ab9555dc62275bbd71f6f49529b1a44feba42", "cve": "CVE-2026-75803", "cwe": "CWE-119", "file": "openssl-cve-2026-75803-chacha20_poly1305_cipher/vuln.c", "function": "chacha20_poly1305_cipher", "id": "openssl-cve-2026-75803-chacha20_poly1305_cipher:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-75803-chacha20_poly1305_cipher", "project": "openssl", "relpath": "providers/implementations/ciphers/cipher_chacha20_poly1305.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "119ab9555dc62275bbd71f6f49529b1a44feba42", "commit_url": "https://github.com/openssl/openssl/commit/119ab9555dc62275bbd71f6f49529b1a44feba42", "cve": "CVE-2026-75803", "cwe": "CWE-119", "file": "openssl-cve-2026-75803-chacha20_poly1305_cipher/fixed.c", "function": "chacha20_poly1305_cipher", "id": "openssl-cve-2026-75803-chacha20_poly1305_cipher:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-75803-chacha20_poly1305_cipher", "project": "openssl", "relpath": "providers/implementations/ciphers/cipher_chacha20_poly1305.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "de7d1871087fc1fa3e2c1db4b11275b68d72f416", "commit_url": "https://github.com/openssl/openssl/commit/bf95f5f772e9362f87b25cfa2f8cb15d984865b9", "cve": "CVE-2026-75803", "cwe": "CWE-119", "file": "openssl-cve-2026-75803-aes_gcm_siv_finish/vuln.c", "function": "aes_gcm_siv_finish", "id": "openssl-cve-2026-75803-aes_gcm_siv_finish:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-75803-aes_gcm_siv_finish", "project": "openssl", "relpath": "providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "bf95f5f772e9362f87b25cfa2f8cb15d984865b9", "commit_url": "https://github.com/openssl/openssl/commit/bf95f5f772e9362f87b25cfa2f8cb15d984865b9", "cve": "CVE-2026-75803", "cwe": "CWE-119", "file": "openssl-cve-2026-75803-aes_gcm_siv_finish/fixed.c", "function": "aes_gcm_siv_finish", "id": "openssl-cve-2026-75803-aes_gcm_siv_finish:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-75803-aes_gcm_siv_finish", "project": "openssl", "relpath": "providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "2dacccc943b47b8dc1ce8f7109c9852391b5a0d8", "commit_url": "https://github.com/openssl/openssl/commit/08e7756c3900bcfd77a720e7b74e27d6e4ed01a9", "cve": "CVE-2026-14456", "cwe": "CWE-119", "file": "openssl-cve-2026-14456-port_default_packet_hand/vuln.c", "function": "port_default_packet_handler", "id": "openssl-cve-2026-14456-port_default_packet_hand:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-14456-port_default_packet_hand", "project": "openssl", "relpath": "ssl/quic/quic_port.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "08e7756c3900bcfd77a720e7b74e27d6e4ed01a9", "commit_url": "https://github.com/openssl/openssl/commit/08e7756c3900bcfd77a720e7b74e27d6e4ed01a9", "cve": "CVE-2026-14456", "cwe": "CWE-119", "file": "openssl-cve-2026-14456-port_default_packet_hand/fixed.c", "function": "port_default_packet_handler", "id": "openssl-cve-2026-14456-port_default_packet_hand:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-14456-port_default_packet_hand", "project": "openssl", "relpath": "ssl/quic/quic_port.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "2c9a078b6030444ed868a3943991f42b35cd49dc", "commit_url": "https://github.com/openssl/openssl/commit/9416706d408bb84deb7cee4647bff3045d2dc7ba", "cve": "CVE-2026-14456", "cwe": "CWE-119", "file": "openssl-cve-2026-14456-expect_quic_for_value/vuln.c", "function": "expect_quic_for_value", "id": "openssl-cve-2026-14456-expect_quic_for_value:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-14456-expect_quic_for_value", "project": "openssl", "relpath": "ssl/quic/quic_impl.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "9416706d408bb84deb7cee4647bff3045d2dc7ba", "commit_url": "https://github.com/openssl/openssl/commit/9416706d408bb84deb7cee4647bff3045d2dc7ba", "cve": "CVE-2026-14456", "cwe": "CWE-119", "file": "openssl-cve-2026-14456-expect_quic_for_value/fixed.c", "function": "expect_quic_for_value", "id": "openssl-cve-2026-14456-expect_quic_for_value:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-14456-expect_quic_for_value", "project": "openssl", "relpath": "ssl/quic/quic_impl.c", "repo": "openssl/openssl", "year": 2026} +{"class": "use after free", "commit": "609bcb24866d64f1fc49d38b852edbb39057d721", "commit_url": "https://github.com/openssl/openssl/commit/f4129fbe3cde786d363510069fe297234f99be8f", "cve": "CVE-2026-45447", "cwe": "CWE-416", "file": "openssl-cve-2026-45447/vuln.c", "function": "PKCS7_verify", "id": "openssl-cve-2026-45447:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-45447", "project": "openssl", "relpath": "crypto/pkcs7/pk7_smime.c", "repo": "openssl/openssl", "year": 2026} +{"class": "use after free", "commit": "f4129fbe3cde786d363510069fe297234f99be8f", "commit_url": "https://github.com/openssl/openssl/commit/f4129fbe3cde786d363510069fe297234f99be8f", "cve": "CVE-2026-45447", "cwe": "CWE-416", "file": "openssl-cve-2026-45447/fixed.c", "function": "PKCS7_verify", "id": "openssl-cve-2026-45447:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-45447", "project": "openssl", "relpath": "crypto/pkcs7/pk7_smime.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "f87f0b6a8e04bcdeb98afc82b0da06a2d537f399", "commit_url": "https://github.com/openssl/openssl/commit/609bcb24866d64f1fc49d38b852edbb39057d721", "cve": "CVE-2026-45446", "cwe": "CWE-119", "file": "openssl-cve-2026-45446/vuln.c", "function": "aes_gcm_siv_initkey", "id": "openssl-cve-2026-45446:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-45446", "project": "openssl", "relpath": "providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "609bcb24866d64f1fc49d38b852edbb39057d721", "commit_url": "https://github.com/openssl/openssl/commit/609bcb24866d64f1fc49d38b852edbb39057d721", "cve": "CVE-2026-45446", "cwe": "CWE-119", "file": "openssl-cve-2026-45446/fixed.c", "function": "aes_gcm_siv_initkey", "id": "openssl-cve-2026-45446:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-45446", "project": "openssl", "relpath": "providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "f87f0b6a8e04bcdeb98afc82b0da06a2d537f399", "commit_url": "https://github.com/openssl/openssl/commit/609bcb24866d64f1fc49d38b852edbb39057d721", "cve": "CVE-2026-45446", "cwe": "CWE-119", "file": "openssl-cve-2026-45446-aes_siv_set_ctx_params/vuln.c", "function": "aes_siv_set_ctx_params", "id": "openssl-cve-2026-45446-aes_siv_set_ctx_params:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-45446-aes_siv_set_ctx_params", "project": "openssl", "relpath": "providers/implementations/ciphers/cipher_aes_siv.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "609bcb24866d64f1fc49d38b852edbb39057d721", "commit_url": "https://github.com/openssl/openssl/commit/609bcb24866d64f1fc49d38b852edbb39057d721", "cve": "CVE-2026-45446", "cwe": "CWE-119", "file": "openssl-cve-2026-45446-aes_siv_set_ctx_params/fixed.c", "function": "aes_siv_set_ctx_params", "id": "openssl-cve-2026-45446-aes_siv_set_ctx_params:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-45446-aes_siv_set_ctx_params", "project": "openssl", "relpath": "providers/implementations/ciphers/cipher_aes_siv.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "5f489043b662fed32fbf7eb7442c479568eb43fd", "commit_url": "https://github.com/openssl/openssl/commit/f87f0b6a8e04bcdeb98afc82b0da06a2d537f399", "cve": "CVE-2026-45445", "cwe": "CWE-119", "file": "openssl-cve-2026-45445/vuln.c", "function": "aes_ocb_cipher", "id": "openssl-cve-2026-45445:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-45445", "project": "openssl", "relpath": "providers/implementations/ciphers/cipher_aes_ocb.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "f87f0b6a8e04bcdeb98afc82b0da06a2d537f399", "commit_url": "https://github.com/openssl/openssl/commit/f87f0b6a8e04bcdeb98afc82b0da06a2d537f399", "cve": "CVE-2026-45445", "cwe": "CWE-119", "file": "openssl-cve-2026-45445/fixed.c", "function": "aes_ocb_cipher", "id": "openssl-cve-2026-45445:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-45445", "project": "openssl", "relpath": "providers/implementations/ciphers/cipher_aes_ocb.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "0f3fab2eccc7c3417093a8243dd15d95b6cb472d", "commit_url": "https://github.com/openssl/openssl/commit/b3a555a0a7aa0028887149f6f973af89a4937bea", "cve": "CVE-2026-42771", "cwe": "CWE-119", "file": "openssl-cve-2026-42771/vuln.c", "function": "validate_hostname_part", "id": "openssl-cve-2026-42771:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-42771", "project": "openssl", "relpath": "crypto/x509/x509_vpm.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "b3a555a0a7aa0028887149f6f973af89a4937bea", "commit_url": "https://github.com/openssl/openssl/commit/b3a555a0a7aa0028887149f6f973af89a4937bea", "cve": "CVE-2026-42771", "cwe": "CWE-119", "file": "openssl-cve-2026-42771/fixed.c", "function": "validate_hostname_part", "id": "openssl-cve-2026-42771:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-42771", "project": "openssl", "relpath": "crypto/x509/x509_vpm.c", "repo": "openssl/openssl", "year": 2026} +{"class": "null pointer dereference", "commit": "d5030cdf32d6cd27bd964a0cb7aed2b7cb713369", "commit_url": "https://github.com/openssl/openssl/commit/c2765d53c2649b56bc1ca1bb799e42002953056a", "cve": "CVE-2026-42769", "cwe": "CWE-476", "file": "openssl-cve-2026-42769/vuln.c", "function": "selfsigned_verify_cb", "id": "openssl-cve-2026-42769:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-42769", "project": "openssl", "relpath": "crypto/cmp/cmp_genm.c", "repo": "openssl/openssl", "year": 2026} +{"class": "null pointer dereference", "commit": "c2765d53c2649b56bc1ca1bb799e42002953056a", "commit_url": "https://github.com/openssl/openssl/commit/c2765d53c2649b56bc1ca1bb799e42002953056a", "cve": "CVE-2026-42769", "cwe": "CWE-476", "file": "openssl-cve-2026-42769/fixed.c", "function": "selfsigned_verify_cb", "id": "openssl-cve-2026-42769:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-42769", "project": "openssl", "relpath": "crypto/cmp/cmp_genm.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "f04d65692dd8109be9f387ce2ddd9fb1ab612b6b", "commit_url": "https://github.com/openssl/openssl/commit/d5030cdf32d6cd27bd964a0cb7aed2b7cb713369", "cve": "CVE-2026-42768", "cwe": "CWE-119", "file": "openssl-cve-2026-42768/vuln.c", "function": "cms_RecipientInfo_ktri_decrypt", "id": "openssl-cve-2026-42768:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-42768", "project": "openssl", "relpath": "crypto/cms/cms_env.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "d5030cdf32d6cd27bd964a0cb7aed2b7cb713369", "commit_url": "https://github.com/openssl/openssl/commit/d5030cdf32d6cd27bd964a0cb7aed2b7cb713369", "cve": "CVE-2026-42768", "cwe": "CWE-119", "file": "openssl-cve-2026-42768/fixed.c", "function": "cms_RecipientInfo_ktri_decrypt", "id": "openssl-cve-2026-42768:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-42768", "project": "openssl", "relpath": "crypto/cms/cms_env.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "f04d65692dd8109be9f387ce2ddd9fb1ab612b6b", "commit_url": "https://github.com/openssl/openssl/commit/d5030cdf32d6cd27bd964a0cb7aed2b7cb713369", "cve": "CVE-2026-42768", "cwe": "CWE-119", "file": "openssl-cve-2026-42768-pkcs7_decrypt_rinfo/vuln.c", "function": "pkcs7_decrypt_rinfo", "id": "openssl-cve-2026-42768-pkcs7_decrypt_rinfo:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-42768-pkcs7_decrypt_rinfo", "project": "openssl", "relpath": "crypto/pkcs7/pk7_doit.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "d5030cdf32d6cd27bd964a0cb7aed2b7cb713369", "commit_url": "https://github.com/openssl/openssl/commit/d5030cdf32d6cd27bd964a0cb7aed2b7cb713369", "cve": "CVE-2026-42768", "cwe": "CWE-119", "file": "openssl-cve-2026-42768-pkcs7_decrypt_rinfo/fixed.c", "function": "pkcs7_decrypt_rinfo", "id": "openssl-cve-2026-42768-pkcs7_decrypt_rinfo:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-42768-pkcs7_decrypt_rinfo", "project": "openssl", "relpath": "crypto/pkcs7/pk7_doit.c", "repo": "openssl/openssl", "year": 2026} +{"class": "null pointer dereference", "commit": "a9af3442290e8a04706a3cd5f284ffd5b486e3f6", "commit_url": "https://github.com/openssl/openssl/commit/74245170b5a64b234ac4af27c86a25ec251c8b2a", "cve": "CVE-2026-42766", "cwe": "CWE-476", "file": "openssl-cve-2026-42766/vuln.c", "function": "ossl_cms_RecipientInfo_pwri_crypt", "id": "openssl-cve-2026-42766:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-42766", "project": "openssl", "relpath": "crypto/cms/cms_pwri.c", "repo": "openssl/openssl", "year": 2026} +{"class": "null pointer dereference", "commit": "74245170b5a64b234ac4af27c86a25ec251c8b2a", "commit_url": "https://github.com/openssl/openssl/commit/74245170b5a64b234ac4af27c86a25ec251c8b2a", "cve": "CVE-2026-42766", "cwe": "CWE-476", "file": "openssl-cve-2026-42766/fixed.c", "function": "ossl_cms_RecipientInfo_pwri_crypt", "id": "openssl-cve-2026-42766:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-42766", "project": "openssl", "relpath": "crypto/cms/cms_pwri.c", "repo": "openssl/openssl", "year": 2026} +{"class": "null pointer dereference", "commit": "5097ec4dae239112498abb722e255ea60ef7ac48", "commit_url": "https://github.com/openssl/openssl/commit/a9af3442290e8a04706a3cd5f284ffd5b486e3f6", "cve": "CVE-2026-42765", "cwe": "CWE-476", "file": "openssl-cve-2026-42765/vuln.c", "function": "check_revocation", "id": "openssl-cve-2026-42765:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-42765", "project": "openssl", "relpath": "crypto/x509/x509_vfy.c", "repo": "openssl/openssl", "year": 2026} +{"class": "null pointer dereference", "commit": "a9af3442290e8a04706a3cd5f284ffd5b486e3f6", "commit_url": "https://github.com/openssl/openssl/commit/a9af3442290e8a04706a3cd5f284ffd5b486e3f6", "cve": "CVE-2026-42765", "cwe": "CWE-476", "file": "openssl-cve-2026-42765/fixed.c", "function": "check_revocation", "id": "openssl-cve-2026-42765:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-42765", "project": "openssl", "relpath": "crypto/x509/x509_vfy.c", "repo": "openssl/openssl", "year": 2026} +{"class": "null pointer dereference", "commit": "58633b658fe74095c8cdde191e4ce1bf94f8c5f9", "commit_url": "https://github.com/openssl/openssl/commit/5097ec4dae239112498abb722e255ea60ef7ac48", "cve": "CVE-2026-42764", "cwe": "CWE-476", "file": "openssl-cve-2026-42764/vuln.c", "function": "port_default_packet_handler", "id": "openssl-cve-2026-42764:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-42764", "project": "openssl", "relpath": "ssl/quic/quic_port.c", "repo": "openssl/openssl", "year": 2026} +{"class": "null pointer dereference", "commit": "5097ec4dae239112498abb722e255ea60ef7ac48", "commit_url": "https://github.com/openssl/openssl/commit/5097ec4dae239112498abb722e255ea60ef7ac48", "cve": "CVE-2026-42764", "cwe": "CWE-476", "file": "openssl-cve-2026-42764/fixed.c", "function": "port_default_packet_handler", "id": "openssl-cve-2026-42764:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-42764", "project": "openssl", "relpath": "ssl/quic/quic_port.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "68ef88913e321bdb47eee88118ceba18ed2388cd", "commit_url": "https://github.com/openssl/openssl/commit/58633b658fe74095c8cdde191e4ce1bf94f8c5f9", "cve": "CVE-2026-35188", "cwe": "CWE-119", "file": "openssl-cve-2026-35188/vuln.c", "function": "check_cert_ocsp_resp", "id": "openssl-cve-2026-35188:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-35188", "project": "openssl", "relpath": "crypto/x509/x509_vfy.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "58633b658fe74095c8cdde191e4ce1bf94f8c5f9", "commit_url": "https://github.com/openssl/openssl/commit/58633b658fe74095c8cdde191e4ce1bf94f8c5f9", "cve": "CVE-2026-35188", "cwe": "CWE-119", "file": "openssl-cve-2026-35188/fixed.c", "function": "check_cert_ocsp_resp", "id": "openssl-cve-2026-35188:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-35188", "project": "openssl", "relpath": "crypto/x509/x509_vfy.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "fcb23806047f5afbe55d5d601a527fc24bf7ca2c", "commit_url": "https://github.com/openssl/openssl/commit/5a0230b6cc95a576b0c2b7b5b2ba7c74232e7b7c", "cve": "CVE-2026-34181", "cwe": "CWE-119", "file": "openssl-cve-2026-34181/vuln.c", "function": "PBMAC1_PBKDF2_HMAC", "id": "openssl-cve-2026-34181:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-34181", "project": "openssl", "relpath": "crypto/pkcs12/p12_mutl.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "5a0230b6cc95a576b0c2b7b5b2ba7c74232e7b7c", "commit_url": "https://github.com/openssl/openssl/commit/5a0230b6cc95a576b0c2b7b5b2ba7c74232e7b7c", "cve": "CVE-2026-34181", "cwe": "CWE-119", "file": "openssl-cve-2026-34181/fixed.c", "function": "PBMAC1_PBKDF2_HMAC", "id": "openssl-cve-2026-34181:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-34181", "project": "openssl", "relpath": "crypto/pkcs12/p12_mutl.c", "repo": "openssl/openssl", "year": 2026} +{"class": "buffer overflow", "commit": "97f6b621f7af2c4c4e162c75045a6e12a8fdf8d9", "commit_url": "https://github.com/openssl/openssl/commit/51d1800e95283a8beec85152e35e3634dab8dd82", "cve": "CVE-2026-9076", "cwe": "CWE-119", "file": "openssl-cve-2026-9076/vuln.c", "function": "kek_unwrap_key", "id": "openssl-cve-2026-9076:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-9076", "project": "openssl", "relpath": "crypto/cms/cms_pwri.c", "repo": "openssl/openssl", "year": 2026} +{"class": "buffer overflow", "commit": "51d1800e95283a8beec85152e35e3634dab8dd82", "commit_url": "https://github.com/openssl/openssl/commit/51d1800e95283a8beec85152e35e3634dab8dd82", "cve": "CVE-2026-9076", "cwe": "CWE-119", "file": "openssl-cve-2026-9076/fixed.c", "function": "kek_unwrap_key", "id": "openssl-cve-2026-9076:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-9076", "project": "openssl", "relpath": "crypto/cms/cms_pwri.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "cb005ceaaf1fb50722e0101762a3e266338c5bf9", "commit_url": "https://github.com/openssl/openssl/commit/97f6b621f7af2c4c4e162c75045a6e12a8fdf8d9", "cve": "CVE-2026-7383", "cwe": "CWE-119", "file": "openssl-cve-2026-7383/vuln.c", "function": "ASN1_mbstring_ncopy", "id": "openssl-cve-2026-7383:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-7383", "project": "openssl", "relpath": "crypto/asn1/a_mbstr.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "97f6b621f7af2c4c4e162c75045a6e12a8fdf8d9", "commit_url": "https://github.com/openssl/openssl/commit/97f6b621f7af2c4c4e162c75045a6e12a8fdf8d9", "cve": "CVE-2026-7383", "cwe": "CWE-119", "file": "openssl-cve-2026-7383/fixed.c", "function": "ASN1_mbstring_ncopy", "id": "openssl-cve-2026-7383:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-7383", "project": "openssl", "relpath": "crypto/asn1/a_mbstr.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "a91e537d16d74050dbde50bb0dfb1fe9930f0521", "commit_url": "https://github.com/openssl/openssl/commit/eed200f58cd8645ed77e46b7e9f764e284df379e", "cve": "CVE-2026-31790", "cwe": "CWE-119", "file": "openssl-cve-2026-31790/vuln.c", "function": "rsasve_generate", "id": "openssl-cve-2026-31790:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-31790", "project": "openssl", "relpath": "providers/implementations/kem/rsa_kem.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "eed200f58cd8645ed77e46b7e9f764e284df379e", "commit_url": "https://github.com/openssl/openssl/commit/eed200f58cd8645ed77e46b7e9f764e284df379e", "cve": "CVE-2026-31790", "cwe": "CWE-119", "file": "openssl-cve-2026-31790/fixed.c", "function": "rsasve_generate", "id": "openssl-cve-2026-31790:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-31790", "project": "openssl", "relpath": "providers/implementations/kem/rsa_kem.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "a24216018e1ede8ff01a4ff5afff7dfbd443e2f9", "commit_url": "https://github.com/openssl/openssl/commit/abd8b2eec7e3f3fda60ecfb68498b246b52af482", "cve": "CVE-2026-31790", "cwe": "CWE-119", "file": "openssl-cve-2026-31790-rsasve_generate/vuln.in", "function": "rsasve_generate", "id": "openssl-cve-2026-31790-rsasve_generate:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-31790-rsasve_generate", "project": "openssl", "relpath": "providers/implementations/kem/rsa_kem.c.in", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "abd8b2eec7e3f3fda60ecfb68498b246b52af482", "commit_url": "https://github.com/openssl/openssl/commit/abd8b2eec7e3f3fda60ecfb68498b246b52af482", "cve": "CVE-2026-31790", "cwe": "CWE-119", "file": "openssl-cve-2026-31790-rsasve_generate/fixed.in", "function": "rsasve_generate", "id": "openssl-cve-2026-31790-rsasve_generate:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-31790-rsasve_generate", "project": "openssl", "relpath": "providers/implementations/kem/rsa_kem.c.in", "repo": "openssl/openssl", "year": 2026} +{"class": "buffer overflow", "commit": "b7ae7a093997b5cd549bc21cccd715510fef86c0", "commit_url": "https://github.com/openssl/openssl/commit/a91e537d16d74050dbde50bb0dfb1fe9930f0521", "cve": "CVE-2026-31789", "cwe": "CWE-119", "file": "openssl-cve-2026-31789/vuln.c", "function": "buf2hexstr_sep", "id": "openssl-cve-2026-31789:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-31789", "project": "openssl", "relpath": "crypto/o_str.c", "repo": "openssl/openssl", "year": 2026} +{"class": "buffer overflow", "commit": "a91e537d16d74050dbde50bb0dfb1fe9930f0521", "commit_url": "https://github.com/openssl/openssl/commit/a91e537d16d74050dbde50bb0dfb1fe9930f0521", "cve": "CVE-2026-31789", "cwe": "CWE-119", "file": "openssl-cve-2026-31789/fixed.c", "function": "buf2hexstr_sep", "id": "openssl-cve-2026-31789:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-31789", "project": "openssl", "relpath": "crypto/o_str.c", "repo": "openssl/openssl", "year": 2026} +{"class": "null pointer dereference", "commit": "d044f9252fe9a54001986fb4eb4e32076a056527", "commit_url": "https://github.com/openssl/openssl/commit/59c3b3158553ab53275bbbccca5cb305d591cf2e", "cve": "CVE-2026-28388", "cwe": "CWE-476", "file": "openssl-cve-2026-28388/vuln.c", "function": "check_delta_base", "id": "openssl-cve-2026-28388:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-28388", "project": "openssl", "relpath": "crypto/x509/x509_vfy.c", "repo": "openssl/openssl", "year": 2026} +{"class": "null pointer dereference", "commit": "59c3b3158553ab53275bbbccca5cb305d591cf2e", "commit_url": "https://github.com/openssl/openssl/commit/59c3b3158553ab53275bbbccca5cb305d591cf2e", "cve": "CVE-2026-28388", "cwe": "CWE-476", "file": "openssl-cve-2026-28388/fixed.c", "function": "check_delta_base", "id": "openssl-cve-2026-28388:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-28388", "project": "openssl", "relpath": "crypto/x509/x509_vfy.c", "repo": "openssl/openssl", "year": 2026} +{"class": "null pointer dereference", "commit": "6e74b1275cbc1fd1cf7ba32f662602d68501f6ca", "commit_url": "https://github.com/openssl/openssl/commit/af2a5fecd3e71a29e7568f9c1453dec5cebbaff4", "cve": "CVE-2026-28389", "cwe": "CWE-476", "file": "openssl-cve-2026-28389/vuln.c", "function": "rsa_cms_decrypt", "id": "openssl-cve-2026-28389:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-28389", "project": "openssl", "relpath": "crypto/cms/cms_rsa.c", "repo": "openssl/openssl", "year": 2026} +{"class": "null pointer dereference", "commit": "af2a5fecd3e71a29e7568f9c1453dec5cebbaff4", "commit_url": "https://github.com/openssl/openssl/commit/af2a5fecd3e71a29e7568f9c1453dec5cebbaff4", "cve": "CVE-2026-28389", "cwe": "CWE-476", "file": "openssl-cve-2026-28389/fixed.c", "function": "rsa_cms_decrypt", "id": "openssl-cve-2026-28389:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-28389", "project": "openssl", "relpath": "crypto/cms/cms_rsa.c", "repo": "openssl/openssl", "year": 2026} +{"class": "null pointer dereference", "commit": "72ec3e38c87f71f5c50ae3b16cc34d8371c71bb9", "commit_url": "https://github.com/openssl/openssl/commit/7b5274e812400cacb6f3be4c2df5340923fa807f", "cve": "CVE-2026-28389", "cwe": "CWE-476", "file": "openssl-cve-2026-28389-dh_cms_set_shared_info/vuln.c", "function": "dh_cms_set_shared_info", "id": "openssl-cve-2026-28389-dh_cms_set_shared_info:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-28389-dh_cms_set_shared_info", "project": "openssl", "relpath": "crypto/cms/cms_dh.c", "repo": "openssl/openssl", "year": 2026} +{"class": "null pointer dereference", "commit": "7b5274e812400cacb6f3be4c2df5340923fa807f", "commit_url": "https://github.com/openssl/openssl/commit/7b5274e812400cacb6f3be4c2df5340923fa807f", "cve": "CVE-2026-28389", "cwe": "CWE-476", "file": "openssl-cve-2026-28389-dh_cms_set_shared_info/fixed.c", "function": "dh_cms_set_shared_info", "id": "openssl-cve-2026-28389-dh_cms_set_shared_info:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-28389-dh_cms_set_shared_info", "project": "openssl", "relpath": "crypto/cms/cms_dh.c", "repo": "openssl/openssl", "year": 2026} +{"class": "null pointer dereference", "commit": "72ec3e38c87f71f5c50ae3b16cc34d8371c71bb9", "commit_url": "https://github.com/openssl/openssl/commit/7b5274e812400cacb6f3be4c2df5340923fa807f", "cve": "CVE-2026-28389", "cwe": "CWE-476", "file": "openssl-cve-2026-28389-ecdh_cms_set_shared_info/vuln.c", "function": "ecdh_cms_set_shared_info", "id": "openssl-cve-2026-28389-ecdh_cms_set_shared_info:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-28389-ecdh_cms_set_shared_info", "project": "openssl", "relpath": "crypto/cms/cms_ec.c", "repo": "openssl/openssl", "year": 2026} +{"class": "null pointer dereference", "commit": "7b5274e812400cacb6f3be4c2df5340923fa807f", "commit_url": "https://github.com/openssl/openssl/commit/7b5274e812400cacb6f3be4c2df5340923fa807f", "cve": "CVE-2026-28389", "cwe": "CWE-476", "file": "openssl-cve-2026-28389-ecdh_cms_set_shared_info/fixed.c", "function": "ecdh_cms_set_shared_info", "id": "openssl-cve-2026-28389-ecdh_cms_set_shared_info:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-28389-ecdh_cms_set_shared_info", "project": "openssl", "relpath": "crypto/cms/cms_ec.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "21d525dc846aed171fc886f3da614a6645948f13", "commit_url": "https://github.com/openssl/openssl/commit/85977e013f32ceb96aa034c0e741adddc1a05e34", "cve": "CVE-2026-2673", "cwe": "CWE-119", "file": "openssl-cve-2026-2673/vuln.c", "function": "gid_cb", "id": "openssl-cve-2026-2673:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2026-2673", "project": "openssl", "relpath": "ssl/t1_lib.c", "repo": "openssl/openssl", "year": 2026} +{"class": "security fix", "commit": "85977e013f32ceb96aa034c0e741adddc1a05e34", "commit_url": "https://github.com/openssl/openssl/commit/85977e013f32ceb96aa034c0e741adddc1a05e34", "cve": "CVE-2026-2673", "cwe": "CWE-119", "file": "openssl-cve-2026-2673/fixed.c", "function": "gid_cb", "id": "openssl-cve-2026-2673:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2026-2673", "project": "openssl", "relpath": "ssl/t1_lib.c", "repo": "openssl/openssl", "year": 2026} +{"class": "buffer overflow", "commit": "7565bb46fa2979511cb27aad1c2bd6b80adf7352", "commit_url": "https://github.com/openssl/openssl/commit/4191043c36f1a50c717a2d0075fc6f3b9bc0afc5", "cve": "CVE-2025-69419", "cwe": "CWE-119", "file": "openssl-cve-2025-69419/vuln.c", "function": "bmp_to_utf8", "id": "openssl-cve-2025-69419:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2025-69419", "project": "openssl", "relpath": "crypto/pkcs12/p12_utl.c", "repo": "openssl/openssl", "year": 2025} +{"class": "buffer overflow", "commit": "4191043c36f1a50c717a2d0075fc6f3b9bc0afc5", "commit_url": "https://github.com/openssl/openssl/commit/4191043c36f1a50c717a2d0075fc6f3b9bc0afc5", "cve": "CVE-2025-69419", "cwe": "CWE-119", "file": "openssl-cve-2025-69419/fixed.c", "function": "bmp_to_utf8", "id": "openssl-cve-2025-69419:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2025-69419", "project": "openssl", "relpath": "crypto/pkcs12/p12_utl.c", "repo": "openssl/openssl", "year": 2025} +{"class": "security fix", "commit": "475c466ef2fbd8fc1df6fae1c3eed9c813fc8ff6", "commit_url": "https://github.com/openssl/openssl/commit/52d23c86a54adab5ee9f80e48b242b52c4cc2347", "cve": "CVE-2025-69418", "cwe": "CWE-119", "file": "openssl-cve-2025-69418/vuln.c", "function": "CRYPTO_ocb128_encrypt", "id": "openssl-cve-2025-69418:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2025-69418", "project": "openssl", "relpath": "crypto/modes/ocb128.c", "repo": "openssl/openssl", "year": 2025} +{"class": "security fix", "commit": "52d23c86a54adab5ee9f80e48b242b52c4cc2347", "commit_url": "https://github.com/openssl/openssl/commit/52d23c86a54adab5ee9f80e48b242b52c4cc2347", "cve": "CVE-2025-69418", "cwe": "CWE-119", "file": "openssl-cve-2025-69418/fixed.c", "function": "CRYPTO_ocb128_encrypt", "id": "openssl-cve-2025-69418:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2025-69418", "project": "openssl", "relpath": "crypto/modes/ocb128.c", "repo": "openssl/openssl", "year": 2025} +{"class": "security fix", "commit": "384011202af92605d926fafe4a0bcd6b65d162ad", "commit_url": "https://github.com/openssl/openssl/commit/3ed1f75249932b155eef993a8e66a99cb98bfef4", "cve": "CVE-2025-66199", "cwe": "CWE-119", "file": "openssl-cve-2025-66199-tls13_process_compressed/vuln.c", "function": "tls13_process_compressed_certificate", "id": "openssl-cve-2025-66199-tls13_process_compressed:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2025-66199-tls13_process_compressed", "project": "openssl", "relpath": "ssl/statem/statem_lib.c", "repo": "openssl/openssl", "year": 2025} +{"class": "security fix", "commit": "3ed1f75249932b155eef993a8e66a99cb98bfef4", "commit_url": "https://github.com/openssl/openssl/commit/3ed1f75249932b155eef993a8e66a99cb98bfef4", "cve": "CVE-2025-66199", "cwe": "CWE-119", "file": "openssl-cve-2025-66199-tls13_process_compressed/fixed.c", "function": "tls13_process_compressed_certificate", "id": "openssl-cve-2025-66199-tls13_process_compressed:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2025-66199-tls13_process_compressed", "project": "openssl", "relpath": "ssl/statem/statem_lib.c", "repo": "openssl/openssl", "year": 2025} +{"class": "buffer overflow", "commit": "e0666f72294691a808443970b654412a6d92fa0f", "commit_url": "https://github.com/openssl/openssl/commit/475c466ef2fbd8fc1df6fae1c3eed9c813fc8ff6", "cve": "CVE-2025-68160", "cwe": "CWE-119", "file": "openssl-cve-2025-68160/vuln.c", "function": "linebuffer_write", "id": "openssl-cve-2025-68160:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2025-68160", "project": "openssl", "relpath": "crypto/bio/bf_lbuf.c", "repo": "openssl/openssl", "year": 2025} +{"class": "buffer overflow", "commit": "475c466ef2fbd8fc1df6fae1c3eed9c813fc8ff6", "commit_url": "https://github.com/openssl/openssl/commit/475c466ef2fbd8fc1df6fae1c3eed9c813fc8ff6", "cve": "CVE-2025-68160", "cwe": "CWE-119", "file": "openssl-cve-2025-68160/fixed.c", "function": "linebuffer_write", "id": "openssl-cve-2025-68160:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2025-68160", "project": "openssl", "relpath": "crypto/bio/bf_lbuf.c", "repo": "openssl/openssl", "year": 2025} +{"class": "security fix", "commit": "1f08e54bad32843044fe8a675948d65e3b4ece65", "commit_url": "https://github.com/openssl/openssl/commit/a7936fa4bd23c906e1955a16a0a0ab39a4953a61", "cve": "CVE-2025-15469", "cwe": "CWE-119", "file": "openssl-cve-2025-15469/vuln.c", "function": "do_fp_oneshot_sign", "id": "openssl-cve-2025-15469:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2025-15469", "project": "openssl", "relpath": "apps/dgst.c", "repo": "openssl/openssl", "year": 2025} +{"class": "security fix", "commit": "a7936fa4bd23c906e1955a16a0a0ab39a4953a61", "commit_url": "https://github.com/openssl/openssl/commit/a7936fa4bd23c906e1955a16a0a0ab39a4953a61", "cve": "CVE-2025-15469", "cwe": "CWE-119", "file": "openssl-cve-2025-15469/fixed.c", "function": "do_fp_oneshot_sign", "id": "openssl-cve-2025-15469:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2025-15469", "project": "openssl", "relpath": "apps/dgst.c", "repo": "openssl/openssl", "year": 2025} +{"class": "security fix", "commit": "3250efdfe99d2d7fe4fb05231add7fba864b7653", "commit_url": "https://github.com/openssl/openssl/commit/ce39170276daec87f55c39dad1f629b56344429e", "cve": "CVE-2025-15467", "cwe": "CWE-119", "file": "openssl-cve-2025-15467/vuln.c", "function": "evp_cipher_get_asn1_aead_params", "id": "openssl-cve-2025-15467:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2025-15467", "project": "openssl", "relpath": "crypto/evp/evp_lib.c", "repo": "openssl/openssl", "year": 2025} +{"class": "security fix", "commit": "ce39170276daec87f55c39dad1f629b56344429e", "commit_url": "https://github.com/openssl/openssl/commit/ce39170276daec87f55c39dad1f629b56344429e", "cve": "CVE-2025-15467", "cwe": "CWE-119", "file": "openssl-cve-2025-15467/fixed.c", "function": "evp_cipher_get_asn1_aead_params", "id": "openssl-cve-2025-15467:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2025-15467", "project": "openssl", "relpath": "crypto/evp/evp_lib.c", "repo": "openssl/openssl", "year": 2025} +{"class": "security fix", "commit": "b8654779e3b3b4eb0bda7623c0891d394e068187", "commit_url": "https://github.com/openssl/openssl/commit/205e3a55e16e4bd08c12fdbd3416ab829c0f6206", "cve": "CVE-2025-11187", "cwe": "CWE-119", "file": "openssl-cve-2025-11187/vuln.c", "function": "PBMAC1_PBKDF2_HMAC", "id": "openssl-cve-2025-11187:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2025-11187", "project": "openssl", "relpath": "crypto/pkcs12/p12_mutl.c", "repo": "openssl/openssl", "year": 2025} +{"class": "security fix", "commit": "205e3a55e16e4bd08c12fdbd3416ab829c0f6206", "commit_url": "https://github.com/openssl/openssl/commit/205e3a55e16e4bd08c12fdbd3416ab829c0f6206", "cve": "CVE-2025-11187", "cwe": "CWE-119", "file": "openssl-cve-2025-11187/fixed.c", "function": "PBMAC1_PBKDF2_HMAC", "id": "openssl-cve-2025-11187:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2025-11187", "project": "openssl", "relpath": "crypto/pkcs12/p12_mutl.c", "repo": "openssl/openssl", "year": 2025} +{"class": "security fix", "commit": "a79c4ce559c6a3a8fd4109e9f33c1185d5bf2def", "commit_url": "https://github.com/openssl/openssl/commit/654dc11d23468a74fc8ea4672b702dd3feb7be4b", "cve": "CVE-2025-9232", "cwe": "CWE-119", "file": "openssl-cve-2025-9232/vuln.c", "function": "use_proxy", "id": "openssl-cve-2025-9232:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2025-9232", "project": "openssl", "relpath": "crypto/http/http_lib.c", "repo": "openssl/openssl", "year": 2025} +{"class": "security fix", "commit": "654dc11d23468a74fc8ea4672b702dd3feb7be4b", "commit_url": "https://github.com/openssl/openssl/commit/654dc11d23468a74fc8ea4672b702dd3feb7be4b", "cve": "CVE-2025-9232", "cwe": "CWE-119", "file": "openssl-cve-2025-9232/fixed.c", "function": "use_proxy", "id": "openssl-cve-2025-9232:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2025-9232", "project": "openssl", "relpath": "crypto/http/http_lib.c", "repo": "openssl/openssl", "year": 2025} +{"class": "buffer overflow", "commit": "7e0fc054a08706d194d3355aba4a06003cadfb29", "commit_url": "https://github.com/openssl/openssl/commit/a79c4ce559c6a3a8fd4109e9f33c1185d5bf2def", "cve": "CVE-2025-9230", "cwe": "CWE-119", "file": "openssl-cve-2025-9230/vuln.c", "function": "kek_unwrap_key", "id": "openssl-cve-2025-9230:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2025-9230", "project": "openssl", "relpath": "crypto/cms/cms_pwri.c", "repo": "openssl/openssl", "year": 2025} +{"class": "buffer overflow", "commit": "a79c4ce559c6a3a8fd4109e9f33c1185d5bf2def", "commit_url": "https://github.com/openssl/openssl/commit/a79c4ce559c6a3a8fd4109e9f33c1185d5bf2def", "cve": "CVE-2025-9230", "cwe": "CWE-119", "file": "openssl-cve-2025-9230/fixed.c", "function": "kek_unwrap_key", "id": "openssl-cve-2025-9230:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2025-9230", "project": "openssl", "relpath": "crypto/cms/cms_pwri.c", "repo": "openssl/openssl", "year": 2025} +{"class": "security fix", "commit": "0db27ec7f8abd258d2e8849ac555ca26ba0cd8d6", "commit_url": "https://github.com/openssl/openssl/commit/798779d43494549b611233f92652f0da5328fbe7", "cve": "CVE-2024-12797", "cwe": "CWE-119", "file": "openssl-cve-2024-12797/vuln.c", "function": "tls_post_process_server_rpk", "id": "openssl-cve-2024-12797:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2024-12797", "project": "openssl", "relpath": "ssl/statem/statem_clnt.c", "repo": "openssl/openssl", "year": 2024} +{"class": "security fix", "commit": "798779d43494549b611233f92652f0da5328fbe7", "commit_url": "https://github.com/openssl/openssl/commit/798779d43494549b611233f92652f0da5328fbe7", "cve": "CVE-2024-12797", "cwe": "CWE-119", "file": "openssl-cve-2024-12797/fixed.c", "function": "tls_post_process_server_rpk", "id": "openssl-cve-2024-12797:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2024-12797", "project": "openssl", "relpath": "ssl/statem/statem_clnt.c", "repo": "openssl/openssl", "year": 2024} +{"class": "security fix", "commit": "643de602771f6b38ad7823e26d5a63c669eb185b", "commit_url": "https://github.com/openssl/openssl/commit/07272b05b04836a762b4baa874958af51d513844", "cve": "CVE-2024-13176", "cwe": "CWE-119", "file": "openssl-cve-2024-13176-ec_field_inverse_mod_ord/vuln.c", "function": "ec_field_inverse_mod_ord", "id": "openssl-cve-2024-13176-ec_field_inverse_mod_ord:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2024-13176-ec_field_inverse_mod_ord", "project": "openssl", "relpath": "crypto/ec/ec_lib.c", "repo": "openssl/openssl", "year": 2024} +{"class": "security fix", "commit": "07272b05b04836a762b4baa874958af51d513844", "commit_url": "https://github.com/openssl/openssl/commit/07272b05b04836a762b4baa874958af51d513844", "cve": "CVE-2024-13176", "cwe": "CWE-119", "file": "openssl-cve-2024-13176-ec_field_inverse_mod_ord/fixed.c", "function": "ec_field_inverse_mod_ord", "id": "openssl-cve-2024-13176-ec_field_inverse_mod_ord:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2024-13176-ec_field_inverse_mod_ord", "project": "openssl", "relpath": "crypto/ec/ec_lib.c", "repo": "openssl/openssl", "year": 2024} +{"class": "security fix", "commit": "9aae56395aa8e77c44a9df83fd395a644d016635", "commit_url": "https://github.com/openssl/openssl/commit/06d1dc3fa96a2ba5a3e22735a033012aadc9f0d6", "cve": "CVE-2024-6119", "cwe": "CWE-119", "file": "openssl-cve-2024-6119/vuln.c", "function": "do_x509_check", "id": "openssl-cve-2024-6119:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2024-6119", "project": "openssl", "relpath": "crypto/x509/v3_utl.c", "repo": "openssl/openssl", "year": 2024} +{"class": "security fix", "commit": "06d1dc3fa96a2ba5a3e22735a033012aadc9f0d6", "commit_url": "https://github.com/openssl/openssl/commit/06d1dc3fa96a2ba5a3e22735a033012aadc9f0d6", "cve": "CVE-2024-6119", "cwe": "CWE-119", "file": "openssl-cve-2024-6119/fixed.c", "function": "do_x509_check", "id": "openssl-cve-2024-6119:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2024-6119", "project": "openssl", "relpath": "crypto/x509/v3_utl.c", "repo": "openssl/openssl", "year": 2024} +{"class": "security fix", "commit": "189a7ed3e380e34ea38fe4190a7c9396bace0fb7", "commit_url": "https://github.com/openssl/openssl/commit/4b375b998798dd516d367036773073e1b88e6433", "cve": "CVE-2024-5535", "cwe": "CWE-119", "file": "openssl-cve-2024-5535/vuln.c", "function": "tls_parse_stoc_alpn", "id": "openssl-cve-2024-5535:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2024-5535", "project": "openssl", "relpath": "ssl/statem/extensions_clnt.c", "repo": "openssl/openssl", "year": 2024} +{"class": "security fix", "commit": "4b375b998798dd516d367036773073e1b88e6433", "commit_url": "https://github.com/openssl/openssl/commit/4b375b998798dd516d367036773073e1b88e6433", "cve": "CVE-2024-5535", "cwe": "CWE-119", "file": "openssl-cve-2024-5535/fixed.c", "function": "tls_parse_stoc_alpn", "id": "openssl-cve-2024-5535:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2024-5535", "project": "openssl", "relpath": "ssl/statem/extensions_clnt.c", "repo": "openssl/openssl", "year": 2024} +{"class": "security fix", "commit": "72394c9a1a6a6b07edf43eb2ad7e95e1093ada1b", "commit_url": "https://github.com/openssl/openssl/commit/189a7ed3e380e34ea38fe4190a7c9396bace0fb7", "cve": "CVE-2024-5535", "cwe": "CWE-119", "file": "openssl-cve-2024-5535-tls_construct_stoc_next_/vuln.c", "function": "tls_construct_stoc_next_proto_neg", "id": "openssl-cve-2024-5535-tls_construct_stoc_next_:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2024-5535-tls_construct_stoc_next_", "project": "openssl", "relpath": "ssl/statem/extensions_srvr.c", "repo": "openssl/openssl", "year": 2024} +{"class": "security fix", "commit": "189a7ed3e380e34ea38fe4190a7c9396bace0fb7", "commit_url": "https://github.com/openssl/openssl/commit/189a7ed3e380e34ea38fe4190a7c9396bace0fb7", "cve": "CVE-2024-5535", "cwe": "CWE-119", "file": "openssl-cve-2024-5535-tls_construct_stoc_next_/fixed.c", "function": "tls_construct_stoc_next_proto_neg", "id": "openssl-cve-2024-5535-tls_construct_stoc_next_:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2024-5535-tls_construct_stoc_next_", "project": "openssl", "relpath": "ssl/statem/extensions_srvr.c", "repo": "openssl/openssl", "year": 2024} +{"class": "security fix", "commit": "cf6f91f6121f4db167405db2f0de410a456f260c", "commit_url": "https://github.com/openssl/openssl/commit/159921152fd4aa91e4c849fd281ad93ac0d0d0ba", "cve": "CVE-2024-5535", "cwe": "CWE-119", "file": "openssl-cve-2024-5535-tls_parse_stoc_npn/vuln.c", "function": "tls_parse_stoc_npn", "id": "openssl-cve-2024-5535-tls_parse_stoc_npn:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2024-5535-tls_parse_stoc_npn", "project": "openssl", "relpath": "ssl/statem/extensions_clnt.c", "repo": "openssl/openssl", "year": 2024} +{"class": "security fix", "commit": "159921152fd4aa91e4c849fd281ad93ac0d0d0ba", "commit_url": "https://github.com/openssl/openssl/commit/159921152fd4aa91e4c849fd281ad93ac0d0d0ba", "cve": "CVE-2024-5535", "cwe": "CWE-119", "file": "openssl-cve-2024-5535-tls_parse_stoc_npn/fixed.c", "function": "tls_parse_stoc_npn", "id": "openssl-cve-2024-5535-tls_parse_stoc_npn:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2024-5535-tls_parse_stoc_npn", "project": "openssl", "relpath": "ssl/statem/extensions_clnt.c", "repo": "openssl/openssl", "year": 2024} +{"class": "security fix", "commit": "a6facb1042adda2394dc5c98fbceb7625eef141a", "commit_url": "https://github.com/openssl/openssl/commit/cf6f91f6121f4db167405db2f0de410a456f260c", "cve": "CVE-2024-5535", "cwe": "CWE-119", "file": "openssl-cve-2024-5535-ssl_select_next_proto/vuln.c", "function": "SSL_select_next_proto", "id": "openssl-cve-2024-5535-ssl_select_next_proto:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2024-5535-ssl_select_next_proto", "project": "openssl", "relpath": "ssl/ssl_lib.c", "repo": "openssl/openssl", "year": 2024} +{"class": "security fix", "commit": "cf6f91f6121f4db167405db2f0de410a456f260c", "commit_url": "https://github.com/openssl/openssl/commit/cf6f91f6121f4db167405db2f0de410a456f260c", "cve": "CVE-2024-5535", "cwe": "CWE-119", "file": "openssl-cve-2024-5535-ssl_select_next_proto/fixed.c", "function": "SSL_select_next_proto", "id": "openssl-cve-2024-5535-ssl_select_next_proto:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2024-5535-ssl_select_next_proto", "project": "openssl", "relpath": "ssl/ssl_lib.c", "repo": "openssl/openssl", "year": 2024} +{"class": "security fix", "commit": "015255851371757d54c2560643eb3b3a88123cf1", "commit_url": "https://github.com/openssl/openssl/commit/6cc511826f09e513b4ec066d9b95acaf4f86d991", "cve": "CVE-2024-5535", "cwe": "CWE-119", "file": "openssl-cve-2024-5535-alpn_select_cb/vuln.c", "function": "alpn_select_cb", "id": "openssl-cve-2024-5535-alpn_select_cb:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2024-5535-alpn_select_cb", "project": "openssl", "relpath": "ssl/quic/quic_tserver.c", "repo": "openssl/openssl", "year": 2024} +{"class": "security fix", "commit": "6cc511826f09e513b4ec066d9b95acaf4f86d991", "commit_url": "https://github.com/openssl/openssl/commit/6cc511826f09e513b4ec066d9b95acaf4f86d991", "cve": "CVE-2024-5535", "cwe": "CWE-119", "file": "openssl-cve-2024-5535-alpn_select_cb/fixed.c", "function": "alpn_select_cb", "id": "openssl-cve-2024-5535-alpn_select_cb:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2024-5535-alpn_select_cb", "project": "openssl", "relpath": "ssl/quic/quic_tserver.c", "repo": "openssl/openssl", "year": 2024} +{"class": "use after free", "commit": "b3f0eb0a295f58f16ba43ba99dad70d4ee5c437d", "commit_url": "https://github.com/openssl/openssl/commit/2d05959073c4bf8803401668b9df85931a08e020", "cve": "CVE-2024-4741", "cwe": "CWE-416", "file": "openssl-cve-2024-4741/vuln.c", "function": "ssl3_read_n", "id": "openssl-cve-2024-4741:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2024-4741", "project": "openssl", "relpath": "ssl/record/rec_layer_s3.c", "repo": "openssl/openssl", "year": 2024} +{"class": "use after free", "commit": "2d05959073c4bf8803401668b9df85931a08e020", "commit_url": "https://github.com/openssl/openssl/commit/2d05959073c4bf8803401668b9df85931a08e020", "cve": "CVE-2024-4741", "cwe": "CWE-416", "file": "openssl-cve-2024-4741/fixed.c", "function": "ssl3_read_n", "id": "openssl-cve-2024-4741:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2024-4741", "project": "openssl", "relpath": "ssl/record/rec_layer_s3.c", "repo": "openssl/openssl", "year": 2024} +{"class": "use after free", "commit": "b3f0eb0a295f58f16ba43ba99dad70d4ee5c437d", "commit_url": "https://github.com/openssl/openssl/commit/2d05959073c4bf8803401668b9df85931a08e020", "cve": "CVE-2024-4741", "cwe": "CWE-416", "file": "openssl-cve-2024-4741-ssl3_release_read_buffer/vuln.c", "function": "ssl3_release_read_buffer", "id": "openssl-cve-2024-4741-ssl3_release_read_buffer:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2024-4741-ssl3_release_read_buffer", "project": "openssl", "relpath": "ssl/record/ssl3_buffer.c", "repo": "openssl/openssl", "year": 2024} +{"class": "use after free", "commit": "2d05959073c4bf8803401668b9df85931a08e020", "commit_url": "https://github.com/openssl/openssl/commit/2d05959073c4bf8803401668b9df85931a08e020", "cve": "CVE-2024-4741", "cwe": "CWE-416", "file": "openssl-cve-2024-4741-ssl3_release_read_buffer/fixed.c", "function": "ssl3_release_read_buffer", "id": "openssl-cve-2024-4741-ssl3_release_read_buffer:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2024-4741-ssl3_release_read_buffer", "project": "openssl", "relpath": "ssl/record/ssl3_buffer.c", "repo": "openssl/openssl", "year": 2024} +{"class": "security fix", "commit": "ec559c2a6cca3fd4cedae5c47f2dfa38e5e24865", "commit_url": "https://github.com/openssl/openssl/commit/b3f0eb0a295f58f16ba43ba99dad70d4ee5c437d", "cve": "CVE-2024-4741", "cwe": "CWE-119", "file": "openssl-cve-2024-4741-ssl_free_buffers/vuln.c", "function": "SSL_free_buffers", "id": "openssl-cve-2024-4741-ssl_free_buffers:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2024-4741-ssl_free_buffers", "project": "openssl", "relpath": "ssl/ssl_lib.c", "repo": "openssl/openssl", "year": 2024} +{"class": "security fix", "commit": "b3f0eb0a295f58f16ba43ba99dad70d4ee5c437d", "commit_url": "https://github.com/openssl/openssl/commit/b3f0eb0a295f58f16ba43ba99dad70d4ee5c437d", "cve": "CVE-2024-4741", "cwe": "CWE-119", "file": "openssl-cve-2024-4741-ssl_free_buffers/fixed.c", "function": "SSL_free_buffers", "id": "openssl-cve-2024-4741-ssl_free_buffers:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2024-4741-ssl_free_buffers", "project": "openssl", "relpath": "ssl/ssl_lib.c", "repo": "openssl/openssl", "year": 2024} +{"class": "use after free", "commit": "c88c3de51020c37e8706bf7a682a162593053aac", "commit_url": "https://github.com/openssl/openssl/commit/10171e5b511b700c5ecd4fd3e1086b19c34b1ae3", "cve": "CVE-2024-4741", "cwe": "CWE-416", "file": "openssl-cve-2024-4741-tls_release_read_buffer/vuln.c", "function": "tls_release_read_buffer", "id": "openssl-cve-2024-4741-tls_release_read_buffer:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2024-4741-tls_release_read_buffer", "project": "openssl", "relpath": "ssl/record/methods/tls_common.c", "repo": "openssl/openssl", "year": 2024} +{"class": "use after free", "commit": "10171e5b511b700c5ecd4fd3e1086b19c34b1ae3", "commit_url": "https://github.com/openssl/openssl/commit/10171e5b511b700c5ecd4fd3e1086b19c34b1ae3", "cve": "CVE-2024-4741", "cwe": "CWE-416", "file": "openssl-cve-2024-4741-tls_release_read_buffer/fixed.c", "function": "tls_release_read_buffer", "id": "openssl-cve-2024-4741-tls_release_read_buffer:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2024-4741-tls_release_read_buffer", "project": "openssl", "relpath": "ssl/record/methods/tls_common.c", "repo": "openssl/openssl", "year": 2024} +{"class": "security fix", "commit": "17765d9cefed8b4ada6548719beb98e22672a9bd", "commit_url": "https://github.com/openssl/openssl/commit/c88c3de51020c37e8706bf7a682a162593053aac", "cve": "CVE-2024-4741", "cwe": "CWE-119", "file": "openssl-cve-2024-4741-tls_free_buffers/vuln.c", "function": "tls_free_buffers", "id": "openssl-cve-2024-4741-tls_free_buffers:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2024-4741-tls_free_buffers", "project": "openssl", "relpath": "ssl/record/methods/tls_common.c", "repo": "openssl/openssl", "year": 2024} +{"class": "security fix", "commit": "c88c3de51020c37e8706bf7a682a162593053aac", "commit_url": "https://github.com/openssl/openssl/commit/c88c3de51020c37e8706bf7a682a162593053aac", "cve": "CVE-2024-4741", "cwe": "CWE-119", "file": "openssl-cve-2024-4741-tls_free_buffers/fixed.c", "function": "tls_free_buffers", "id": "openssl-cve-2024-4741-tls_free_buffers:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2024-4741-tls_free_buffers", "project": "openssl", "relpath": "ssl/record/methods/tls_common.c", "repo": "openssl/openssl", "year": 2024} +{"class": "security fix", "commit": "d4b119c567cb5dcaf83add7ca2ea1d646eb3ef9f", "commit_url": "https://github.com/openssl/openssl/commit/3559e868e58005d15c6013a0c1fd832e51c73397", "cve": "CVE-2024-4603", "cwe": "CWE-119", "file": "openssl-cve-2024-4603/vuln.c", "function": "ossl_dsa_check_params", "id": "openssl-cve-2024-4603:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2024-4603", "project": "openssl", "relpath": "crypto/dsa/dsa_check.c", "repo": "openssl/openssl", "year": 2024} +{"class": "security fix", "commit": "3559e868e58005d15c6013a0c1fd832e51c73397", "commit_url": "https://github.com/openssl/openssl/commit/3559e868e58005d15c6013a0c1fd832e51c73397", "cve": "CVE-2024-4603", "cwe": "CWE-119", "file": "openssl-cve-2024-4603/fixed.c", "function": "ossl_dsa_check_params", "id": "openssl-cve-2024-4603:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2024-4603", "project": "openssl", "relpath": "crypto/dsa/dsa_check.c", "repo": "openssl/openssl", "year": 2024} +{"class": "security fix", "commit": "c1e462ee4bd61867ee391fc13110ca41e4889535", "commit_url": "https://github.com/openssl/openssl/commit/b52867a9f618bb955bed2a3ce3db4d4f97ed8e5d", "cve": "CVE-2024-2511", "cwe": "CWE-119", "file": "openssl-cve-2024-2511/vuln.c", "function": "ssl_update_cache", "id": "openssl-cve-2024-2511:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2024-2511", "project": "openssl", "relpath": "ssl/ssl_lib.c", "repo": "openssl/openssl", "year": 2024} +{"class": "security fix", "commit": "b52867a9f618bb955bed2a3ce3db4d4f97ed8e5d", "commit_url": "https://github.com/openssl/openssl/commit/b52867a9f618bb955bed2a3ce3db4d4f97ed8e5d", "cve": "CVE-2024-2511", "cwe": "CWE-119", "file": "openssl-cve-2024-2511/fixed.c", "function": "ssl_update_cache", "id": "openssl-cve-2024-2511:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2024-2511", "project": "openssl", "relpath": "ssl/ssl_lib.c", "repo": "openssl/openssl", "year": 2024} +{"class": "security fix", "commit": "c1e462ee4bd61867ee391fc13110ca41e4889535", "commit_url": "https://github.com/openssl/openssl/commit/b52867a9f618bb955bed2a3ce3db4d4f97ed8e5d", "cve": "CVE-2024-2511", "cwe": "CWE-119", "file": "openssl-cve-2024-2511-tls_construct_server_hel/vuln.c", "function": "tls_construct_server_hello", "id": "openssl-cve-2024-2511-tls_construct_server_hel:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2024-2511-tls_construct_server_hel", "project": "openssl", "relpath": "ssl/statem/statem_srvr.c", "repo": "openssl/openssl", "year": 2024} +{"class": "security fix", "commit": "b52867a9f618bb955bed2a3ce3db4d4f97ed8e5d", "commit_url": "https://github.com/openssl/openssl/commit/b52867a9f618bb955bed2a3ce3db4d4f97ed8e5d", "cve": "CVE-2024-2511", "cwe": "CWE-119", "file": "openssl-cve-2024-2511-tls_construct_server_hel/fixed.c", "function": "tls_construct_server_hello", "id": "openssl-cve-2024-2511-tls_construct_server_hel:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2024-2511-tls_construct_server_hel", "project": "openssl", "relpath": "ssl/statem/statem_srvr.c", "repo": "openssl/openssl", "year": 2024} +{"class": "null pointer dereference", "commit": "6c70934a46eaa1734c2efbe9d7baac51c607062e", "commit_url": "https://github.com/openssl/openssl/commit/09df4395b5071217b76dc7d3d2e630eb8c5a79c2", "cve": "CVE-2024-0727", "cwe": "CWE-476", "file": "openssl-cve-2024-0727/vuln.c", "function": "pkcs12_gen_mac", "id": "openssl-cve-2024-0727:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2024-0727", "project": "openssl", "relpath": "crypto/pkcs12/p12_mutl.c", "repo": "openssl/openssl", "year": 2024} +{"class": "null pointer dereference", "commit": "09df4395b5071217b76dc7d3d2e630eb8c5a79c2", "commit_url": "https://github.com/openssl/openssl/commit/09df4395b5071217b76dc7d3d2e630eb8c5a79c2", "cve": "CVE-2024-0727", "cwe": "CWE-476", "file": "openssl-cve-2024-0727/fixed.c", "function": "pkcs12_gen_mac", "id": "openssl-cve-2024-0727:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2024-0727", "project": "openssl", "relpath": "crypto/pkcs12/p12_mutl.c", "repo": "openssl/openssl", "year": 2024} +{"class": "null pointer dereference", "commit": "6c70934a46eaa1734c2efbe9d7baac51c607062e", "commit_url": "https://github.com/openssl/openssl/commit/09df4395b5071217b76dc7d3d2e630eb8c5a79c2", "cve": "CVE-2024-0727", "cwe": "CWE-476", "file": "openssl-cve-2024-0727-smime_write_pkcs7/vuln.c", "function": "SMIME_write_PKCS7", "id": "openssl-cve-2024-0727-smime_write_pkcs7:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2024-0727-smime_write_pkcs7", "project": "openssl", "relpath": "crypto/pkcs7/pk7_mime.c", "repo": "openssl/openssl", "year": 2024} +{"class": "null pointer dereference", "commit": "09df4395b5071217b76dc7d3d2e630eb8c5a79c2", "commit_url": "https://github.com/openssl/openssl/commit/09df4395b5071217b76dc7d3d2e630eb8c5a79c2", "cve": "CVE-2024-0727", "cwe": "CWE-476", "file": "openssl-cve-2024-0727-smime_write_pkcs7/fixed.c", "function": "SMIME_write_PKCS7", "id": "openssl-cve-2024-0727-smime_write_pkcs7:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2024-0727-smime_write_pkcs7", "project": "openssl", "relpath": "crypto/pkcs7/pk7_mime.c", "repo": "openssl/openssl", "year": 2024} +{"class": "security fix", "commit": "23d21359e35536a4ee8f7be0b245ddbfac909bff", "commit_url": "https://github.com/openssl/openssl/commit/0df40630850fb2740e6be6890bb905d3fc623b2d", "cve": "CVE-2023-5363", "cwe": "CWE-119", "file": "openssl-cve-2023-5363/vuln.c", "function": "evp_cipher_init_internal", "id": "openssl-cve-2023-5363:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2023-5363", "project": "openssl", "relpath": "crypto/evp/evp_enc.c", "repo": "openssl/openssl", "year": 2023} +{"class": "security fix", "commit": "0df40630850fb2740e6be6890bb905d3fc623b2d", "commit_url": "https://github.com/openssl/openssl/commit/0df40630850fb2740e6be6890bb905d3fc623b2d", "cve": "CVE-2023-5363", "cwe": "CWE-119", "file": "openssl-cve-2023-5363/fixed.c", "function": "evp_cipher_init_internal", "id": "openssl-cve-2023-5363:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2023-5363", "project": "openssl", "relpath": "crypto/evp/evp_enc.c", "repo": "openssl/openssl", "year": 2023} +{"class": "security fix", "commit": "e648db50d9a63f71cab5cb78424c2932d019a744", "commit_url": "https://github.com/openssl/openssl/commit/9002fd07327a91f35ba6c1307e71fa6fd4409b7f", "cve": "CVE-2023-3817", "cwe": "CWE-119", "file": "openssl-cve-2023-3817-dh_check/vuln.c", "function": "DH_check", "id": "openssl-cve-2023-3817-dh_check:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2023-3817-dh_check", "project": "openssl", "relpath": "crypto/dh/dh_check.c", "repo": "openssl/openssl", "year": 2023} +{"class": "security fix", "commit": "9002fd07327a91f35ba6c1307e71fa6fd4409b7f", "commit_url": "https://github.com/openssl/openssl/commit/9002fd07327a91f35ba6c1307e71fa6fd4409b7f", "cve": "CVE-2023-3817", "cwe": "CWE-119", "file": "openssl-cve-2023-3817-dh_check/fixed.c", "function": "DH_check", "id": "openssl-cve-2023-3817-dh_check:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2023-3817-dh_check", "project": "openssl", "relpath": "crypto/dh/dh_check.c", "repo": "openssl/openssl", "year": 2023} +{"class": "security fix", "commit": "fe824ce0c5d51e7e7cf36c31db6c49c1c0c04a25", "commit_url": "https://github.com/openssl/openssl/commit/8780a896543a654e757db1b9396383f9d8095528", "cve": "CVE-2023-3446", "cwe": "CWE-119", "file": "openssl-cve-2023-3446/vuln.c", "function": "DH_check", "id": "openssl-cve-2023-3446:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2023-3446", "project": "openssl", "relpath": "crypto/dh/dh_check.c", "repo": "openssl/openssl", "year": 2023} +{"class": "security fix", "commit": "8780a896543a654e757db1b9396383f9d8095528", "commit_url": "https://github.com/openssl/openssl/commit/8780a896543a654e757db1b9396383f9d8095528", "cve": "CVE-2023-3446", "cwe": "CWE-119", "file": "openssl-cve-2023-3446/fixed.c", "function": "DH_check", "id": "openssl-cve-2023-3446:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2023-3446", "project": "openssl", "relpath": "crypto/dh/dh_check.c", "repo": "openssl/openssl", "year": 2023} +{"class": "security fix", "commit": "175fa8469fc78f6cf35dfb87d26899e60e9ff1d4", "commit_url": "https://github.com/openssl/openssl/commit/00e2f5eea29994d19293ec4e8c8775ba73678598", "cve": "CVE-2023-2975", "cwe": "CWE-119", "file": "openssl-cve-2023-2975/vuln.c", "function": "siv_cipher", "id": "openssl-cve-2023-2975:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2023-2975", "project": "openssl", "relpath": "providers/implementations/ciphers/cipher_aes_siv.c", "repo": "openssl/openssl", "year": 2023} +{"class": "security fix", "commit": "00e2f5eea29994d19293ec4e8c8775ba73678598", "commit_url": "https://github.com/openssl/openssl/commit/00e2f5eea29994d19293ec4e8c8775ba73678598", "cve": "CVE-2023-2975", "cwe": "CWE-119", "file": "openssl-cve-2023-2975/fixed.c", "function": "siv_cipher", "id": "openssl-cve-2023-2975:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2023-2975", "project": "openssl", "relpath": "providers/implementations/ciphers/cipher_aes_siv.c", "repo": "openssl/openssl", "year": 2023} +{"class": "security fix", "commit": "3ca28c9e81fae36b0b44dc39beecd2b5a7561975", "commit_url": "https://github.com/openssl/openssl/commit/d63b3e7959e79f98d60760a739f7876dc5adc838", "cve": "CVE-2023-2650", "cwe": "CWE-119", "file": "openssl-cve-2023-2650/vuln.c", "function": "OBJ_obj2txt", "id": "openssl-cve-2023-2650:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2023-2650", "project": "openssl", "relpath": "crypto/objects/obj_dat.c", "repo": "openssl/openssl", "year": 2023} +{"class": "security fix", "commit": "d63b3e7959e79f98d60760a739f7876dc5adc838", "commit_url": "https://github.com/openssl/openssl/commit/d63b3e7959e79f98d60760a739f7876dc5adc838", "cve": "CVE-2023-2650", "cwe": "CWE-119", "file": "openssl-cve-2023-2650/fixed.c", "function": "OBJ_obj2txt", "id": "openssl-cve-2023-2650:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2023-2650", "project": "openssl", "relpath": "crypto/objects/obj_dat.c", "repo": "openssl/openssl", "year": 2023} +{"class": "buffer overflow", "commit": "5d6f13d90d5c4212737002bcd54871cf236a1220", "commit_url": "https://github.com/openssl/openssl/commit/d12cde7fc5561d463badcd8a73079cf92864c31e", "cve": "CVE-2022-37454", "cwe": "CWE-119", "file": "openssl-cve-2022-37454/vuln.c", "function": "HKDF_Expand", "id": "openssl-cve-2022-37454:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2022-37454", "project": "openssl", "relpath": "providers/implementations/kdfs/hkdf.c", "repo": "openssl/openssl", "year": 2022} +{"class": "buffer overflow", "commit": "d12cde7fc5561d463badcd8a73079cf92864c31e", "commit_url": "https://github.com/openssl/openssl/commit/d12cde7fc5561d463badcd8a73079cf92864c31e", "cve": "CVE-2022-37454", "cwe": "CWE-119", "file": "openssl-cve-2022-37454/fixed.c", "function": "HKDF_Expand", "id": "openssl-cve-2022-37454:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2022-37454", "project": "openssl", "relpath": "providers/implementations/kdfs/hkdf.c", "repo": "openssl/openssl", "year": 2022} +{"class": "security fix", "commit": "908eaceb62624f5b5c505b286d904bd3a4e8a64a", "commit_url": "https://github.com/openssl/openssl/commit/a00d757d9ca212994625d1a02c81cc5edd27e13b", "cve": "CVE-2022-4304", "cwe": "CWE-119", "file": "openssl-cve-2022-4304/vuln.c", "function": "bn_sub_words", "id": "openssl-cve-2022-4304:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2022-4304", "project": "openssl", "relpath": "crypto/bn/bn_asm.c", "repo": "openssl/openssl", "year": 2022} +{"class": "security fix", "commit": "a00d757d9ca212994625d1a02c81cc5edd27e13b", "commit_url": "https://github.com/openssl/openssl/commit/a00d757d9ca212994625d1a02c81cc5edd27e13b", "cve": "CVE-2022-4304", "cwe": "CWE-119", "file": "openssl-cve-2022-4304/fixed.c", "function": "bn_sub_words", "id": "openssl-cve-2022-4304:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2022-4304", "project": "openssl", "relpath": "crypto/bn/bn_asm.c", "repo": "openssl/openssl", "year": 2022} +{"class": "security fix", "commit": "908eaceb62624f5b5c505b286d904bd3a4e8a64a", "commit_url": "https://github.com/openssl/openssl/commit/a00d757d9ca212994625d1a02c81cc5edd27e13b", "cve": "CVE-2022-4304", "cwe": "CWE-119", "file": "openssl-cve-2022-4304-bn_blinding_invert_ex/vuln.c", "function": "BN_BLINDING_invert_ex", "id": "openssl-cve-2022-4304-bn_blinding_invert_ex:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2022-4304-bn_blinding_invert_ex", "project": "openssl", "relpath": "crypto/bn/bn_blind.c", "repo": "openssl/openssl", "year": 2022} +{"class": "security fix", "commit": "a00d757d9ca212994625d1a02c81cc5edd27e13b", "commit_url": "https://github.com/openssl/openssl/commit/a00d757d9ca212994625d1a02c81cc5edd27e13b", "cve": "CVE-2022-4304", "cwe": "CWE-119", "file": "openssl-cve-2022-4304-bn_blinding_invert_ex/fixed.c", "function": "BN_BLINDING_invert_ex", "id": "openssl-cve-2022-4304-bn_blinding_invert_ex:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2022-4304-bn_blinding_invert_ex", "project": "openssl", "relpath": "crypto/bn/bn_blind.c", "repo": "openssl/openssl", "year": 2022} +{"class": "security fix", "commit": "908eaceb62624f5b5c505b286d904bd3a4e8a64a", "commit_url": "https://github.com/openssl/openssl/commit/a00d757d9ca212994625d1a02c81cc5edd27e13b", "cve": "CVE-2022-4304", "cwe": "CWE-119", "file": "openssl-cve-2022-4304-rsa_blinding_invert/vuln.c", "function": "rsa_blinding_invert", "id": "openssl-cve-2022-4304-rsa_blinding_invert:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2022-4304-rsa_blinding_invert", "project": "openssl", "relpath": "crypto/rsa/rsa_ossl.c", "repo": "openssl/openssl", "year": 2022} +{"class": "security fix", "commit": "a00d757d9ca212994625d1a02c81cc5edd27e13b", "commit_url": "https://github.com/openssl/openssl/commit/a00d757d9ca212994625d1a02c81cc5edd27e13b", "cve": "CVE-2022-4304", "cwe": "CWE-119", "file": "openssl-cve-2022-4304-rsa_blinding_invert/fixed.c", "function": "rsa_blinding_invert", "id": "openssl-cve-2022-4304-rsa_blinding_invert:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2022-4304-rsa_blinding_invert", "project": "openssl", "relpath": "crypto/rsa/rsa_ossl.c", "repo": "openssl/openssl", "year": 2022} +{"class": "security fix", "commit": "f675d164e5d9648c3537a0f5efe1cc2fd232b4a9", "commit_url": "https://github.com/openssl/openssl/commit/b013765abfa80036dc779dd0e50602c57bb3bf95", "cve": "CVE-2023-0465", "cwe": "CWE-119", "file": "openssl-cve-2023-0465/vuln.c", "function": "check_policy", "id": "openssl-cve-2023-0465:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2023-0465", "project": "openssl", "relpath": "crypto/x509/x509_vfy.c", "repo": "openssl/openssl", "year": 2023} +{"class": "security fix", "commit": "b013765abfa80036dc779dd0e50602c57bb3bf95", "commit_url": "https://github.com/openssl/openssl/commit/b013765abfa80036dc779dd0e50602c57bb3bf95", "cve": "CVE-2023-0465", "cwe": "CWE-119", "file": "openssl-cve-2023-0465/fixed.c", "function": "check_policy", "id": "openssl-cve-2023-0465:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2023-0465", "project": "openssl", "relpath": "crypto/x509/x509_vfy.c", "repo": "openssl/openssl", "year": 2023} +{"class": "security fix", "commit": "969327390220aee7515a4054d5189186402d6687", "commit_url": "https://github.com/openssl/openssl/commit/879f7080d7e141f415c79eaa3a8ac4a3dad0348b", "cve": "CVE-2023-0464", "cwe": "CWE-119", "file": "openssl-cve-2023-0464/vuln.c", "function": "tree_init", "id": "openssl-cve-2023-0464:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2023-0464", "project": "openssl", "relpath": "crypto/x509v3/pcy_tree.c", "repo": "openssl/openssl", "year": 2023} +{"class": "security fix", "commit": "879f7080d7e141f415c79eaa3a8ac4a3dad0348b", "commit_url": "https://github.com/openssl/openssl/commit/879f7080d7e141f415c79eaa3a8ac4a3dad0348b", "cve": "CVE-2023-0464", "cwe": "CWE-119", "file": "openssl-cve-2023-0464/fixed.c", "function": "tree_init", "id": "openssl-cve-2023-0464:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2023-0464", "project": "openssl", "relpath": "crypto/x509v3/pcy_tree.c", "repo": "openssl/openssl", "year": 2023} +{"class": "security fix", "commit": "c309c4dce742c3eeb393a0f03f9c567d0e368ccc", "commit_url": "https://github.com/openssl/openssl/commit/959c59c7a0164117e7f8366466a32bb1f8d77ff1", "cve": "CVE-2023-0464", "cwe": "CWE-119", "file": "openssl-cve-2023-0464-tree_init/vuln.c", "function": "tree_init", "id": "openssl-cve-2023-0464-tree_init:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2023-0464-tree_init", "project": "openssl", "relpath": "crypto/x509/pcy_tree.c", "repo": "openssl/openssl", "year": 2023} +{"class": "security fix", "commit": "959c59c7a0164117e7f8366466a32bb1f8d77ff1", "commit_url": "https://github.com/openssl/openssl/commit/959c59c7a0164117e7f8366466a32bb1f8d77ff1", "cve": "CVE-2023-0464", "cwe": "CWE-119", "file": "openssl-cve-2023-0464-tree_init/fixed.c", "function": "tree_init", "id": "openssl-cve-2023-0464-tree_init:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2023-0464-tree_init", "project": "openssl", "relpath": "crypto/x509/pcy_tree.c", "repo": "openssl/openssl", "year": 2023} +{"class": "security fix", "commit": "7b2625274f5d5ec90aee522ec4e4f3aa08fa5b70", "commit_url": "https://github.com/openssl/openssl/commit/2b9e2afc382490592078cdb69d06f54f0fefd4c6", "cve": "CVE-2021-3449", "cwe": "CWE-119", "file": "openssl-cve-2021-3449/vuln.c", "function": "tls_get_more_records", "id": "openssl-cve-2021-3449:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2021-3449", "project": "openssl", "relpath": "ssl/record/methods/tls_common.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "2b9e2afc382490592078cdb69d06f54f0fefd4c6", "commit_url": "https://github.com/openssl/openssl/commit/2b9e2afc382490592078cdb69d06f54f0fefd4c6", "cve": "CVE-2021-3449", "cwe": "CWE-119", "file": "openssl-cve-2021-3449/fixed.c", "function": "tls_get_more_records", "id": "openssl-cve-2021-3449:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2021-3449", "project": "openssl", "relpath": "ssl/record/methods/tls_common.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "7b2625274f5d5ec90aee522ec4e4f3aa08fa5b70", "commit_url": "https://github.com/openssl/openssl/commit/2b9e2afc382490592078cdb69d06f54f0fefd4c6", "cve": "CVE-2021-3449", "cwe": "CWE-119", "file": "openssl-cve-2021-3449-def_generate_session_id/vuln.c", "function": "def_generate_session_id", "id": "openssl-cve-2021-3449-def_generate_session_id:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2021-3449-def_generate_session_id", "project": "openssl", "relpath": "ssl/ssl_sess.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "2b9e2afc382490592078cdb69d06f54f0fefd4c6", "commit_url": "https://github.com/openssl/openssl/commit/2b9e2afc382490592078cdb69d06f54f0fefd4c6", "cve": "CVE-2021-3449", "cwe": "CWE-119", "file": "openssl-cve-2021-3449-def_generate_session_id/fixed.c", "function": "def_generate_session_id", "id": "openssl-cve-2021-3449-def_generate_session_id:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2021-3449-def_generate_session_id", "project": "openssl", "relpath": "ssl/ssl_sess.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "7b2625274f5d5ec90aee522ec4e4f3aa08fa5b70", "commit_url": "https://github.com/openssl/openssl/commit/2b9e2afc382490592078cdb69d06f54f0fefd4c6", "cve": "CVE-2021-3449", "cwe": "CWE-119", "file": "openssl-cve-2021-3449-tls_parse_ctos_renegotia/vuln.c", "function": "tls_parse_ctos_renegotiate", "id": "openssl-cve-2021-3449-tls_parse_ctos_renegotia:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2021-3449-tls_parse_ctos_renegotia", "project": "openssl", "relpath": "ssl/statem/extensions_srvr.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "2b9e2afc382490592078cdb69d06f54f0fefd4c6", "commit_url": "https://github.com/openssl/openssl/commit/2b9e2afc382490592078cdb69d06f54f0fefd4c6", "cve": "CVE-2021-3449", "cwe": "CWE-119", "file": "openssl-cve-2021-3449-tls_parse_ctos_renegotia/fixed.c", "function": "tls_parse_ctos_renegotiate", "id": "openssl-cve-2021-3449-tls_parse_ctos_renegotia:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2021-3449-tls_parse_ctos_renegotia", "project": "openssl", "relpath": "ssl/statem/extensions_srvr.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "7b2625274f5d5ec90aee522ec4e4f3aa08fa5b70", "commit_url": "https://github.com/openssl/openssl/commit/2b9e2afc382490592078cdb69d06f54f0fefd4c6", "cve": "CVE-2021-3449", "cwe": "CWE-119", "file": "openssl-cve-2021-3449-tls_process_finished/vuln.c", "function": "tls_process_finished", "id": "openssl-cve-2021-3449-tls_process_finished:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2021-3449-tls_process_finished", "project": "openssl", "relpath": "ssl/statem/statem_lib.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "2b9e2afc382490592078cdb69d06f54f0fefd4c6", "commit_url": "https://github.com/openssl/openssl/commit/2b9e2afc382490592078cdb69d06f54f0fefd4c6", "cve": "CVE-2021-3449", "cwe": "CWE-119", "file": "openssl-cve-2021-3449-tls_process_finished/fixed.c", "function": "tls_process_finished", "id": "openssl-cve-2021-3449-tls_process_finished:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2021-3449-tls_process_finished", "project": "openssl", "relpath": "ssl/statem/statem_lib.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "7880536fe17c2b5450e279155bedd51771d28c9f", "commit_url": "https://github.com/openssl/openssl/commit/6eebe6c0238178356114a96a7858f36b24172847", "cve": "CVE-2023-0401", "cwe": "CWE-119", "file": "openssl-cve-2023-0401/vuln.c", "function": "pkcs7_bio_add_digest", "id": "openssl-cve-2023-0401:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2023-0401", "project": "openssl", "relpath": "crypto/pkcs7/pk7_doit.c", "repo": "openssl/openssl", "year": 2023} +{"class": "security fix", "commit": "6eebe6c0238178356114a96a7858f36b24172847", "commit_url": "https://github.com/openssl/openssl/commit/6eebe6c0238178356114a96a7858f36b24172847", "cve": "CVE-2023-0401", "cwe": "CWE-119", "file": "openssl-cve-2023-0401/fixed.c", "function": "pkcs7_bio_add_digest", "id": "openssl-cve-2023-0401:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2023-0401", "project": "openssl", "relpath": "crypto/pkcs7/pk7_doit.c", "repo": "openssl/openssl", "year": 2023} +{"class": "security fix", "commit": "adf77d6657e836fc87391fad53d857927a764297", "commit_url": "https://github.com/openssl/openssl/commit/7880536fe17c2b5450e279155bedd51771d28c9f", "cve": "CVE-2023-0286", "cwe": "CWE-119", "file": "openssl-cve-2023-0286-general_name_cmp/vuln.c", "function": "GENERAL_NAME_cmp", "id": "openssl-cve-2023-0286-general_name_cmp:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2023-0286-general_name_cmp", "project": "openssl", "relpath": "crypto/x509/v3_genn.c", "repo": "openssl/openssl", "year": 2023} +{"class": "security fix", "commit": "7880536fe17c2b5450e279155bedd51771d28c9f", "commit_url": "https://github.com/openssl/openssl/commit/7880536fe17c2b5450e279155bedd51771d28c9f", "cve": "CVE-2023-0286", "cwe": "CWE-119", "file": "openssl-cve-2023-0286-general_name_cmp/fixed.c", "function": "GENERAL_NAME_cmp", "id": "openssl-cve-2023-0286-general_name_cmp:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2023-0286-general_name_cmp", "project": "openssl", "relpath": "crypto/x509/v3_genn.c", "repo": "openssl/openssl", "year": 2023} +{"class": "security fix", "commit": "3436f9c24ab90c1661e4798e7944f028d5d251ce", "commit_url": "https://github.com/openssl/openssl/commit/bcec03c33cc00a7b5eb89ebeeee59e604570a86a", "cve": "CVE-2023-0217", "cwe": "CWE-119", "file": "openssl-cve-2023-0217/vuln.c", "function": "ossl_ffc_validate_public_key_partial", "id": "openssl-cve-2023-0217:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2023-0217", "project": "openssl", "relpath": "crypto/ffc/ffc_key_validate.c", "repo": "openssl/openssl", "year": 2023} +{"class": "security fix", "commit": "bcec03c33cc00a7b5eb89ebeeee59e604570a86a", "commit_url": "https://github.com/openssl/openssl/commit/bcec03c33cc00a7b5eb89ebeeee59e604570a86a", "cve": "CVE-2023-0217", "cwe": "CWE-119", "file": "openssl-cve-2023-0217/fixed.c", "function": "ossl_ffc_validate_public_key_partial", "id": "openssl-cve-2023-0217:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2023-0217", "project": "openssl", "relpath": "crypto/ffc/ffc_key_validate.c", "repo": "openssl/openssl", "year": 2023} +{"class": "security fix", "commit": "625faca931957719c76fb16094cf5b6e0debe23f", "commit_url": "https://github.com/openssl/openssl/commit/80253dbdc92bec584f4a9866b43f8674156d838a", "cve": "CVE-2023-0216", "cwe": "CWE-119", "file": "openssl-cve-2023-0216/vuln.c", "function": "STACK_OF", "id": "openssl-cve-2023-0216:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2023-0216", "project": "openssl", "relpath": "crypto/pkcs7/pk7_lib.c", "repo": "openssl/openssl", "year": 2023} +{"class": "security fix", "commit": "80253dbdc92bec584f4a9866b43f8674156d838a", "commit_url": "https://github.com/openssl/openssl/commit/80253dbdc92bec584f4a9866b43f8674156d838a", "cve": "CVE-2023-0216", "cwe": "CWE-119", "file": "openssl-cve-2023-0216/fixed.c", "function": "STACK_OF", "id": "openssl-cve-2023-0216:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2023-0216", "project": "openssl", "relpath": "crypto/pkcs7/pk7_lib.c", "repo": "openssl/openssl", "year": 2023} +{"class": "security fix", "commit": "e2d0a3b5f559e23f11e4d4687b2889b483afb22a", "commit_url": "https://github.com/openssl/openssl/commit/8022a4799fe884b3bf8d538e2b4c4ec323663118", "cve": "CVE-2022-4304", "cwe": "CWE-119", "file": "openssl-cve-2022-4304-rsa_ossl_private_decrypt/vuln.c", "function": "rsa_ossl_private_decrypt", "id": "openssl-cve-2022-4304-rsa_ossl_private_decrypt:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2022-4304-rsa_ossl_private_decrypt", "project": "openssl", "relpath": "crypto/rsa/rsa_ossl.c", "repo": "openssl/openssl", "year": 2022} +{"class": "security fix", "commit": "8022a4799fe884b3bf8d538e2b4c4ec323663118", "commit_url": "https://github.com/openssl/openssl/commit/8022a4799fe884b3bf8d538e2b4c4ec323663118", "cve": "CVE-2022-4304", "cwe": "CWE-119", "file": "openssl-cve-2022-4304-rsa_ossl_private_decrypt/fixed.c", "function": "rsa_ossl_private_decrypt", "id": "openssl-cve-2022-4304-rsa_ossl_private_decrypt:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2022-4304-rsa_ossl_private_decrypt", "project": "openssl", "relpath": "crypto/rsa/rsa_ossl.c", "repo": "openssl/openssl", "year": 2022} +{"class": "security fix", "commit": "1ca61aa56090356bbdbb16cf48916fbd9886c78d", "commit_url": "https://github.com/openssl/openssl/commit/7fc67e0a33102aa47bbaa56533eeecb98c0450f7", "cve": "CVE-2020-25659", "cwe": "CWE-119", "file": "openssl-cve-2020-25659/vuln.c", "function": "rsa_ossl_private_decrypt", "id": "openssl-cve-2020-25659:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2020-25659", "project": "openssl", "relpath": "crypto/rsa/rsa_ossl.c", "repo": "openssl/openssl", "year": 2020} +{"class": "security fix", "commit": "7fc67e0a33102aa47bbaa56533eeecb98c0450f7", "commit_url": "https://github.com/openssl/openssl/commit/7fc67e0a33102aa47bbaa56533eeecb98c0450f7", "cve": "CVE-2020-25659", "cwe": "CWE-119", "file": "openssl-cve-2020-25659/fixed.c", "function": "rsa_ossl_private_decrypt", "id": "openssl-cve-2020-25659:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2020-25659", "project": "openssl", "relpath": "crypto/rsa/rsa_ossl.c", "repo": "openssl/openssl", "year": 2020} +{"class": "security fix", "commit": "9a5c884999a55595e376083b3a165515c8123049", "commit_url": "https://github.com/openssl/openssl/commit/7725e7bfe6f2ce8146b6552b44e0d226be7638e7", "cve": "CVE-2022-3996", "cwe": "CWE-119", "file": "openssl-cve-2022-3996/vuln.c", "function": "ossl_policy_cache_set_mapping", "id": "openssl-cve-2022-3996:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2022-3996", "project": "openssl", "relpath": "crypto/x509/pcy_map.c", "repo": "openssl/openssl", "year": 2022} +{"class": "security fix", "commit": "7725e7bfe6f2ce8146b6552b44e0d226be7638e7", "commit_url": "https://github.com/openssl/openssl/commit/7725e7bfe6f2ce8146b6552b44e0d226be7638e7", "cve": "CVE-2022-3996", "cwe": "CWE-119", "file": "openssl-cve-2022-3996/fixed.c", "function": "ossl_policy_cache_set_mapping", "id": "openssl-cve-2022-3996:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2022-3996", "project": "openssl", "relpath": "crypto/x509/pcy_map.c", "repo": "openssl/openssl", "year": 2022} +{"class": "buffer overflow", "commit": "3b421ebc64c7b52f1b9feb3812bdc7781c784332", "commit_url": "https://github.com/openssl/openssl/commit/680e65b94c916af259bfdc2e25f1ab6e0c7a97d6", "cve": "CVE-2022-3786", "cwe": "CWE-119", "file": "openssl-cve-2022-3786-ossl_punycode_decode/vuln.c", "function": "ossl_punycode_decode", "id": "openssl-cve-2022-3786-ossl_punycode_decode:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2022-3786-ossl_punycode_decode", "project": "openssl", "relpath": "crypto/punycode.c", "repo": "openssl/openssl", "year": 2022} +{"class": "buffer overflow", "commit": "680e65b94c916af259bfdc2e25f1ab6e0c7a97d6", "commit_url": "https://github.com/openssl/openssl/commit/680e65b94c916af259bfdc2e25f1ab6e0c7a97d6", "cve": "CVE-2022-3786", "cwe": "CWE-119", "file": "openssl-cve-2022-3786-ossl_punycode_decode/fixed.c", "function": "ossl_punycode_decode", "id": "openssl-cve-2022-3786-ossl_punycode_decode:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2022-3786-ossl_punycode_decode", "project": "openssl", "relpath": "crypto/punycode.c", "repo": "openssl/openssl", "year": 2022} +{"class": "security fix", "commit": "89d72311327735ef15c804d2adea84a0fb1bfa0a", "commit_url": "https://github.com/openssl/openssl/commit/3b421ebc64c7b52f1b9feb3812bdc7781c784332", "cve": "CVE-2022-3602", "cwe": "CWE-119", "file": "openssl-cve-2022-3602-ossl_punycode_decode/vuln.c", "function": "ossl_punycode_decode", "id": "openssl-cve-2022-3602-ossl_punycode_decode:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2022-3602-ossl_punycode_decode", "project": "openssl", "relpath": "crypto/punycode.c", "repo": "openssl/openssl", "year": 2022} +{"class": "security fix", "commit": "3b421ebc64c7b52f1b9feb3812bdc7781c784332", "commit_url": "https://github.com/openssl/openssl/commit/3b421ebc64c7b52f1b9feb3812bdc7781c784332", "cve": "CVE-2022-3602", "cwe": "CWE-119", "file": "openssl-cve-2022-3602-ossl_punycode_decode/fixed.c", "function": "ossl_punycode_decode", "id": "openssl-cve-2022-3602-ossl_punycode_decode:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2022-3602-ossl_punycode_decode", "project": "openssl", "relpath": "crypto/punycode.c", "repo": "openssl/openssl", "year": 2022} +{"class": "null pointer dereference", "commit": "9f0867da4cbf77ed642717b5e703e09ab2c087a0", "commit_url": "https://github.com/openssl/openssl/commit/5485c56679d7c49b96e8fc8ca708b0b7e7c03c4b", "cve": "CVE-2022-3358", "cwe": "CWE-476", "file": "openssl-cve-2022-3358/vuln.c", "function": "evp_md_init_internal", "id": "openssl-cve-2022-3358:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2022-3358", "project": "openssl", "relpath": "crypto/evp/digest.c", "repo": "openssl/openssl", "year": 2022} +{"class": "null pointer dereference", "commit": "5485c56679d7c49b96e8fc8ca708b0b7e7c03c4b", "commit_url": "https://github.com/openssl/openssl/commit/5485c56679d7c49b96e8fc8ca708b0b7e7c03c4b", "cve": "CVE-2022-3358", "cwe": "CWE-476", "file": "openssl-cve-2022-3358/fixed.c", "function": "evp_md_init_internal", "id": "openssl-cve-2022-3358:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2022-3358", "project": "openssl", "relpath": "crypto/evp/digest.c", "repo": "openssl/openssl", "year": 2022} +{"class": "null pointer dereference", "commit": "9f0867da4cbf77ed642717b5e703e09ab2c087a0", "commit_url": "https://github.com/openssl/openssl/commit/5485c56679d7c49b96e8fc8ca708b0b7e7c03c4b", "cve": "CVE-2022-3358", "cwe": "CWE-476", "file": "openssl-cve-2022-3358-evp_cipher_init_internal/vuln.c", "function": "evp_cipher_init_internal", "id": "openssl-cve-2022-3358-evp_cipher_init_internal:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2022-3358-evp_cipher_init_internal", "project": "openssl", "relpath": "crypto/evp/evp_enc.c", "repo": "openssl/openssl", "year": 2022} +{"class": "null pointer dereference", "commit": "5485c56679d7c49b96e8fc8ca708b0b7e7c03c4b", "commit_url": "https://github.com/openssl/openssl/commit/5485c56679d7c49b96e8fc8ca708b0b7e7c03c4b", "cve": "CVE-2022-3358", "cwe": "CWE-476", "file": "openssl-cve-2022-3358-evp_cipher_init_internal/fixed.c", "function": "evp_cipher_init_internal", "id": "openssl-cve-2022-3358-evp_cipher_init_internal:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2022-3358-evp_cipher_init_internal", "project": "openssl", "relpath": "crypto/evp/evp_enc.c", "repo": "openssl/openssl", "year": 2022} +{"class": "security fix", "commit": "abebcec7b1a30fbb1fd5c5cbbe8817690c139163", "commit_url": "https://github.com/openssl/openssl/commit/2c9c35870601b4a44d86ddbf512b38df38285cfa", "cve": "CVE-2022-2068", "cwe": "CWE-119", "file": "openssl-cve-2022-2068-hash_dir/vuln.in", "function": "hash_dir", "id": "openssl-cve-2022-2068-hash_dir:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2022-2068-hash_dir", "project": "openssl", "relpath": "tools/c_rehash.in", "repo": "openssl/openssl", "year": 2022} +{"class": "security fix", "commit": "2c9c35870601b4a44d86ddbf512b38df38285cfa", "commit_url": "https://github.com/openssl/openssl/commit/2c9c35870601b4a44d86ddbf512b38df38285cfa", "cve": "CVE-2022-2068", "cwe": "CWE-119", "file": "openssl-cve-2022-2068-hash_dir/fixed.in", "function": "hash_dir", "id": "openssl-cve-2022-2068-hash_dir:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2022-2068-hash_dir", "project": "openssl", "relpath": "tools/c_rehash.in", "repo": "openssl/openssl", "year": 2022} +{"class": "security fix", "commit": "3be529cd2eb4eb3eaaa7913af619fb9c918d4581", "commit_url": "https://github.com/openssl/openssl/commit/373de40f3f76c63e4f2684abd86706f3863347ca", "cve": "CVE-2022-29242", "cwe": "CWE-119", "file": "openssl-cve-2022-29242/vuln.c", "function": "tls_construct_cke_gost18", "id": "openssl-cve-2022-29242:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2022-29242", "project": "openssl", "relpath": "ssl/statem/statem_clnt.c", "repo": "openssl/openssl", "year": 2022} +{"class": "security fix", "commit": "373de40f3f76c63e4f2684abd86706f3863347ca", "commit_url": "https://github.com/openssl/openssl/commit/373de40f3f76c63e4f2684abd86706f3863347ca", "cve": "CVE-2022-29242", "cwe": "CWE-119", "file": "openssl-cve-2022-29242/fixed.c", "function": "tls_construct_cke_gost18", "id": "openssl-cve-2022-29242:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2022-29242", "project": "openssl", "relpath": "ssl/statem/statem_clnt.c", "repo": "openssl/openssl", "year": 2022} +{"class": "security fix", "commit": "55c80c222293a972587004c185dc5653ae207a0e", "commit_url": "https://github.com/openssl/openssl/commit/7d56a74a96828985db7354a55227a511615f732b", "cve": "CVE-2022-1434", "cwe": "CWE-119", "file": "openssl-cve-2022-1434/vuln.c", "function": "rc4_hmac_md5_set_ctx_params", "id": "openssl-cve-2022-1434:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2022-1434", "project": "openssl", "relpath": "providers/implementations/ciphers/cipher_rc4_hmac_md5.c", "repo": "openssl/openssl", "year": 2022} +{"class": "security fix", "commit": "7d56a74a96828985db7354a55227a511615f732b", "commit_url": "https://github.com/openssl/openssl/commit/7d56a74a96828985db7354a55227a511615f732b", "cve": "CVE-2022-1434", "cwe": "CWE-119", "file": "openssl-cve-2022-1434/fixed.c", "function": "rc4_hmac_md5_set_ctx_params", "id": "openssl-cve-2022-1434:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2022-1434", "project": "openssl", "relpath": "providers/implementations/ciphers/cipher_rc4_hmac_md5.c", "repo": "openssl/openssl", "year": 2022} +{"class": "security fix", "commit": "ae3ece03a61e8822fd7ea58f44812871efba82d1", "commit_url": "https://github.com/openssl/openssl/commit/2eda98790c5c2741d76d23cc1e74b0dc4f4b391a", "cve": "CVE-2022-1343", "cwe": "CWE-119", "file": "openssl-cve-2022-1343/vuln.c", "function": "ocsp_verify_signer", "id": "openssl-cve-2022-1343:vuln", "label": "vuln", "license": "Apache-2.0", "pair": "openssl-cve-2022-1343", "project": "openssl", "relpath": "crypto/ocsp/ocsp_vfy.c", "repo": "openssl/openssl", "year": 2022} +{"class": "security fix", "commit": "2eda98790c5c2741d76d23cc1e74b0dc4f4b391a", "commit_url": "https://github.com/openssl/openssl/commit/2eda98790c5c2741d76d23cc1e74b0dc4f4b391a", "cve": "CVE-2022-1343", "cwe": "CWE-119", "file": "openssl-cve-2022-1343/fixed.c", "function": "ocsp_verify_signer", "id": "openssl-cve-2022-1343:fixed", "label": "fixed", "license": "Apache-2.0", "pair": "openssl-cve-2022-1343", "project": "openssl", "relpath": "crypto/ocsp/ocsp_vfy.c", "repo": "openssl/openssl", "year": 2022} +{"class": "security fix", "commit": "758754966791c537ea95241438454aa86f91f256", "commit_url": "https://github.com/openssl/openssl/commit/d69ae8a93bfc0f2489c008fcf303a98d77a6df4d", "cve": "CVE-2021-4044", "cwe": "CWE-119", "file": "openssl-cve-2021-4044/vuln.c", "function": "has_san_id", "id": "openssl-cve-2021-4044:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2021-4044", "project": "openssl", "relpath": "crypto/x509/x509_vfy.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "d69ae8a93bfc0f2489c008fcf303a98d77a6df4d", "commit_url": "https://github.com/openssl/openssl/commit/d69ae8a93bfc0f2489c008fcf303a98d77a6df4d", "cve": "CVE-2021-4044", "cwe": "CWE-119", "file": "openssl-cve-2021-4044/fixed.c", "function": "has_san_id", "id": "openssl-cve-2021-4044:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2021-4044", "project": "openssl", "relpath": "crypto/x509/x509_vfy.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "8e78289c4e6f4c9f2fec073b78443736e689854d", "commit_url": "https://github.com/openssl/openssl/commit/758754966791c537ea95241438454aa86f91f256", "cve": "CVE-2021-4044", "cwe": "CWE-119", "file": "openssl-cve-2021-4044-tls_post_process_server_/vuln.c", "function": "tls_post_process_server_certificate", "id": "openssl-cve-2021-4044-tls_post_process_server_:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2021-4044-tls_post_process_server_", "project": "openssl", "relpath": "ssl/statem/statem_clnt.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "758754966791c537ea95241438454aa86f91f256", "commit_url": "https://github.com/openssl/openssl/commit/758754966791c537ea95241438454aa86f91f256", "cve": "CVE-2021-4044", "cwe": "CWE-119", "file": "openssl-cve-2021-4044-tls_post_process_server_/fixed.c", "function": "tls_post_process_server_certificate", "id": "openssl-cve-2021-4044-tls_post_process_server_:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2021-4044-tls_post_process_server_", "project": "openssl", "relpath": "ssl/statem/statem_clnt.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "4b8a8bb75229b64d1c7598d845fdc3c7e7d7eee2", "commit_url": "https://github.com/openssl/openssl/commit/36cf45ef3ba71e44a8be06ee81cb31aa02cb0010", "cve": "CVE-2021-3711", "cwe": "CWE-119", "file": "openssl-cve-2021-3711-sm2_asym_decrypt/vuln.c", "function": "sm2_asym_decrypt", "id": "openssl-cve-2021-3711-sm2_asym_decrypt:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2021-3711-sm2_asym_decrypt", "project": "openssl", "relpath": "providers/implementations/asymciphers/sm2_enc.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "36cf45ef3ba71e44a8be06ee81cb31aa02cb0010", "commit_url": "https://github.com/openssl/openssl/commit/36cf45ef3ba71e44a8be06ee81cb31aa02cb0010", "cve": "CVE-2021-3711", "cwe": "CWE-119", "file": "openssl-cve-2021-3711-sm2_asym_decrypt/fixed.c", "function": "sm2_asym_decrypt", "id": "openssl-cve-2021-3711-sm2_asym_decrypt:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2021-3711-sm2_asym_decrypt", "project": "openssl", "relpath": "providers/implementations/asymciphers/sm2_enc.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "98624776c4d501c8badd6f772ab7048ac9191cb9", "commit_url": "https://github.com/openssl/openssl/commit/7c038a6bcd98d4bbfd2c2892a87a1138d2f7c5f3", "cve": "CVE-2021-3712", "cwe": "CWE-119", "file": "openssl-cve-2021-3712-netscape_spki_print/vuln.c", "function": "NETSCAPE_SPKI_print", "id": "openssl-cve-2021-3712-netscape_spki_print:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2021-3712-netscape_spki_print", "project": "openssl", "relpath": "crypto/asn1/t_spki.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "7c038a6bcd98d4bbfd2c2892a87a1138d2f7c5f3", "commit_url": "https://github.com/openssl/openssl/commit/7c038a6bcd98d4bbfd2c2892a87a1138d2f7c5f3", "cve": "CVE-2021-3712", "cwe": "CWE-119", "file": "openssl-cve-2021-3712-netscape_spki_print/fixed.c", "function": "NETSCAPE_SPKI_print", "id": "openssl-cve-2021-3712-netscape_spki_print:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2021-3712-netscape_spki_print", "project": "openssl", "relpath": "crypto/asn1/t_spki.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "1f365708a3318a5f1a395f90c38b584a58d37fb9", "commit_url": "https://github.com/openssl/openssl/commit/98624776c4d501c8badd6f772ab7048ac9191cb9", "cve": "CVE-2021-3712", "cwe": "CWE-119", "file": "openssl-cve-2021-3712-append_ia5/vuln.c", "function": "append_ia5", "id": "openssl-cve-2021-3712-append_ia5:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2021-3712-append_ia5", "project": "openssl", "relpath": "crypto/x509/v3_utl.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "98624776c4d501c8badd6f772ab7048ac9191cb9", "commit_url": "https://github.com/openssl/openssl/commit/98624776c4d501c8badd6f772ab7048ac9191cb9", "cve": "CVE-2021-3712", "cwe": "CWE-119", "file": "openssl-cve-2021-3712-append_ia5/fixed.c", "function": "append_ia5", "id": "openssl-cve-2021-3712-append_ia5:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2021-3712-append_ia5", "project": "openssl", "relpath": "crypto/x509/v3_utl.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "d2015a783e64613d8e4a142fa05048d1863df944", "commit_url": "https://github.com/openssl/openssl/commit/95f8c1e142df835d03b5b62521383a462fc5470d", "cve": "CVE-2021-3712", "cwe": "CWE-119", "file": "openssl-cve-2021-3712-ossl_cmp_hdr_push1_freet/vuln.c", "function": "ossl_cmp_hdr_push1_freeText", "id": "openssl-cve-2021-3712-ossl_cmp_hdr_push1_freet:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2021-3712-ossl_cmp_hdr_push1_freet", "project": "openssl", "relpath": "crypto/cmp/cmp_hdr.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "95f8c1e142df835d03b5b62521383a462fc5470d", "commit_url": "https://github.com/openssl/openssl/commit/95f8c1e142df835d03b5b62521383a462fc5470d", "cve": "CVE-2021-3712", "cwe": "CWE-119", "file": "openssl-cve-2021-3712-ossl_cmp_hdr_push1_freet/fixed.c", "function": "ossl_cmp_hdr_push1_freeText", "id": "openssl-cve-2021-3712-ossl_cmp_hdr_push1_freet:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2021-3712-ossl_cmp_hdr_push1_freet", "project": "openssl", "relpath": "crypto/cmp/cmp_hdr.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "918430ba80d94ec8f05383b43b1872b1ebb13e1a", "commit_url": "https://github.com/openssl/openssl/commit/d2015a783e64613d8e4a142fa05048d1863df944", "cve": "CVE-2021-3712", "cwe": "CWE-119", "file": "openssl-cve-2021-3712-ia5ncasecmp/vuln.c", "function": "ia5ncasecmp", "id": "openssl-cve-2021-3712-ia5ncasecmp:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2021-3712-ia5ncasecmp", "project": "openssl", "relpath": "crypto/x509/v3_ncons.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "d2015a783e64613d8e4a142fa05048d1863df944", "commit_url": "https://github.com/openssl/openssl/commit/d2015a783e64613d8e4a142fa05048d1863df944", "cve": "CVE-2021-3712", "cwe": "CWE-119", "file": "openssl-cve-2021-3712-ia5ncasecmp/fixed.c", "function": "ia5ncasecmp", "id": "openssl-cve-2021-3712-ia5ncasecmp:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2021-3712-ia5ncasecmp", "project": "openssl", "relpath": "crypto/x509/v3_ncons.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "b2b3b9c9936b91315adc0f3254879cb2fd5ca2bd", "commit_url": "https://github.com/openssl/openssl/commit/918430ba80d94ec8f05383b43b1872b1ebb13e1a", "cve": "CVE-2021-3712", "cwe": "CWE-119", "file": "openssl-cve-2021-3712-i2r_pci/vuln.c", "function": "i2r_pci", "id": "openssl-cve-2021-3712-i2r_pci:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2021-3712-i2r_pci", "project": "openssl", "relpath": "crypto/x509/v3_pci.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "918430ba80d94ec8f05383b43b1872b1ebb13e1a", "commit_url": "https://github.com/openssl/openssl/commit/918430ba80d94ec8f05383b43b1872b1ebb13e1a", "cve": "CVE-2021-3712", "cwe": "CWE-119", "file": "openssl-cve-2021-3712-i2r_pci/fixed.c", "function": "i2r_pci", "id": "openssl-cve-2021-3712-i2r_pci:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2021-3712-i2r_pci", "project": "openssl", "relpath": "crypto/x509/v3_pci.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "1747d4658b3830951068a6a6c1fa2b45c4731fb3", "commit_url": "https://github.com/openssl/openssl/commit/b2b3b9c9936b91315adc0f3254879cb2fd5ca2bd", "cve": "CVE-2021-3712", "cwe": "CWE-119", "file": "openssl-cve-2021-3712-general_name_print/vuln.c", "function": "GENERAL_NAME_print", "id": "openssl-cve-2021-3712-general_name_print:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2021-3712-general_name_print", "project": "openssl", "relpath": "crypto/x509/v3_san.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "b2b3b9c9936b91315adc0f3254879cb2fd5ca2bd", "commit_url": "https://github.com/openssl/openssl/commit/b2b3b9c9936b91315adc0f3254879cb2fd5ca2bd", "cve": "CVE-2021-3712", "cwe": "CWE-119", "file": "openssl-cve-2021-3712-general_name_print/fixed.c", "function": "GENERAL_NAME_print", "id": "openssl-cve-2021-3712-general_name_print:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2021-3712-general_name_print", "project": "openssl", "relpath": "crypto/x509/v3_san.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "ad6ac17489241574136b7d035f01f6175dd9c941", "commit_url": "https://github.com/openssl/openssl/commit/1747d4658b3830951068a6a6c1fa2b45c4731fb3", "cve": "CVE-2021-3712", "cwe": "CWE-119", "file": "openssl-cve-2021-3712-print_qualifiers/vuln.c", "function": "print_qualifiers", "id": "openssl-cve-2021-3712-print_qualifiers:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2021-3712-print_qualifiers", "project": "openssl", "relpath": "crypto/x509/v3_cpols.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "1747d4658b3830951068a6a6c1fa2b45c4731fb3", "commit_url": "https://github.com/openssl/openssl/commit/1747d4658b3830951068a6a6c1fa2b45c4731fb3", "cve": "CVE-2021-3712", "cwe": "CWE-119", "file": "openssl-cve-2021-3712-print_qualifiers/fixed.c", "function": "print_qualifiers", "id": "openssl-cve-2021-3712-print_qualifiers:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2021-3712-print_qualifiers", "project": "openssl", "relpath": "crypto/x509/v3_cpols.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "8c74c9d1ade0fbdab5b815ddb747351b8b839641", "commit_url": "https://github.com/openssl/openssl/commit/59f5e75f3bced8fc0e130d72a3f582cf7b480b46", "cve": "CVE-2021-3711", "cwe": "CWE-119", "file": "openssl-cve-2021-3711-pkey_sm2_decrypt/vuln.c", "function": "pkey_sm2_decrypt", "id": "openssl-cve-2021-3711-pkey_sm2_decrypt:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2021-3711-pkey_sm2_decrypt", "project": "openssl", "relpath": "crypto/sm2/sm2_pmeth.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "59f5e75f3bced8fc0e130d72a3f582cf7b480b46", "commit_url": "https://github.com/openssl/openssl/commit/59f5e75f3bced8fc0e130d72a3f582cf7b480b46", "cve": "CVE-2021-3711", "cwe": "CWE-119", "file": "openssl-cve-2021-3711-pkey_sm2_decrypt/fixed.c", "function": "pkey_sm2_decrypt", "id": "openssl-cve-2021-3711-pkey_sm2_decrypt:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2021-3711-pkey_sm2_decrypt", "project": "openssl", "relpath": "crypto/sm2/sm2_pmeth.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "02b1636fe3db274497304a3e95a4e32ced7e841b", "commit_url": "https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a", "cve": "CVE-2021-3449", "cwe": "CWE-119", "file": "openssl-cve-2021-3449-ssl_generate_master_secr/vuln.c", "function": "ssl_generate_master_secret", "id": "openssl-cve-2021-3449-ssl_generate_master_secr:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2021-3449-ssl_generate_master_secr", "project": "openssl", "relpath": "ssl/s3_lib.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "39a140597d874e554b736885ac4dea16ac40a87a", "commit_url": "https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a", "cve": "CVE-2021-3449", "cwe": "CWE-119", "file": "openssl-cve-2021-3449-ssl_generate_master_secr/fixed.c", "function": "ssl_generate_master_secret", "id": "openssl-cve-2021-3449-ssl_generate_master_secr:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2021-3449-ssl_generate_master_secr", "project": "openssl", "relpath": "ssl/s3_lib.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "02b1636fe3db274497304a3e95a4e32ced7e841b", "commit_url": "https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a", "cve": "CVE-2021-3449", "cwe": "CWE-119", "file": "openssl-cve-2021-3449-ssl_ctx_set_alpn_protos/vuln.c", "function": "SSL_CTX_set_alpn_protos", "id": "openssl-cve-2021-3449-ssl_ctx_set_alpn_protos:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2021-3449-ssl_ctx_set_alpn_protos", "project": "openssl", "relpath": "ssl/ssl_lib.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "39a140597d874e554b736885ac4dea16ac40a87a", "commit_url": "https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a", "cve": "CVE-2021-3449", "cwe": "CWE-119", "file": "openssl-cve-2021-3449-ssl_ctx_set_alpn_protos/fixed.c", "function": "SSL_CTX_set_alpn_protos", "id": "openssl-cve-2021-3449-ssl_ctx_set_alpn_protos:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2021-3449-ssl_ctx_set_alpn_protos", "project": "openssl", "relpath": "ssl/ssl_lib.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "02b1636fe3db274497304a3e95a4e32ced7e841b", "commit_url": "https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a", "cve": "CVE-2021-3449", "cwe": "CWE-119", "file": "openssl-cve-2021-3449-init_sig_algs_cert/vuln.c", "function": "init_sig_algs_cert", "id": "openssl-cve-2021-3449-init_sig_algs_cert:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2021-3449-init_sig_algs_cert", "project": "openssl", "relpath": "ssl/statem/extensions.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "39a140597d874e554b736885ac4dea16ac40a87a", "commit_url": "https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a", "cve": "CVE-2021-3449", "cwe": "CWE-119", "file": "openssl-cve-2021-3449-init_sig_algs_cert/fixed.c", "function": "init_sig_algs_cert", "id": "openssl-cve-2021-3449-init_sig_algs_cert:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2021-3449-init_sig_algs_cert", "project": "openssl", "relpath": "ssl/statem/extensions.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "02b1636fe3db274497304a3e95a4e32ced7e841b", "commit_url": "https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a", "cve": "CVE-2021-3449", "cwe": "CWE-119", "file": "openssl-cve-2021-3449-tls_construct_ctos_early/vuln.c", "function": "tls_construct_ctos_early_data", "id": "openssl-cve-2021-3449-tls_construct_ctos_early:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2021-3449-tls_construct_ctos_early", "project": "openssl", "relpath": "ssl/statem/extensions_clnt.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "39a140597d874e554b736885ac4dea16ac40a87a", "commit_url": "https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a", "cve": "CVE-2021-3449", "cwe": "CWE-119", "file": "openssl-cve-2021-3449-tls_construct_ctos_early/fixed.c", "function": "tls_construct_ctos_early_data", "id": "openssl-cve-2021-3449-tls_construct_ctos_early:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2021-3449-tls_construct_ctos_early", "project": "openssl", "relpath": "ssl/statem/extensions_clnt.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "02b1636fe3db274497304a3e95a4e32ced7e841b", "commit_url": "https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a", "cve": "CVE-2021-3449", "cwe": "CWE-119", "file": "openssl-cve-2021-3449-tls_process_certificate_/vuln.c", "function": "tls_process_certificate_request", "id": "openssl-cve-2021-3449-tls_process_certificate_:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2021-3449-tls_process_certificate_", "project": "openssl", "relpath": "ssl/statem/statem_clnt.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "39a140597d874e554b736885ac4dea16ac40a87a", "commit_url": "https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a", "cve": "CVE-2021-3449", "cwe": "CWE-119", "file": "openssl-cve-2021-3449-tls_process_certificate_/fixed.c", "function": "tls_process_certificate_request", "id": "openssl-cve-2021-3449-tls_process_certificate_:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2021-3449-tls_process_certificate_", "project": "openssl", "relpath": "ssl/statem/statem_clnt.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "02b1636fe3db274497304a3e95a4e32ced7e841b", "commit_url": "https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a", "cve": "CVE-2021-3449", "cwe": "CWE-119", "file": "openssl-cve-2021-3449-tls_handle_alpn/vuln.c", "function": "tls_handle_alpn", "id": "openssl-cve-2021-3449-tls_handle_alpn:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2021-3449-tls_handle_alpn", "project": "openssl", "relpath": "ssl/statem/statem_srvr.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "39a140597d874e554b736885ac4dea16ac40a87a", "commit_url": "https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a", "cve": "CVE-2021-3449", "cwe": "CWE-119", "file": "openssl-cve-2021-3449-tls_handle_alpn/fixed.c", "function": "tls_handle_alpn", "id": "openssl-cve-2021-3449-tls_handle_alpn:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2021-3449-tls_handle_alpn", "project": "openssl", "relpath": "ssl/statem/statem_srvr.c", "repo": "openssl/openssl", "year": 2021} +{"class": "null pointer dereference", "commit": "112580c27b829b0ac0874d5c5787195f27c7952c", "commit_url": "https://github.com/openssl/openssl/commit/02b1636fe3db274497304a3e95a4e32ced7e841b", "cve": "CVE-2021-3449", "cwe": "CWE-476", "file": "openssl-cve-2021-3449-init_sig_algs/vuln.c", "function": "init_sig_algs", "id": "openssl-cve-2021-3449-init_sig_algs:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2021-3449-init_sig_algs", "project": "openssl", "relpath": "ssl/statem/extensions.c", "repo": "openssl/openssl", "year": 2021} +{"class": "null pointer dereference", "commit": "02b1636fe3db274497304a3e95a4e32ced7e841b", "commit_url": "https://github.com/openssl/openssl/commit/02b1636fe3db274497304a3e95a4e32ced7e841b", "cve": "CVE-2021-3449", "cwe": "CWE-476", "file": "openssl-cve-2021-3449-init_sig_algs/fixed.c", "function": "init_sig_algs", "id": "openssl-cve-2021-3449-init_sig_algs:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2021-3449-init_sig_algs", "project": "openssl", "relpath": "ssl/statem/extensions.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "cfd74383d9b06f85cb1e166180346115a3f9a452", "commit_url": "https://github.com/openssl/openssl/commit/2a40b7bc7b94dd7de897a74571e7024f0cf0d63b", "cve": "CVE-2021-3450", "cwe": "CWE-119", "file": "openssl-cve-2021-3450/vuln.c", "function": "check_chain_extensions", "id": "openssl-cve-2021-3450:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2021-3450", "project": "openssl", "relpath": "crypto/x509/x509_vfy.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "2a40b7bc7b94dd7de897a74571e7024f0cf0d63b", "commit_url": "https://github.com/openssl/openssl/commit/2a40b7bc7b94dd7de897a74571e7024f0cf0d63b", "cve": "CVE-2021-3450", "cwe": "CWE-119", "file": "openssl-cve-2021-3450/fixed.c", "function": "check_chain_extensions", "id": "openssl-cve-2021-3450:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2021-3450", "project": "openssl", "relpath": "crypto/x509/x509_vfy.c", "repo": "openssl/openssl", "year": 2021} +{"class": "buffer overflow", "commit": "481a88f13c44996a008195791ea0dc076b968774", "commit_url": "https://github.com/openssl/openssl/commit/6a51b9e1d0cf0bf8515f7201b68fb0a3482b3dc1", "cve": "CVE-2021-23840", "cwe": "CWE-119", "file": "openssl-cve-2021-23840-evp_encryptdecryptupdate/vuln.c", "function": "evp_EncryptDecryptUpdate", "id": "openssl-cve-2021-23840-evp_encryptdecryptupdate:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2021-23840-evp_encryptdecryptupdate", "project": "openssl", "relpath": "crypto/evp/evp_enc.c", "repo": "openssl/openssl", "year": 2021} +{"class": "buffer overflow", "commit": "6a51b9e1d0cf0bf8515f7201b68fb0a3482b3dc1", "commit_url": "https://github.com/openssl/openssl/commit/6a51b9e1d0cf0bf8515f7201b68fb0a3482b3dc1", "cve": "CVE-2021-23840", "cwe": "CWE-119", "file": "openssl-cve-2021-23840-evp_encryptdecryptupdate/fixed.c", "function": "evp_EncryptDecryptUpdate", "id": "openssl-cve-2021-23840-evp_encryptdecryptupdate:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2021-23840-evp_encryptdecryptupdate", "project": "openssl", "relpath": "crypto/evp/evp_enc.c", "repo": "openssl/openssl", "year": 2021} +{"class": "null pointer dereference", "commit": "c8c6e7438c03b2fc24e7ead460feeaef04911fb4", "commit_url": "https://github.com/openssl/openssl/commit/122a19ab48091c657f7cb1fb3af9fc07bd557bbf", "cve": "CVE-2021-23841", "cwe": "CWE-476", "file": "openssl-cve-2021-23841/vuln.c", "function": "X509_issuer_and_serial_hash", "id": "openssl-cve-2021-23841:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2021-23841", "project": "openssl", "relpath": "crypto/x509/x509_cmp.c", "repo": "openssl/openssl", "year": 2021} +{"class": "null pointer dereference", "commit": "122a19ab48091c657f7cb1fb3af9fc07bd557bbf", "commit_url": "https://github.com/openssl/openssl/commit/122a19ab48091c657f7cb1fb3af9fc07bd557bbf", "cve": "CVE-2021-23841", "cwe": "CWE-476", "file": "openssl-cve-2021-23841/fixed.c", "function": "X509_issuer_and_serial_hash", "id": "openssl-cve-2021-23841:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2021-23841", "project": "openssl", "relpath": "crypto/x509/x509_cmp.c", "repo": "openssl/openssl", "year": 2021} +{"class": "security fix", "commit": "aa0ad2011d3e7ad8a611da274ef7d9c7706e289b", "commit_url": "https://github.com/openssl/openssl/commit/f960d81215ebf3f65e03d4d5d857fb9b666d6920", "cve": "CVE-2020-1971", "cwe": "CWE-119", "file": "openssl-cve-2020-1971-general_name_cmp/vuln.c", "function": "GENERAL_NAME_cmp", "id": "openssl-cve-2020-1971-general_name_cmp:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2020-1971-general_name_cmp", "project": "openssl", "relpath": "crypto/x509v3/v3_genn.c", "repo": "openssl/openssl", "year": 2020} +{"class": "security fix", "commit": "f960d81215ebf3f65e03d4d5d857fb9b666d6920", "commit_url": "https://github.com/openssl/openssl/commit/f960d81215ebf3f65e03d4d5d857fb9b666d6920", "cve": "CVE-2020-1971", "cwe": "CWE-119", "file": "openssl-cve-2020-1971-general_name_cmp/fixed.c", "function": "GENERAL_NAME_cmp", "id": "openssl-cve-2020-1971-general_name_cmp:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2020-1971-general_name_cmp", "project": "openssl", "relpath": "crypto/x509v3/v3_genn.c", "repo": "openssl/openssl", "year": 2020} +{"class": "null pointer dereference", "commit": "3656c08ab4b1b892730cb5e808b6f4298b08a2e6", "commit_url": "https://github.com/openssl/openssl/commit/a87f3fe01a5a894aa27ccd6a239155fd129988e4", "cve": "CVE-2020-1967", "cwe": "CWE-476", "file": "openssl-cve-2020-1967-tls1_check_sig_alg/vuln.c", "function": "tls1_check_sig_alg", "id": "openssl-cve-2020-1967-tls1_check_sig_alg:vuln", "label": "vuln", "license": "OpenSSL License", "pair": "openssl-cve-2020-1967-tls1_check_sig_alg", "project": "openssl", "relpath": "ssl/t1_lib.c", "repo": "openssl/openssl", "year": 2020} +{"class": "null pointer dereference", "commit": "a87f3fe01a5a894aa27ccd6a239155fd129988e4", "commit_url": "https://github.com/openssl/openssl/commit/a87f3fe01a5a894aa27ccd6a239155fd129988e4", "cve": "CVE-2020-1967", "cwe": "CWE-476", "file": "openssl-cve-2020-1967-tls1_check_sig_alg/fixed.c", "function": "tls1_check_sig_alg", "id": "openssl-cve-2020-1967-tls1_check_sig_alg:fixed", "label": "fixed", "license": "OpenSSL License", "pair": "openssl-cve-2020-1967-tls1_check_sig_alg", "project": "openssl", "relpath": "ssl/t1_lib.c", "repo": "openssl/openssl", "year": 2020} +{"class": "security fix", "commit": "f746780a1e548b4b93790b58d70c3b22fde5360d", "commit_url": "https://github.com/curl/curl/commit/e9a2b0dc72dd3a9aa3a5210e89079a3b719475dc", "cve": "CVE-2026-9080", "cwe": "CWE-119", "file": "curl-cve-2026-9080/vuln.c", "function": "mev_forget_socket", "id": "curl-cve-2026-9080:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2026-9080", "project": "curl", "relpath": "lib/multi_ev.c", "repo": "curl/curl", "year": 2026} +{"class": "security fix", "commit": "e9a2b0dc72dd3a9aa3a5210e89079a3b719475dc", "commit_url": "https://github.com/curl/curl/commit/e9a2b0dc72dd3a9aa3a5210e89079a3b719475dc", "cve": "CVE-2026-9080", "cwe": "CWE-119", "file": "curl-cve-2026-9080/fixed.c", "function": "mev_forget_socket", "id": "curl-cve-2026-9080:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2026-9080", "project": "curl", "relpath": "lib/multi_ev.c", "repo": "curl/curl", "year": 2026} +{"class": "security fix", "commit": "09e25b9d94f4106eac8ca3a43b221bdc66f405e4", "commit_url": "https://github.com/curl/curl/commit/fb4415d8aee6c1045be932a34fe6107c2f5ed147", "cve": "CVE-2023-38545", "cwe": "CWE-119", "file": "curl-cve-2023-38545-do_socks5/vuln.c", "function": "do_SOCKS5", "id": "curl-cve-2023-38545-do_socks5:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2023-38545-do_socks5", "project": "curl", "relpath": "lib/socks.c", "repo": "curl/curl", "year": 2023} +{"class": "security fix", "commit": "fb4415d8aee6c1045be932a34fe6107c2f5ed147", "commit_url": "https://github.com/curl/curl/commit/fb4415d8aee6c1045be932a34fe6107c2f5ed147", "cve": "CVE-2023-38545", "cwe": "CWE-119", "file": "curl-cve-2023-38545-do_socks5/fixed.c", "function": "do_SOCKS5", "id": "curl-cve-2023-38545-do_socks5:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2023-38545-do_socks5", "project": "curl", "relpath": "lib/socks.c", "repo": "curl/curl", "year": 2023} +{"class": "security fix", "commit": "46f8911d3942dc06fdd67e9f6f3908982e5d2fb4", "commit_url": "https://github.com/curl/curl/commit/20f9dd6bae50b7223171b17ba7798946e74f877f", "cve": "CVE-2022-32207", "cwe": "CWE-119", "file": "curl-cve-2022-32207/vuln.c", "function": "cookie_output", "id": "curl-cve-2022-32207:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2022-32207", "project": "curl", "relpath": "lib/cookie.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "20f9dd6bae50b7223171b17ba7798946e74f877f", "commit_url": "https://github.com/curl/curl/commit/20f9dd6bae50b7223171b17ba7798946e74f877f", "cve": "CVE-2022-32207", "cwe": "CWE-119", "file": "curl-cve-2022-32207/fixed.c", "function": "cookie_output", "id": "curl-cve-2022-32207:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2022-32207", "project": "curl", "relpath": "lib/cookie.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "6ecdf5136b52af747e7bda08db9a748256b1cd09", "commit_url": "https://github.com/curl/curl/commit/3a09fbb7f264c67c438d01a30669ce325aa508e2", "cve": "CVE-2022-32206", "cwe": "CWE-119", "file": "curl-cve-2022-32206/vuln.c", "function": "Curl_build_unencoding_stack", "id": "curl-cve-2022-32206:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2022-32206", "project": "curl", "relpath": "lib/content_encoding.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "3a09fbb7f264c67c438d01a30669ce325aa508e2", "commit_url": "https://github.com/curl/curl/commit/3a09fbb7f264c67c438d01a30669ce325aa508e2", "cve": "CVE-2022-32206", "cwe": "CWE-119", "file": "curl-cve-2022-32206/fixed.c", "function": "Curl_build_unencoding_stack", "id": "curl-cve-2022-32206:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2022-32206", "project": "curl", "relpath": "lib/content_encoding.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "2b67a0a1129b20a56ed04859fec8999f5c0c4280", "commit_url": "https://github.com/curl/curl/commit/6ecdf5136b52af747e7bda08db9a748256b1cd09", "cve": "CVE-2022-32208", "cwe": "CWE-119", "file": "curl-cve-2022-32208/vuln.c", "function": "read_data", "id": "curl-cve-2022-32208:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2022-32208", "project": "curl", "relpath": "lib/krb5.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "6ecdf5136b52af747e7bda08db9a748256b1cd09", "commit_url": "https://github.com/curl/curl/commit/6ecdf5136b52af747e7bda08db9a748256b1cd09", "cve": "CVE-2022-32208", "cwe": "CWE-119", "file": "curl-cve-2022-32208/fixed.c", "function": "read_data", "id": "curl-cve-2022-32208:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2022-32208", "project": "curl", "relpath": "lib/krb5.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "7e92d12b4e6911f424678a133b19de670e183a59", "commit_url": "https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c", "cve": "CVE-2022-27782", "cwe": "CWE-119", "file": "curl-cve-2022-27782-curl_init_userdefined/vuln.c", "function": "Curl_init_userdefined", "id": "curl-cve-2022-27782-curl_init_userdefined:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2022-27782-curl_init_userdefined", "project": "curl", "relpath": "lib/url.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "f18af4f874cecab82a9797e8c7541e0990c7a64c", "commit_url": "https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c", "cve": "CVE-2022-27782", "cwe": "CWE-119", "file": "curl-cve-2022-27782-curl_init_userdefined/fixed.c", "function": "Curl_init_userdefined", "id": "curl-cve-2022-27782-curl_init_userdefined:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2022-27782-curl_init_userdefined", "project": "curl", "relpath": "lib/url.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "7e92d12b4e6911f424678a133b19de670e183a59", "commit_url": "https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c", "cve": "CVE-2022-27782", "cwe": "CWE-119", "file": "curl-cve-2022-27782-gtls_shutdown/vuln.c", "function": "gtls_shutdown", "id": "curl-cve-2022-27782-gtls_shutdown:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2022-27782-gtls_shutdown", "project": "curl", "relpath": "lib/vtls/gtls.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "f18af4f874cecab82a9797e8c7541e0990c7a64c", "commit_url": "https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c", "cve": "CVE-2022-27782", "cwe": "CWE-119", "file": "curl-cve-2022-27782-gtls_shutdown/fixed.c", "function": "gtls_shutdown", "id": "curl-cve-2022-27782-gtls_shutdown:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2022-27782-gtls_shutdown", "project": "curl", "relpath": "lib/vtls/gtls.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "7e92d12b4e6911f424678a133b19de670e183a59", "commit_url": "https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c", "cve": "CVE-2022-27782", "cwe": "CWE-119", "file": "curl-cve-2022-27782-nss_setup_connect/vuln.c", "function": "nss_setup_connect", "id": "curl-cve-2022-27782-nss_setup_connect:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2022-27782-nss_setup_connect", "project": "curl", "relpath": "lib/vtls/nss.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "f18af4f874cecab82a9797e8c7541e0990c7a64c", "commit_url": "https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c", "cve": "CVE-2022-27782", "cwe": "CWE-119", "file": "curl-cve-2022-27782-nss_setup_connect/fixed.c", "function": "nss_setup_connect", "id": "curl-cve-2022-27782-nss_setup_connect:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2022-27782-nss_setup_connect", "project": "curl", "relpath": "lib/vtls/nss.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "7e92d12b4e6911f424678a133b19de670e183a59", "commit_url": "https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c", "cve": "CVE-2022-27782", "cwe": "CWE-119", "file": "curl-cve-2022-27782-ossl_connect_step1/vuln.c", "function": "ossl_connect_step1", "id": "curl-cve-2022-27782-ossl_connect_step1:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2022-27782-ossl_connect_step1", "project": "curl", "relpath": "lib/vtls/openssl.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "f18af4f874cecab82a9797e8c7541e0990c7a64c", "commit_url": "https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c", "cve": "CVE-2022-27782", "cwe": "CWE-119", "file": "curl-cve-2022-27782-ossl_connect_step1/fixed.c", "function": "ossl_connect_step1", "id": "curl-cve-2022-27782-ossl_connect_step1:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2022-27782-ossl_connect_step1", "project": "curl", "relpath": "lib/vtls/openssl.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "7e92d12b4e6911f424678a133b19de670e183a59", "commit_url": "https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c", "cve": "CVE-2022-27782", "cwe": "CWE-119", "file": "curl-cve-2022-27782-curl_free_primary_ssl_co/vuln.c", "function": "Curl_free_primary_ssl_config", "id": "curl-cve-2022-27782-curl_free_primary_ssl_co:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2022-27782-curl_free_primary_ssl_co", "project": "curl", "relpath": "lib/vtls/vtls.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "f18af4f874cecab82a9797e8c7541e0990c7a64c", "commit_url": "https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c", "cve": "CVE-2022-27782", "cwe": "CWE-119", "file": "curl-cve-2022-27782-curl_free_primary_ssl_co/fixed.c", "function": "Curl_free_primary_ssl_config", "id": "curl-cve-2022-27782-curl_free_primary_ssl_co:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2022-27782-curl_free_primary_ssl_co", "project": "curl", "relpath": "lib/vtls/vtls.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "fae6fea209a2d4db1582f608bd8cc8000721733a", "commit_url": "https://github.com/curl/curl/commit/8c7ee9083d0d719d0a77ab20d9cc2ae84eeea7f3", "cve": "CVE-2022-27778", "cwe": "CWE-119", "file": "curl-cve-2022-27778/vuln.c", "function": "post_per_transfer", "id": "curl-cve-2022-27778:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2022-27778", "project": "curl", "relpath": "src/tool_operate.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "8c7ee9083d0d719d0a77ab20d9cc2ae84eeea7f3", "commit_url": "https://github.com/curl/curl/commit/8c7ee9083d0d719d0a77ab20d9cc2ae84eeea7f3", "cve": "CVE-2022-27778", "cwe": "CWE-119", "file": "curl-cve-2022-27778/fixed.c", "function": "post_per_transfer", "id": "curl-cve-2022-27778:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2022-27778", "project": "curl", "relpath": "src/tool_operate.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "ff3ee510c328db03bf171cae6179bb9463fb054f", "commit_url": "https://github.com/curl/curl/commit/fae6fea209a2d4db1582f608bd8cc8000721733a", "cve": "CVE-2022-30115", "cwe": "CWE-119", "file": "curl-cve-2022-30115/vuln.c", "function": "hsts_create", "id": "curl-cve-2022-30115:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2022-30115", "project": "curl", "relpath": "lib/hsts.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "fae6fea209a2d4db1582f608bd8cc8000721733a", "commit_url": "https://github.com/curl/curl/commit/fae6fea209a2d4db1582f608bd8cc8000721733a", "cve": "CVE-2022-30115", "cwe": "CWE-119", "file": "curl-cve-2022-30115/fixed.c", "function": "hsts_create", "id": "curl-cve-2022-30115:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2022-30115", "project": "curl", "relpath": "lib/hsts.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "5c7da89d404bf59c8dd82a001119a16d18365917", "commit_url": "https://github.com/curl/curl/commit/914aaab9153764ef8fa4178215b8ad89d3ac263a", "cve": "CVE-2022-27780", "cwe": "CWE-119", "file": "curl-cve-2022-27780/vuln.c", "function": "hostname_check", "id": "curl-cve-2022-27780:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2022-27780", "project": "curl", "relpath": "lib/urlapi.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "914aaab9153764ef8fa4178215b8ad89d3ac263a", "commit_url": "https://github.com/curl/curl/commit/914aaab9153764ef8fa4178215b8ad89d3ac263a", "cve": "CVE-2022-27780", "cwe": "CWE-119", "file": "curl-cve-2022-27780/fixed.c", "function": "hostname_check", "id": "curl-cve-2022-27780:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2022-27780", "project": "curl", "relpath": "lib/urlapi.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "08b8ef4e726ba10f45081ecda5b3cea788d3c839", "commit_url": "https://github.com/curl/curl/commit/620ea21410030a9977396b4661806bc187231b79", "cve": "CVE-2022-27774", "cwe": "CWE-119", "file": "curl-cve-2022-27774/vuln.c", "function": "Curl_follow", "id": "curl-cve-2022-27774:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2022-27774", "project": "curl", "relpath": "lib/transfer.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "620ea21410030a9977396b4661806bc187231b79", "commit_url": "https://github.com/curl/curl/commit/620ea21410030a9977396b4661806bc187231b79", "cve": "CVE-2022-27774", "cwe": "CWE-119", "file": "curl-cve-2022-27774/fixed.c", "function": "Curl_follow", "id": "curl-cve-2022-27774:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2022-27774", "project": "curl", "relpath": "lib/transfer.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "8f2079154f80561ccffcaa954268798b658e66b6", "commit_url": "https://github.com/curl/curl/commit/6e659993952aa5f90f48864be84a1bbb047fc258", "cve": "CVE-2022-27776", "cwe": "CWE-119", "file": "curl-cve-2022-27776/vuln.c", "function": "Curl_add_custom_headers", "id": "curl-cve-2022-27776:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2022-27776", "project": "curl", "relpath": "lib/http.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "6e659993952aa5f90f48864be84a1bbb047fc258", "commit_url": "https://github.com/curl/curl/commit/6e659993952aa5f90f48864be84a1bbb047fc258", "cve": "CVE-2022-27776", "cwe": "CWE-119", "file": "curl-cve-2022-27776/fixed.c", "function": "Curl_add_custom_headers", "id": "curl-cve-2022-27776:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2022-27776", "project": "curl", "relpath": "lib/http.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "852aa5ad351ea53e5f01d2f44b5b4370c2bf5425", "commit_url": "https://github.com/curl/curl/commit/058f98dc3fe595f21dc26a5b9b1699e519ba5705", "cve": "CVE-2022-27775", "cwe": "CWE-119", "file": "curl-cve-2022-27775/vuln.c", "function": "hashkey", "id": "curl-cve-2022-27775:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2022-27775", "project": "curl", "relpath": "lib/conncache.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "058f98dc3fe595f21dc26a5b9b1699e519ba5705", "commit_url": "https://github.com/curl/curl/commit/058f98dc3fe595f21dc26a5b9b1699e519ba5705", "cve": "CVE-2022-27775", "cwe": "CWE-119", "file": "curl-cve-2022-27775/fixed.c", "function": "hashkey", "id": "curl-cve-2022-27775:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2022-27775", "project": "curl", "relpath": "lib/conncache.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "ff2f3e836702daa82e2356195482fcc95f4257dc", "commit_url": "https://github.com/curl/curl/commit/852aa5ad351ea53e5f01d2f44b5b4370c2bf5425", "cve": "CVE-2022-22576", "cwe": "CWE-119", "file": "curl-cve-2022-22576-conn_free/vuln.c", "function": "conn_free", "id": "curl-cve-2022-22576-conn_free:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2022-22576-conn_free", "project": "curl", "relpath": "lib/url.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "852aa5ad351ea53e5f01d2f44b5b4370c2bf5425", "commit_url": "https://github.com/curl/curl/commit/852aa5ad351ea53e5f01d2f44b5b4370c2bf5425", "cve": "CVE-2022-22576", "cwe": "CWE-119", "file": "curl-cve-2022-22576-conn_free/fixed.c", "function": "conn_free", "id": "curl-cve-2022-22576-conn_free:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2022-22576-conn_free", "project": "curl", "relpath": "lib/url.c", "repo": "curl/curl", "year": 2022} +{"class": "security fix", "commit": "364f174724ef115c63d5e5dc1d3342c8a43b1cca", "commit_url": "https://github.com/curl/curl/commit/8ef147c43646e91fdaad5d0e7b60351f842e5c68", "cve": "CVE-2021-22947", "cwe": "CWE-119", "file": "curl-cve-2021-22947/vuln.c", "function": "ftp_statemachine", "id": "curl-cve-2021-22947:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2021-22947", "project": "curl", "relpath": "lib/ftp.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "8ef147c43646e91fdaad5d0e7b60351f842e5c68", "commit_url": "https://github.com/curl/curl/commit/8ef147c43646e91fdaad5d0e7b60351f842e5c68", "cve": "CVE-2021-22947", "cwe": "CWE-119", "file": "curl-cve-2021-22947/fixed.c", "function": "ftp_statemachine", "id": "curl-cve-2021-22947:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2021-22947", "project": "curl", "relpath": "lib/ftp.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "364f174724ef115c63d5e5dc1d3342c8a43b1cca", "commit_url": "https://github.com/curl/curl/commit/8ef147c43646e91fdaad5d0e7b60351f842e5c68", "cve": "CVE-2021-22947", "cwe": "CWE-119", "file": "curl-cve-2021-22947-imap_state_starttls_resp/vuln.c", "function": "imap_state_starttls_resp", "id": "curl-cve-2021-22947-imap_state_starttls_resp:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2021-22947-imap_state_starttls_resp", "project": "curl", "relpath": "lib/imap.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "8ef147c43646e91fdaad5d0e7b60351f842e5c68", "commit_url": "https://github.com/curl/curl/commit/8ef147c43646e91fdaad5d0e7b60351f842e5c68", "cve": "CVE-2021-22947", "cwe": "CWE-119", "file": "curl-cve-2021-22947-imap_state_starttls_resp/fixed.c", "function": "imap_state_starttls_resp", "id": "curl-cve-2021-22947-imap_state_starttls_resp:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2021-22947-imap_state_starttls_resp", "project": "curl", "relpath": "lib/imap.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "364f174724ef115c63d5e5dc1d3342c8a43b1cca", "commit_url": "https://github.com/curl/curl/commit/8ef147c43646e91fdaad5d0e7b60351f842e5c68", "cve": "CVE-2021-22947", "cwe": "CWE-119", "file": "curl-cve-2021-22947-pop3_state_starttls_resp/vuln.c", "function": "pop3_state_starttls_resp", "id": "curl-cve-2021-22947-pop3_state_starttls_resp:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2021-22947-pop3_state_starttls_resp", "project": "curl", "relpath": "lib/pop3.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "8ef147c43646e91fdaad5d0e7b60351f842e5c68", "commit_url": "https://github.com/curl/curl/commit/8ef147c43646e91fdaad5d0e7b60351f842e5c68", "cve": "CVE-2021-22947", "cwe": "CWE-119", "file": "curl-cve-2021-22947-pop3_state_starttls_resp/fixed.c", "function": "pop3_state_starttls_resp", "id": "curl-cve-2021-22947-pop3_state_starttls_resp:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2021-22947-pop3_state_starttls_resp", "project": "curl", "relpath": "lib/pop3.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "364f174724ef115c63d5e5dc1d3342c8a43b1cca", "commit_url": "https://github.com/curl/curl/commit/8ef147c43646e91fdaad5d0e7b60351f842e5c68", "cve": "CVE-2021-22947", "cwe": "CWE-119", "file": "curl-cve-2021-22947-smtp_state_starttls_resp/vuln.c", "function": "smtp_state_starttls_resp", "id": "curl-cve-2021-22947-smtp_state_starttls_resp:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2021-22947-smtp_state_starttls_resp", "project": "curl", "relpath": "lib/smtp.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "8ef147c43646e91fdaad5d0e7b60351f842e5c68", "commit_url": "https://github.com/curl/curl/commit/8ef147c43646e91fdaad5d0e7b60351f842e5c68", "cve": "CVE-2021-22947", "cwe": "CWE-119", "file": "curl-cve-2021-22947-smtp_state_starttls_resp/fixed.c", "function": "smtp_state_starttls_resp", "id": "curl-cve-2021-22947-smtp_state_starttls_resp:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2021-22947-smtp_state_starttls_resp", "project": "curl", "relpath": "lib/smtp.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "43157490a5054bd24256fe12876931e8abc9df49", "commit_url": "https://github.com/curl/curl/commit/364f174724ef115c63d5e5dc1d3342c8a43b1cca", "cve": "CVE-2021-22946", "cwe": "CWE-119", "file": "curl-cve-2021-22946/vuln.c", "function": "ftp_statemachine", "id": "curl-cve-2021-22946:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2021-22946", "project": "curl", "relpath": "lib/ftp.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "364f174724ef115c63d5e5dc1d3342c8a43b1cca", "commit_url": "https://github.com/curl/curl/commit/364f174724ef115c63d5e5dc1d3342c8a43b1cca", "cve": "CVE-2021-22946", "cwe": "CWE-119", "file": "curl-cve-2021-22946/fixed.c", "function": "ftp_statemachine", "id": "curl-cve-2021-22946:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2021-22946", "project": "curl", "relpath": "lib/ftp.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "43157490a5054bd24256fe12876931e8abc9df49", "commit_url": "https://github.com/curl/curl/commit/364f174724ef115c63d5e5dc1d3342c8a43b1cca", "cve": "CVE-2021-22946", "cwe": "CWE-119", "file": "curl-cve-2021-22946-imap_state_capability_re/vuln.c", "function": "imap_state_capability_resp", "id": "curl-cve-2021-22946-imap_state_capability_re:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2021-22946-imap_state_capability_re", "project": "curl", "relpath": "lib/imap.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "364f174724ef115c63d5e5dc1d3342c8a43b1cca", "commit_url": "https://github.com/curl/curl/commit/364f174724ef115c63d5e5dc1d3342c8a43b1cca", "cve": "CVE-2021-22946", "cwe": "CWE-119", "file": "curl-cve-2021-22946-imap_state_capability_re/fixed.c", "function": "imap_state_capability_resp", "id": "curl-cve-2021-22946-imap_state_capability_re:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2021-22946-imap_state_capability_re", "project": "curl", "relpath": "lib/imap.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "43157490a5054bd24256fe12876931e8abc9df49", "commit_url": "https://github.com/curl/curl/commit/364f174724ef115c63d5e5dc1d3342c8a43b1cca", "cve": "CVE-2021-22946", "cwe": "CWE-119", "file": "curl-cve-2021-22946-pop3_state_capa_resp/vuln.c", "function": "pop3_state_capa_resp", "id": "curl-cve-2021-22946-pop3_state_capa_resp:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2021-22946-pop3_state_capa_resp", "project": "curl", "relpath": "lib/pop3.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "364f174724ef115c63d5e5dc1d3342c8a43b1cca", "commit_url": "https://github.com/curl/curl/commit/364f174724ef115c63d5e5dc1d3342c8a43b1cca", "cve": "CVE-2021-22946", "cwe": "CWE-119", "file": "curl-cve-2021-22946-pop3_state_capa_resp/fixed.c", "function": "pop3_state_capa_resp", "id": "curl-cve-2021-22946-pop3_state_capa_resp:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2021-22946-pop3_state_capa_resp", "project": "curl", "relpath": "lib/pop3.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "409a4412409371db00af0a3fe987e517bfab3d19", "commit_url": "https://github.com/curl/curl/commit/43157490a5054bd24256fe12876931e8abc9df49", "cve": "CVE-2021-22945", "cwe": "CWE-119", "file": "curl-cve-2021-22945/vuln.c", "function": "mqtt_send", "id": "curl-cve-2021-22945:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2021-22945", "project": "curl", "relpath": "lib/mqtt.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "43157490a5054bd24256fe12876931e8abc9df49", "commit_url": "https://github.com/curl/curl/commit/43157490a5054bd24256fe12876931e8abc9df49", "cve": "CVE-2021-22945", "cwe": "CWE-119", "file": "curl-cve-2021-22945/fixed.c", "function": "mqtt_send", "id": "curl-cve-2021-22945:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2021-22945", "project": "curl", "relpath": "lib/mqtt.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "fd9b40bf8dfd43edcbc0d254d613d95a11061c05", "commit_url": "https://github.com/curl/curl/commit/5ea3145850ebff1dc2b13d17440300a01ca38161", "cve": "CVE-2021-22924", "cwe": "CWE-119", "file": "curl-cve-2021-22924/vuln.c", "function": "create_conn", "id": "curl-cve-2021-22924:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2021-22924", "project": "curl", "relpath": "lib/url.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "5ea3145850ebff1dc2b13d17440300a01ca38161", "commit_url": "https://github.com/curl/curl/commit/5ea3145850ebff1dc2b13d17440300a01ca38161", "cve": "CVE-2021-22924", "cwe": "CWE-119", "file": "curl-cve-2021-22924/fixed.c", "function": "create_conn", "id": "curl-cve-2021-22924:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2021-22924", "project": "curl", "relpath": "lib/url.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "fd9b40bf8dfd43edcbc0d254d613d95a11061c05", "commit_url": "https://github.com/curl/curl/commit/5ea3145850ebff1dc2b13d17440300a01ca38161", "cve": "CVE-2021-22924", "cwe": "CWE-119", "file": "curl-cve-2021-22924-nss_do_connect/vuln.c", "function": "nss_do_connect", "id": "curl-cve-2021-22924-nss_do_connect:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2021-22924-nss_do_connect", "project": "curl", "relpath": "lib/vtls/nss.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "5ea3145850ebff1dc2b13d17440300a01ca38161", "commit_url": "https://github.com/curl/curl/commit/5ea3145850ebff1dc2b13d17440300a01ca38161", "cve": "CVE-2021-22924", "cwe": "CWE-119", "file": "curl-cve-2021-22924-nss_do_connect/fixed.c", "function": "nss_do_connect", "id": "curl-cve-2021-22924-nss_do_connect:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2021-22924-nss_do_connect", "project": "curl", "relpath": "lib/vtls/nss.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "fd9b40bf8dfd43edcbc0d254d613d95a11061c05", "commit_url": "https://github.com/curl/curl/commit/5ea3145850ebff1dc2b13d17440300a01ca38161", "cve": "CVE-2021-22924", "cwe": "CWE-119", "file": "curl-cve-2021-22924-servercert/vuln.c", "function": "servercert", "id": "curl-cve-2021-22924-servercert:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2021-22924-servercert", "project": "curl", "relpath": "lib/vtls/openssl.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "5ea3145850ebff1dc2b13d17440300a01ca38161", "commit_url": "https://github.com/curl/curl/commit/5ea3145850ebff1dc2b13d17440300a01ca38161", "cve": "CVE-2021-22924", "cwe": "CWE-119", "file": "curl-cve-2021-22924-servercert/fixed.c", "function": "servercert", "id": "curl-cve-2021-22924-servercert:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2021-22924-servercert", "project": "curl", "relpath": "lib/vtls/openssl.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "12284e008bad5156b67d0ac253331a96d77201d1", "commit_url": "https://github.com/curl/curl/commit/894f6ec730597eb243618d33cc84d71add8d6a8a", "cve": "CVE-2021-22925", "cwe": "CWE-119", "file": "curl-cve-2021-22925/vuln.c", "function": "suboption", "id": "curl-cve-2021-22925:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2021-22925", "project": "curl", "relpath": "lib/telnet.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "894f6ec730597eb243618d33cc84d71add8d6a8a", "commit_url": "https://github.com/curl/curl/commit/894f6ec730597eb243618d33cc84d71add8d6a8a", "cve": "CVE-2021-22925", "cwe": "CWE-119", "file": "curl-cve-2021-22925/fixed.c", "function": "suboption", "id": "curl-cve-2021-22925:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2021-22925", "project": "curl", "relpath": "lib/telnet.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "39ce47f219b09c380b81f89fe54ac586c8db6bde", "commit_url": "https://github.com/curl/curl/commit/7f4a9a9b2a49547eae24d2e19bc5c346e9026479", "cve": "CVE-2021-22901", "cwe": "CWE-119", "file": "curl-cve-2021-22901-ossl_connect_step1/vuln.c", "function": "ossl_connect_step1", "id": "curl-cve-2021-22901-ossl_connect_step1:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2021-22901-ossl_connect_step1", "project": "curl", "relpath": "lib/vtls/openssl.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "7f4a9a9b2a49547eae24d2e19bc5c346e9026479", "commit_url": "https://github.com/curl/curl/commit/7f4a9a9b2a49547eae24d2e19bc5c346e9026479", "cve": "CVE-2021-22901", "cwe": "CWE-119", "file": "curl-cve-2021-22901-ossl_connect_step1/fixed.c", "function": "ossl_connect_step1", "id": "curl-cve-2021-22901-ossl_connect_step1:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2021-22901-ossl_connect_step1", "project": "curl", "relpath": "lib/vtls/openssl.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "bbb71507b7bab52002f9b1e0880bed6a32834511", "commit_url": "https://github.com/curl/curl/commit/39ce47f219b09c380b81f89fe54ac586c8db6bde", "cve": "CVE-2021-22898", "cwe": "CWE-119", "file": "curl-cve-2021-22898/vuln.c", "function": "suboption", "id": "curl-cve-2021-22898:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2021-22898", "project": "curl", "relpath": "lib/telnet.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "39ce47f219b09c380b81f89fe54ac586c8db6bde", "commit_url": "https://github.com/curl/curl/commit/39ce47f219b09c380b81f89fe54ac586c8db6bde", "cve": "CVE-2021-22898", "cwe": "CWE-119", "file": "curl-cve-2021-22898/fixed.c", "function": "suboption", "id": "curl-cve-2021-22898:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2021-22898", "project": "curl", "relpath": "lib/telnet.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "7214288898f5625a6cc196e22a74232eada7861c", "commit_url": "https://github.com/curl/curl/commit/b09c8ee15771c614c4bf3ddac893cdb12187c844", "cve": "CVE-2021-22890", "cwe": "CWE-119", "file": "curl-cve-2021-22890/vuln.c", "function": "bearssl_connect_step1", "id": "curl-cve-2021-22890:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2021-22890", "project": "curl", "relpath": "lib/vtls/bearssl.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "b09c8ee15771c614c4bf3ddac893cdb12187c844", "commit_url": "https://github.com/curl/curl/commit/b09c8ee15771c614c4bf3ddac893cdb12187c844", "cve": "CVE-2021-22890", "cwe": "CWE-119", "file": "curl-cve-2021-22890/fixed.c", "function": "bearssl_connect_step1", "id": "curl-cve-2021-22890:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2021-22890", "project": "curl", "relpath": "lib/vtls/bearssl.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "184ffc0bdfcab17eb96d1dd64f9c0cecc139e3e9", "commit_url": "https://github.com/curl/curl/commit/7214288898f5625a6cc196e22a74232eada7861c", "cve": "CVE-2021-22876", "cwe": "CWE-119", "file": "curl-cve-2021-22876/vuln.c", "function": "Curl_follow", "id": "curl-cve-2021-22876:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2021-22876", "project": "curl", "relpath": "lib/transfer.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "7214288898f5625a6cc196e22a74232eada7861c", "commit_url": "https://github.com/curl/curl/commit/7214288898f5625a6cc196e22a74232eada7861c", "cve": "CVE-2021-22876", "cwe": "CWE-119", "file": "curl-cve-2021-22876/fixed.c", "function": "Curl_follow", "id": "curl-cve-2021-22876:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2021-22876", "project": "curl", "relpath": "lib/transfer.c", "repo": "curl/curl", "year": 2021} +{"class": "security fix", "commit": "69a358f2186e04cf44698b5100332cbf1ee7f01d", "commit_url": "https://github.com/curl/curl/commit/d9d01672785b8ac04aab1abb6de95fe3072ae199", "cve": "CVE-2020-8286", "cwe": "CWE-119", "file": "curl-cve-2020-8286/vuln.c", "function": "verifystatus", "id": "curl-cve-2020-8286:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2020-8286", "project": "curl", "relpath": "lib/vtls/openssl.c", "repo": "curl/curl", "year": 2020} +{"class": "security fix", "commit": "d9d01672785b8ac04aab1abb6de95fe3072ae199", "commit_url": "https://github.com/curl/curl/commit/d9d01672785b8ac04aab1abb6de95fe3072ae199", "cve": "CVE-2020-8286", "cwe": "CWE-119", "file": "curl-cve-2020-8286/fixed.c", "function": "verifystatus", "id": "curl-cve-2020-8286:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2020-8286", "project": "curl", "relpath": "lib/vtls/openssl.c", "repo": "curl/curl", "year": 2020} +{"class": "security fix", "commit": "abd846c374c5269809ce11740754bc6f00a0b193", "commit_url": "https://github.com/curl/curl/commit/ec9cc725d598ac77de7b6df8afeec292b3c8ad46", "cve": "CVE-2020-8284", "cwe": "CWE-119", "file": "curl-cve-2020-8284/vuln.c", "function": "Curl_init_userdefined", "id": "curl-cve-2020-8284:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2020-8284", "project": "curl", "relpath": "lib/url.c", "repo": "curl/curl", "year": 2020} +{"class": "security fix", "commit": "ec9cc725d598ac77de7b6df8afeec292b3c8ad46", "commit_url": "https://github.com/curl/curl/commit/ec9cc725d598ac77de7b6df8afeec292b3c8ad46", "cve": "CVE-2020-8284", "cwe": "CWE-119", "file": "curl-cve-2020-8284/fixed.c", "function": "Curl_init_userdefined", "id": "curl-cve-2020-8284:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2020-8284", "project": "curl", "relpath": "lib/url.c", "repo": "curl/curl", "year": 2020} +{"class": "security fix", "commit": "abd846c374c5269809ce11740754bc6f00a0b193", "commit_url": "https://github.com/curl/curl/commit/ec9cc725d598ac77de7b6df8afeec292b3c8ad46", "cve": "CVE-2020-8284", "cwe": "CWE-119", "file": "curl-cve-2020-8284-config_init/vuln.c", "function": "config_init", "id": "curl-cve-2020-8284-config_init:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2020-8284-config_init", "project": "curl", "relpath": "src/tool_cfgable.c", "repo": "curl/curl", "year": 2020} +{"class": "security fix", "commit": "ec9cc725d598ac77de7b6df8afeec292b3c8ad46", "commit_url": "https://github.com/curl/curl/commit/ec9cc725d598ac77de7b6df8afeec292b3c8ad46", "cve": "CVE-2020-8284", "cwe": "CWE-119", "file": "curl-cve-2020-8284-config_init/fixed.c", "function": "config_init", "id": "curl-cve-2020-8284-config_init:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2020-8284-config_init", "project": "curl", "relpath": "src/tool_cfgable.c", "repo": "curl/curl", "year": 2020} +{"class": "security fix", "commit": "687908c6e6332b2bf4ba74b271e795f9c65a5a61", "commit_url": "https://github.com/curl/curl/commit/3c9e021f86872baae412a427e807fbfa2f3e8a22", "cve": "CVE-2020-8231", "cwe": "CWE-119", "file": "curl-cve-2020-8231-curl_multi_add_handle/vuln.c", "function": "curl_multi_add_handle", "id": "curl-cve-2020-8231-curl_multi_add_handle:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2020-8231-curl_multi_add_handle", "project": "curl", "relpath": "lib/multi.c", "repo": "curl/curl", "year": 2020} +{"class": "security fix", "commit": "3c9e021f86872baae412a427e807fbfa2f3e8a22", "commit_url": "https://github.com/curl/curl/commit/3c9e021f86872baae412a427e807fbfa2f3e8a22", "cve": "CVE-2020-8231", "cwe": "CWE-119", "file": "curl-cve-2020-8231-curl_multi_add_handle/fixed.c", "function": "curl_multi_add_handle", "id": "curl-cve-2020-8231-curl_multi_add_handle:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2020-8231-curl_multi_add_handle", "project": "curl", "relpath": "lib/multi.c", "repo": "curl/curl", "year": 2020} +{"class": "security fix", "commit": "687908c6e6332b2bf4ba74b271e795f9c65a5a61", "commit_url": "https://github.com/curl/curl/commit/3c9e021f86872baae412a427e807fbfa2f3e8a22", "cve": "CVE-2020-8231", "cwe": "CWE-119", "file": "curl-cve-2020-8231-curl_open/vuln.c", "function": "Curl_open", "id": "curl-cve-2020-8231-curl_open:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2020-8231-curl_open", "project": "curl", "relpath": "lib/url.c", "repo": "curl/curl", "year": 2020} +{"class": "security fix", "commit": "3c9e021f86872baae412a427e807fbfa2f3e8a22", "commit_url": "https://github.com/curl/curl/commit/3c9e021f86872baae412a427e807fbfa2f3e8a22", "cve": "CVE-2020-8231", "cwe": "CWE-119", "file": "curl-cve-2020-8231-curl_open/fixed.c", "function": "Curl_open", "id": "curl-cve-2020-8231-curl_open:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2020-8231-curl_open", "project": "curl", "relpath": "lib/url.c", "repo": "curl/curl", "year": 2020} +{"class": "security fix", "commit": "26d2755d7c3181e90e46014778941bff53d2309f", "commit_url": "https://github.com/curl/curl/commit/8236aba58542c5f89f1d41ca09d84579efb05e22", "cve": "CVE-2020-8177", "cwe": "CWE-119", "file": "curl-cve-2020-8177/vuln.c", "function": "tool_header_cb", "id": "curl-cve-2020-8177:vuln", "label": "vuln", "license": "curl", "pair": "curl-cve-2020-8177", "project": "curl", "relpath": "src/tool_cb_hdr.c", "repo": "curl/curl", "year": 2020} +{"class": "security fix", "commit": "8236aba58542c5f89f1d41ca09d84579efb05e22", "commit_url": "https://github.com/curl/curl/commit/8236aba58542c5f89f1d41ca09d84579efb05e22", "cve": "CVE-2020-8177", "cwe": "CWE-119", "file": "curl-cve-2020-8177/fixed.c", "function": "tool_header_cb", "id": "curl-cve-2020-8177:fixed", "label": "fixed", "license": "curl", "pair": "curl-cve-2020-8177", "project": "curl", "relpath": "src/tool_cb_hdr.c", "repo": "curl/curl", "year": 2020} diff --git a/src/openultrasast/cli.py b/src/openultrasast/cli.py index a243fe4..f4c5ddc 100644 --- a/src/openultrasast/cli.py +++ b/src/openultrasast/cli.py @@ -125,7 +125,7 @@ def main(argv: list[str] | None = None) -> int: help="scan isolated vuln-vs-fixed pairs (TP on vuln, silent on fix) and emit improve-loop signals", ) pairs.add_argument("--catalog", type=Path, default=DEFAULT_CATALOG) - pairs.add_argument("--slice", choices=("all", "local", "github", "sast"), default="all") + pairs.add_argument("--slice", choices=("all", "local", "github", "sast", "vfc"), default="all") pairs.add_argument("--json", action="store_true", help="print the pair scoreboard as JSON") subparsers.add_parser("mcp", help="run the narrow MCP server over stdio for OpenCode integration") diff --git a/src/openultrasast/pair_gate.py b/src/openultrasast/pair_gate.py index 4c406ed..5be88db 100644 --- a/src/openultrasast/pair_gate.py +++ b/src/openultrasast/pair_gate.py @@ -1,9 +1,9 @@ """Pair-efficiency gate: local fixtures must fire on vuln and stay silent on fix. The stage-1 smoke gate stays on cheat-sheet trees. This module measures -differential detection and only *fails CI* on the local slice. GitHub/SVEN -pairs are printed as the honesty dashboard (real VFC misses become improve -signals, they do not block merge). +differential detection and only *fails CI* on the local slice. GitHub/SVEN, +sast, and vfc pairs are honesty dashboards (`ousast pairs --slice ...`); +they are not evaluated here so a large vfc catalog cannot slow the merge gate. python -m openultrasast.pair_gate """ @@ -36,7 +36,7 @@ def pair_gate(cases: Sequence[PairCase] | None = None) -> PairGateVerdict: local = select_slice(catalog, "local") if not local: return PairGateVerdict(passed=False, reasons=("no local pairs in catalog",), result=evaluate_catalog(())) - result = evaluate_catalog(catalog) + result = evaluate_catalog(local) local_metrics = result.per_slice.get("local") reasons: list[str] = [] if local_metrics is None: @@ -62,6 +62,12 @@ def print_pair_metrics(label: str, result: PairEvalResult) -> None: f"vuln {metrics.vuln_recall:>6.2%} silent {metrics.specificity:>6.2%} " f"Youden {metrics.youden:>+7.2%} labeled {metrics.labeled_recall:>6.2%}" ) + for slice_name, inner in result.scorers.items(): + for scorer, metrics in inner.items(): + print( + f" {slice_name:<8} scorer={scorer:<10} pair_pass {metrics.pair_pass_rate:>6.2%} " + f"({metrics.pair_correct}/{metrics.pairs}) Youden {metrics.youden:>+7.2%}" + ) for outcome in result.outcomes: mark = "PASS" if outcome.pair_correct else "MISS" if not outcome.detected_vuln else "LEAK" print( diff --git a/src/openultrasast/pairs.py b/src/openultrasast/pairs.py index e99c461..b1fabf2 100644 --- a/src/openultrasast/pairs.py +++ b/src/openultrasast/pairs.py @@ -11,7 +11,7 @@ import shutil import tempfile import tomllib from collections.abc import Sequence -from dataclasses import asdict, dataclass +from dataclasses import asdict, dataclass, field from pathlib import Path from .benchmark import ( @@ -30,7 +30,9 @@ from .semantic import OverlayRecord, adjudicate DEFAULT_CATALOG = Path("benchmarks/pairs/catalog.toml") DEFAULT_SAST_CATALOG = Path("benchmarks/pairs/sast/catalog.toml") +DEFAULT_VFC_CATALOG = Path("benchmarks/pairs/vfc/catalog.toml") DEFAULT_DATASETS = Path("benchmarks/pairs/datasets.toml") +OVERLAY_SLICES = frozenset({"sast", "vfc"}) @dataclass(frozen=True) @@ -95,6 +97,7 @@ class PairEvalResult: overall: PairCorpusMetrics per_slice: dict[str, PairCorpusMetrics] signals: tuple[dict[str, object], ...] + scorers: dict[str, dict[str, PairCorpusMetrics]] = field(default_factory=dict) def load_datasets(path: Path = DEFAULT_DATASETS) -> tuple[dict[str, object], ...]: @@ -104,8 +107,11 @@ def load_datasets(path: Path = DEFAULT_DATASETS) -> tuple[dict[str, object], ... def load_pair_catalog(path: Path = DEFAULT_CATALOG) -> tuple[PairCase, ...]: cases = _load_catalog_file(path) - if path.resolve() == DEFAULT_CATALOG.resolve() and DEFAULT_SAST_CATALOG.exists(): - cases = cases + _load_catalog_file(DEFAULT_SAST_CATALOG) + if path.resolve() == DEFAULT_CATALOG.resolve(): + if DEFAULT_SAST_CATALOG.exists(): + cases = cases + _load_catalog_file(DEFAULT_SAST_CATALOG) + if DEFAULT_VFC_CATALOG.exists(): + cases = cases + _load_catalog_file(DEFAULT_VFC_CATALOG) return cases @@ -142,48 +148,21 @@ def evaluate_pair(case: PairCase) -> PairOutcome: with tempfile.TemporaryDirectory(prefix="ousast-pair-") as scratch: vuln_root = _materialize(Path(scratch) / "vuln", case.vuln_file, case.relpath) fix_root = _materialize(Path(scratch) / "fixed", case.fixed_file, case.relpath) - if case.slice == "sast": + if case.slice in OVERLAY_SLICES: return _evaluate_overlay_pair(case, vuln_root, fix_root) - vuln_findings = _quick_scan(vuln_root) - fix_findings = _quick_scan(fix_root) - vuln_result = evaluate_benchmark( - run=BenchmarkRun(benchmark_run_id="pair", root=Path("/tmp/pair"), manifest=_manifest(case)), - mode="quick", - findings=vuln_findings, - scan_id=None, - scan_run_dir=None, - ) - expected_total = len(case.expected) - matched = vuln_result.metrics.matched_findings_total - recall = matched / expected_total if expected_total else 1.0 - leaks = _fix_leaks(case, fix_findings) - detected = recall + 1e-12 >= case.min_recall - silent = not leaks - misses = tuple(f"{miss.rule_id or '-'}:{miss.path}:{miss.cwe}" for miss in vuln_result.misses) - leak_ids = tuple(finding.finding_id for finding in leaks) - return PairOutcome( - name=case.name, - slice=case.slice, - language=case.language, - origin=case.origin, - detected_vuln=detected, - silent_fix=silent, - pair_correct=detected and silent, - vuln_matched=matched, - vuln_expected=expected_total, - vuln_findings=len(vuln_findings), - fix_findings=len(fix_findings), - fix_leaks=len(leaks), - recall=recall, - misses=misses, - leaks=leak_ids, - commit_url=case.commit_url, - cve=case.cve, - ) + return _evaluate_inventory_pair(case, vuln_root, fix_root) def evaluate_catalog(cases: Sequence[PairCase]) -> PairEvalResult: outcomes = tuple(evaluate_pair(case) for case in cases) + scorers: dict[str, dict[str, PairCorpusMetrics]] = {} + vfc_cases = tuple(case for case in cases if case.slice == "vfc") + if vfc_cases: + overlay_outcomes = tuple(item for item in outcomes if item.slice == "vfc") + scorers["vfc"] = { + "overlay": _metrics(overlay_outcomes), + "inventory": _metrics(tuple(_inventory_only(case) for case in vfc_cases)), + } return PairEvalResult( outcomes=outcomes, overall=_metrics(outcomes), @@ -192,6 +171,7 @@ def evaluate_catalog(cases: Sequence[PairCase]) -> PairEvalResult: for slice_name in sorted({item.slice for item in outcomes}) }, signals=tuple(build_pair_signals(outcomes)), + scorers=scorers, ) @@ -220,6 +200,10 @@ def result_payload(result: PairEvalResult) -> dict[str, object]: "per_slice": {name: asdict(metrics) for name, metrics in result.per_slice.items()}, "outcomes": [asdict(outcome) for outcome in result.outcomes], "signals": list(result.signals), + "scorers": { + slice_name: {scorer: asdict(metrics) for scorer, metrics in inner.items()} + for slice_name, inner in result.scorers.items() + }, } @@ -290,6 +274,52 @@ def _overlay_scan(target: Path) -> tuple[list[StaticFinding], list[OverlayRecord return findings, adjudicate(root=target, targets=targets, findings=findings) +def _inventory_only(case: PairCase) -> PairOutcome: + with tempfile.TemporaryDirectory(prefix="ousast-pair-inv-") as scratch: + vuln_root = _materialize(Path(scratch) / "vuln", case.vuln_file, case.relpath) + fix_root = _materialize(Path(scratch) / "fixed", case.fixed_file, case.relpath) + return _evaluate_inventory_pair(case, vuln_root, fix_root) + + +def _evaluate_inventory_pair(case: PairCase, vuln_root: Path, fix_root: Path) -> PairOutcome: + vuln_findings = _quick_scan(vuln_root) + fix_findings = _quick_scan(fix_root) + vuln_result = evaluate_benchmark( + run=BenchmarkRun(benchmark_run_id="pair", root=Path("/tmp/pair"), manifest=_manifest(case)), + mode="quick", + findings=vuln_findings, + scan_id=None, + scan_run_dir=None, + ) + expected_total = len(case.expected) + matched = vuln_result.metrics.matched_findings_total + recall = matched / expected_total if expected_total else 1.0 + leaks = _fix_leaks(case, fix_findings) + detected = recall + 1e-12 >= case.min_recall + silent = not leaks + misses = tuple(f"{miss.rule_id or '-'}:{miss.path}:{miss.cwe}" for miss in vuln_result.misses) + leak_ids = tuple(finding.finding_id for finding in leaks) + return PairOutcome( + name=case.name, + slice=case.slice, + language=case.language, + origin=case.origin, + detected_vuln=detected, + silent_fix=silent, + pair_correct=detected and silent, + vuln_matched=matched, + vuln_expected=expected_total, + vuln_findings=len(vuln_findings), + fix_findings=len(fix_findings), + fix_leaks=len(leaks), + recall=recall, + misses=misses, + leaks=leak_ids, + commit_url=case.commit_url, + cve=case.cve, + ) + + def _evaluate_overlay_pair(case: PairCase, vuln_root: Path, fix_root: Path) -> PairOutcome: vuln_findings, vuln_overlay = _overlay_scan(vuln_root) fix_findings, fix_overlay = _overlay_scan(fix_root) diff --git a/tests/test_pair_corpus.py b/tests/test_pair_corpus.py index 1092146..afd619e 100644 --- a/tests/test_pair_corpus.py +++ b/tests/test_pair_corpus.py @@ -10,6 +10,7 @@ from openultrasast.pair_gate import pair_gate from openultrasast.pairs import ( DEFAULT_CATALOG, DEFAULT_SAST_CATALOG, + DEFAULT_VFC_CATALOG, PairCase, build_pair_signals, evaluate_catalog, @@ -24,12 +25,15 @@ def test_catalog_loads_local_and_github_slices() -> None: cases = load_pair_catalog(DEFAULT_CATALOG) slices = {case.slice for case in cases} names = {case.name for case in cases} - assert {"local", "github", "sast"} <= slices + assert {"local", "github", "sast", "vfc"} <= slices assert "local-python-vulnerable" in names assert "sven-cwe-078-os-system" in names assert "hutool-cve-2018-17297" in names assert "owasp-python-codeinj" in names assert "juliet-c-cwe134-printf" in names + assert "openssl-cve-2014-0160" in names + assert "firefox-cve-2020-15667" in names + assert "chromium-cve-2019-5786" in names assert all(case.vuln_file.is_file() and case.fixed_file.is_file() for case in cases) @@ -52,8 +56,13 @@ def test_datasets_catalog_lists_public_vfc_repos() -> None: "OWASP Benchmark Python", "Juliet Test Suite C/C++", "Juliet Test Suite Java", + "OpenSSL", + "Firefox mozilla-central", + "Chromium", + "curl", } <= names assert DEFAULT_SAST_CATALOG.is_file() + assert DEFAULT_VFC_CATALOG.is_file() java = Path("benchmarks/pairs/datasets/cwe-bench-java-project_info.csv") assert java.is_file() assert "CVE-2018-17297" in java.read_text() @@ -161,6 +170,55 @@ def test_sast_slice_scores_owasp_and_juliet() -> None: assert -1.0 <= result.overall.youden <= 1.0 +def test_vfc_slice_is_labeled_openssl_firefox_chromium() -> None: + cases = select_slice(load_pair_catalog(), "vfc") + by_name = {case.name: case for case in cases} + assert set(by_name) >= { + "openssl-cve-2014-0160", + "firefox-cve-2020-15667", + "chromium-cve-2019-5786", + "openssl-cve-2022-1292", + "chromium-cve-2022-2162", + "curl-cve-2023-38545", + "openssl-cve-2025-69421", + } + for case in cases: + header = case.vuln_file.read_text() + case.fixed_file.read_text() + assert case.commit_url + assert case.cve + assert case.license + assert case.cve in header + assert case.license.split()[0] in header + assert case.vuln_file != case.fixed_file + sample = tuple(case for case in cases if case.name in {"openssl-cve-2014-0160", "firefox-cve-2020-15667", "chromium-cve-2019-5786"}) + result = evaluate_catalog(sample) + assert result.overall.pairs == len(sample) + assert "overlay" in result.scorers["vfc"] + assert "inventory" in result.scorers["vfc"] + # Honesty dashboard: memcpy-after-fix and UAF are labeled, not a 100% gate. + assert -1.0 <= result.overall.youden <= 1.0 + + +def test_vfc_training_manifest_has_vuln_and_fixed_labels() -> None: + import json + + manifest = Path("benchmarks/pairs/vfc/training/manifest.jsonl") + rows = [json.loads(line) for line in manifest.read_text().splitlines() if line.strip()] + assert rows + assert {row["label"] for row in rows} == {"vuln", "fixed"} + by_pair: dict[str, set[str]] = {} + for row in rows: + by_pair.setdefault(str(row["pair"]), set()).add(str(row["label"])) + excerpt = Path("benchmarks/pairs/vfc") / str(row["file"]) + assert excerpt.is_file(), row["id"] + assert 2014 <= int(row["year"]) <= 2026 + assert all(labels == {"vuln", "fixed"} for labels in by_pair.values()) + recent = {row["pair"] for row in rows if 2020 <= int(row["year"]) <= 2026} + assert len(recent) >= 80 + assert len(by_pair) >= 100 + assert len(rows) == 2 * len(by_pair) + + def test_cli_pairs_json_scoreboard() -> None: import io from contextlib import redirect_stdout @@ -171,3 +229,19 @@ def test_cli_pairs_json_scoreboard() -> None: payload = json.loads(buf.getvalue()) assert payload["overall"]["pairs"] >= 4 assert "sven-cwe-078-os-system" in {item["name"] for item in payload["outcomes"]} + + +def test_cli_vfc_json_includes_dual_scorers() -> None: + import io + from contextlib import redirect_stdout + + buf = io.StringIO() + with redirect_stdout(buf): + assert main(["pairs", "--slice", "vfc", "--json"]) == 0 + payload = json.loads(buf.getvalue()) + names = {item["name"] for item in payload["outcomes"]} + assert {"openssl-cve-2014-0160", "firefox-cve-2020-15667", "chromium-cve-2019-5786"} <= names + assert payload["overall"]["pairs"] >= 3 + assert "overlay" in payload["scorers"]["vfc"] + assert "inventory" in payload["scorers"]["vfc"] + assert payload["per_slice"]["vfc"]["pairs"] == payload["scorers"]["vfc"]["overlay"]["pairs"] diff --git a/tests/test_vfc_harvest.py b/tests/test_vfc_harvest.py new file mode 100644 index 0000000..1807b4b --- /dev/null +++ b/tests/test_vfc_harvest.py @@ -0,0 +1,95 @@ +"""Maintainer VFC harvest stays offline in CI: extract and reject, no HTTP.""" + +from __future__ import annotations + +import runpy +from pathlib import Path + +import pytest + +HARVEST = Path("benchmarks/pairs/vfc/harvest.py") + + +def _harvest() -> dict[str, object]: + return runpy.run_path(str(HARVEST)) + + +def test_extract_function_round_trips_perl_sub_without_parens() -> None: + harvest = _harvest() + source = """ +sub other { return 0; } +sub link_hash_cert { + my ($hash, $fprint) = `"$openssl" x509 -in "$fname"`; +} +sub later { return 1; } +""" + body = harvest["extract_function"](source, "link_hash_cert") + assert "sub link_hash_cert {" in body + assert "`\"$openssl\" x509" in body + assert "sub other" not in body + assert "sub later" not in body + + +def test_extract_function_round_trips_a_local_body() -> None: + harvest = _harvest() + source = """ +int before(void) { return 0; } + +int target_fn(char *name, int namelen) { + memcpy(name, name, namelen + 1); + return namelen; +} + +int after(void) { return 1; } +""" + body = harvest["extract_function"](source, "target_fn") + assert "int target_fn(char *name, int namelen)" in body + assert "memcpy(name, name, namelen + 1);" in body + assert "int before" not in body + assert "int after" not in body + + +def test_extract_function_skips_prototype_before_definition() -> None: + harvest = _harvest() + source = """ +class Loader { + public: + char *ArrayBufferResult(); +}; + +char *Loader::ArrayBufferResult() { + return raw_data_->ToArrayBuffer(); +} +""" + body = harvest["extract_function"](source, "ArrayBufferResult") + assert "Loader::ArrayBufferResult" in body + assert "return raw_data_->ToArrayBuffer();" in body + assert "class Loader" not in body + + +def test_validate_recipe_rejects_advisory_only_and_fixfox() -> None: + harvest = _harvest() + validate = harvest["validate_recipe"] + with pytest.raises(harvest["RecipeError"], match="advisory-only"): + validate({"name": "mfsa-only", "cve": "CVE-2019-11730"}) + with pytest.raises(harvest["RecipeError"], match="embargoed"): + validate( + { + "name": "fixfox", + "parent": "abc", + "commit": "def", + "path": "a.c", + "function": "f", + "license": "MIT", + "url": "https://zenodo.org/record/fixfox", + } + ) + + +def test_harvest_dry_run_accepts_seed_recipes() -> None: + harvest = _harvest() + recipes = {str(item["name"]): item for item in harvest["load_recipes"](Path("benchmarks/pairs/vfc/recipes.toml"))} + assert {"openssl-cve-2014-0160", "firefox-cve-2020-15667", "chromium-cve-2019-5786"} <= set(recipes) + for recipe in recipes.values(): + harvest["validate_recipe"](recipe) + assert harvest["main"](["--name", "openssl-cve-2014-0160"]) == 0