Skip to content

danindiana/oqs-ssl-threat-vector

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OQS SSL Provider Threat Vector Analysis

Stars Forks License: CC BY 4.0 Last Commit Repo Size

date system kernel openssl liboqs diagrams threat vectors status


OQS SSL Provider — Threat Vector Analysis

A security research document grounded in a real system incident. On May 27, 2026, the machine worlock experienced a cascading crash of all SSL-linked processes — including sort, grep, lsof, dpkg-query, ollama, and the claude CLI — due to a corrupted OpenSSL OQS (Open Quantum Safe) provider propagating via /etc/environment. This repository documents the incident, maps the attack surface to 7 primary threat vectors, and expands the analysis into 32 Graphviz diagrams covering architecture, topology, empirical data, causality chains, and future defensive directions.

All artifact paths, library versions, and crash sequences are verified against the live system.


Table of Contents

  1. Incident Overview
  2. The 7 Threat Vectors
  3. Architecture Diagrams
  4. System Topology Diagrams
  5. Empirical Results
  6. Causality Chains
  7. Future Directions
  8. Defensive Countermeasures
  9. Affected Artifacts
  10. Reproduction Notes
  11. References

Incident Overview

Boot Timeline

Boot Index Start (CDT) End (CDT) Duration Status
-2 Wed May 27 09:59 Wed May 27 23:04 13h 4m CRASH BOOT
-1 Wed May 27 23:04 Thu May 29 11:23 ~36h Partial stability
0 Thu May 29 11:23 (running) STABLE

What Crashed

May 28 09:47:35  ollama      SIGSEGV  (×6 total)
May 28 11:15:57  claude      SIGSEGV
May 28 11:16:23  dpkg-query  SIGABRT  ← KEY INDICATOR
May 28 11:16:41  claude      SIGILL
May 28 21:02:47  sort        SIGSEGV  ← KEY INDICATOR
May 28 21:42:09  grep        SIGSEGV  ← KEY INDICATOR
May 28 21:42:46  lsof        SIGSEGV  ← KEY INDICATOR

Smoking gun: sort, grep, lsof, and dpkg-query have no GPU or ML dependencies. Their only shared exposure with ollama and claude is the crypto stack — specifically libssl/libcrypto. When unrelated system utilities crash simultaneously, a shared library is poisoned.

Root Cause

/etc/environment
  └─ OPENSSL_CONF=/usr/local/ssl/openssl.cnf   ← dev build left behind
        └─ loads oqsprovider.so linked to liboqs.so.8 (dev ABI)
              └─ every process that calls OPENSSL_init_ssl() → SIGSEGV

Two concurrent faults:

  1. OQS dev buildliboqs.so.8 installed alongside stable liboqs.so.9; OPENSSL_CONF pointing at the dev config was left in /etc/environment after a gryphgen build session
  2. APT mirror corruptionus.archive.ubuntu.com serving malformed packages with bad UTF-8 metadata, compounding package manager instability

Both were fixed on May 27-29. See session.md for the full incident narrative.


The 7 Threat Vectors

TV1: OPENSSL_CONF as Universal Process Hijack

OPENSSL_CONF in /etc/environment is inherited by every process started by PAM. A single line written by an attacker with root access (e.g., via a malicious apt postinst script) poisons the crypto environment of all login sessions, shell children, cron jobs, and system services.

TV1: OPENSSL_CONF Hijack

Privilege ladder:

  • /etc/environment (root) → all users, all processes
  • ~/.pam_environment (user) → that user's sessions, no root needed
  • systemd Environment= (root, per-unit) → correct, scoped pattern

TV2: ossl-modules/ as Stealthy Persistence Drop Zone

/usr/lib/x86_64-linux-gnu/ossl-modules/ is the OpenSSL plugin directory. Any .so placed here and referenced in openssl.cnf is loaded in-process into every application calling OPENSSL_init_ssl() — with no separate PID, no auditd entry, and no debsums baseline unless manually configured.

TV2: ossl-modules Persistence

Why this beats LD_PRELOAD for stealth:

  • No separate process ID
  • Not logged by auditd execve hooks
  • Not visible in /proc/<pid>/environ
  • Not tracked by debsums (if not dpkg-installed)
  • Affects all SSL processes, not just one

TV3: Supply Chain via Build-from-Source

Both liboqs.so.0.15.0 and oqsprovider.so on worlock are built from GitHub source. Neither is dpkg-tracked. This means: no debsums integrity check, no apt signature verification, no dpkg --verify, and no automatic removal on apt purge.

TV3: Supply Chain

A compromised open-quantum-safe/oqs-provider upstream — via maintainer account compromise, dependency confusion, or a malicious CMake toolchain — propagates silently to every source-builder. The resulting .so is loaded into sshd, nginx, curl, dpkg, and every other SSL-linked process simultaneously.


TV4: Crash-as-DoS Weaponization

The May 27 incident is an unintentional but fully functional proof-of-concept system DoS. A single bad OPENSSL_CONF entry brought down the entire SSL process tree in minutes, including the package manager needed to fix the problem.

TV4: Crash DoS

The recovery paradox: dpkg-query itself crashed, meaning apt could not be used to fix the broken library. Recovery required the out-of-band WAN SSH path on port 57291 (ryleh-worlock.duckdns.org).


TV5: ABI Version Confusion

The actual crash mechanism: oqsprovider.so was compiled against liboqs.so.9 (stable ABI), but OPENSSL_CONF pointed to a dev config that loaded liboqs.so.8 (dev ABI). The dynamic linker resolves symbols by name, not by offset — so the wrong .so loads, and the first call into a mismatched function produces SIGSEGV, SIGILL, or SIGABRT depending on how the offset lands.

TV5: ABI Confusion

An attacker who can plant a .so with the correct SONAME but a subtly wrong dispatch table can trigger crashes on specific codepaths only — e.g., only during RSA-PSS signing, only during TLS client auth — making the attack highly targeted and difficult to reproduce in a test environment.


TV6: Crypto Exfiltration via Malicious Provider

The worlock incident crashed. A sophisticated attacker would not crash — they would intercept silently. An OpenSSL provider sits between the application and the hardware crypto layer, with hooks at every key generation, signing, decapsulation, and PRNG call.

TV6: Crypto Exfil

Hook What the Attacker Gets
OSSL_FUNC_KEYMGMT_GEN Full private key at birth
OSSL_FUNC_KEM_DECAPSULATE Session pre-master secret
OSSL_FUNC_SIGNATURE_SIGN Private key usage + signed data
OSSL_FUNC_RAND_GENERATE Ability to bias randomness
OSSL_FUNC_SIGNATURE_VERIFY Ability to accept forged certs

Detection gap: openssl list -providers shows the provider as active but cannot verify its behavior. No standard audit tool performs behavioral attestation of loaded providers.


TV7: Post-Quantum Downgrade Attack

OQS provider enables TLS 1.3 hybrid key exchange (e.g., X25519Kyber768). A malicious provider can advertise PQ support during negotiation but silently compute only the classical X25519 component, skipping Kyber768 entirely and filling the PQ ciphertext slot with fake bytes.

TV7: PQ Downgrade

The remote server cannot detect this — it receives a valid-length ciphertext and derives its half of the session key normally. The result is a TLS session that appears post-quantum but has only classical X25519 forward secrecy. A state-level adversary harvesting traffic today can decrypt it once a cryptographically-relevant quantum computer exists (~2035+).


Architecture Diagrams

These diagrams document the internal structure of the OpenSSL 3.x provider system that makes all of the above threat vectors possible.

Arch 1: OpenSSL 3.x Provider Stack

The full layered stack from application through libssl → libcrypto → provider dispatch → algorithm implementation, including the path a malicious provider takes.

OpenSSL Provider Stack

Arch 2: Provider Dispatch Table Anatomy

Every OpenSSL 3.x provider must implement an OSSL_DISPATCH table mapping function IDs to function pointers. This diagram maps every major function ID to what it exposes — and which are the highest-value intercept points for an attacker.

Provider Dispatch Table

Arch 3: OPENSSL_CONF Resolution Chain

How OpenSSL finds and parses its configuration, from environment variable through config file sections through provider loading — and where the worlock incident's attack path entered this chain.

OPENSSL_CONF Resolution

Arch 4: ossl-modules Plugin Load Lifecycle

The six phases of plugin loading: discovery → dlopen → symbol resolution → initialization → algorithm registration → active dispatch. Includes the failure paths that produced the worlock crash.

Plugin Load Lifecycle

Arch 5: TLS 1.3 Handshake → Provider Call Graph

Maps each TLS 1.3 handshake step to the specific provider function calls it triggers, annotated with what a malicious provider intercepts at each step, and the OQS hybrid KEM downgrade opportunity.

TLS Handshake Call Graph


System Topology Diagrams

These diagrams show the physical and logical structure of worlock and how the attack surface maps onto it.

Topo 1: worlock System Topology

Hardware through kernel through systemd services, with attack surface nodes marked. Includes GPU configuration, NIC state, and the specific services affected by the OQS incident.

worlock System Topology

Topo 2: Shared Library Dependency Graph

Which processes link against libssl/libcrypto, and which link libcrypto only. The blast radius of a poisoned provider is every process in this graph. Includes the surprising entries: sort, grep, lsof.

Shared Library Deps

Topo 3: systemd Service Dependency Graph

The systemd service dependency tree for worlock, annotated with which services touch SSL and how a provider failure propagates through the dependency graph.

systemd Service Deps

Topo 4: Network Attack Surface Map

External-facing attack surface: UFW rules, exposed ports, VPN state, WAN SSH out-of-band path, and the Cloudflare tunnel. Maps what an external attacker sees vs. what the OQS internal attack surface is.

Network Attack Surface

Topo 5: PAM → Process Inheritance Tree

How environment variables flow from /etc/environment through PAM into every child process at login. Includes the user-level attack via ~/.pam_environment and the systemd escape hatch.

PAM Inheritance Tree


Empirical Results

These diagrams are grounded in actual data from the May 27-29 incident logs.

Emp 1: Crash Timeline (May 27–29)

Chronological map of every crash event from boot to stable recovery, with timestamps from journalctl -b -1 -p err.

Crash Timeline

Emp 2: Core Dump Frequency by Process

Ranked breakdown of the 12 core dumps across 6 processes, with signal types and timestamps. The coreutils entries are the diagnostic key.

Core Dump Frequency

Emp 3: Affected Process × Root Cause Matrix

Cross-matrix of which processes were exposed to which root causes (OPENSSL_CONF scope, APT mirror, ABI mismatch, missing baseline). Identifies the minimum fix set needed.

Process × Cause Matrix

Emp 4: System Stability Timeline (All Boots)

Boot-index view of all recent boots from -13 to 0, with uptime bars and crash markers. Shows the affected boot window vs. stable history.

Boot Stability Timeline

Emp 5: MTTD / MTTR Metrics

Mean Time to Detect and Mean Time to Recover — actual vs. projected with monitoring in place. Quantifies the value of the out-of-band SSH path and the cost of the missing monitoring layer.

MTTD / MTTR


Causality Chains

Step-by-step causal flows from root cause to observed effect.

Cause 1: Root Cause Fault Tree (FTA)

Formal fault tree with AND/OR gates from the top event (system DoS) through intermediate events to the two root causes and their enabling conditions.

Fault Tree

Cause 2: OQS Provider Load Failure Sequence

Ten-step walk through the exact mechanism: process start → OPENSSL_init_ssl() → config resolution → dlopenrtld ABI mismatch → SIGSEGV/SIGILL/SIGABRT → repeat for all processes.

Provider Load Failure

Cause 3: APT Mirror Poisoning → Crash Cascade

The parallel causal chains — OQS dev build (primary) and APT mirror corruption (concurrent) — converging to produce the crash cascade, including the recovery paradox where dpkg-query itself crashed.

APT Mirror Cascade

Cause 4: Fix Propagation Chain

What each of the five fix steps resolved and what remained as gaps afterward. Includes priority ordering and the remaining TODO items.

Fix Propagation

Cause 5: Detection Pathway Decision Tree

Step-by-step detection flow: if you suspect an OQS provider issue, what to check in what order, and what each check result implies about which threat vector is active.

Detection Pathway


Future Directions

Defensive and architectural evolution paths for the OQS provider ecosystem.

Future 1: Post-Quantum Migration Roadmap

NIST PQC finalization (2024) → TLS 1.3 hybrid default (2027) → distro packaging (2028) → classical deprecation (2033) → CRHQ horizon (~2035). Anchored to worlock's current position on this timeline.

PQ Migration Roadmap

Future 2: Provider Integrity Attestation Pipeline

TPM-backed provider verification: build-time GPG signing → install-time hash verification → boot-time PCR extension → runtime remote attestation. Maps the gap between worlock's current state (Level 0) and SLSA Level 3.

Provider Attestation

Future 3: Automated ossl-modules Monitoring

Three-layer monitoring pipeline: inotifywait filesystem events (instant) → systemd timer hash check (15-minute periodic) → strace behavioral audit (on-demand). With automated quarantine and service restart response.

Automated Monitoring

Future 4: Build Provenance Pipeline (SLSA)

Current state (SLSA Level 0: no provenance) → Level 1 (documented build) → Level 2 (verified source via git verify-tag) → Level 3 (reproducible, signed, attested) → ideal state (distro package, ETA 2028).

Build Provenance SLSA

Future 5: Zero-Trust Crypto Stack Architecture

Per-service OPENSSL_CONF isolation eliminates the blast radius of any single provider compromise. The anti-pattern (global OPENSSL_CONF) vs. the target architecture (each service declares its own crypto config), with the containment result demonstrated by the worlock fix.

Zero-Trust Crypto


Defensive Countermeasures

Immediate (apply now)

# 1. Remove OPENSSL_CONF from global environment
grep -n OPENSSL_CONF /etc/environment  # should return nothing
# If set: remove or comment it out

# 2. Scope to the specific service that needs it
# /etc/systemd/system/my-oqs-service.service
# [Service]
# Environment=OPENSSL_CONF=/etc/my-service-openssl.cnf

# 3. Verify only the default provider loads globally
openssl list -providers
# Expected: only "default" (active)

# 4. Create a baseline of ossl-modules
sha256sum /usr/lib/x86_64-linux-gnu/ossl-modules/*.so > /etc/ossl-modules.sha256
chmod 600 /etc/ossl-modules.sha256

Short-Term (this week)

# 5. Periodic integrity check (add to cron or systemd timer)
sha256sum -c /etc/ossl-modules.sha256

# 6. Filesystem watch (install inotify-tools)
# inotifywait -m /usr/lib/x86_64-linux-gnu/ossl-modules/ -e create,modify,delete

# 7. Verify OQS provider is NOT loaded by default processes
strace -e trace=network openssl speed aes-256-gcm 2>&1 | grep -c connect
# Expected: 0

# 8. Check for unexpected ossl-modules entries
ls /usr/lib/x86_64-linux-gnu/ossl-modules/
# Should only contain: legacy.so, oqsprovider.so (if intentional)

Medium-Term (this month)

# 9. Pin OQS builds to GPG-signed tags
cd liboqs && git verify-tag 0.15.0  # import OQS maintainer keys first

# 10. Behavioral audit before enabling any new provider
strace -e trace=write,open,network openssl genrsa 2048 2>/dev/null | head -20

# 11. Disable stale services
systemctl disable network-queue-optimization.service  # DONE 2026-05-29

Provider Attestation Checklist

Before enabling any non-default OpenSSL provider in production:

  • Provider .so hash recorded in /etc/ossl-modules.sha256
  • OPENSSL_CONF scoped to the specific service — not in /etc/environment
  • Build verified against a GPG-signed upstream tag
  • openssl list -providers -verbose shows expected name and version
  • strace behavioral check: no unexpected connect() / write() calls
  • Recovery path tested: can you reach the system if all SSL processes crash?
  • inotifywait watch active on ossl-modules/

Affected Artifacts

Artifact Path State
OQS provider /usr/lib/x86_64-linux-gnu/ossl-modules/oqsprovider.so Stable 0.11.0 (rebuilt May 27)
liboqs /usr/local/lib/liboqs.so.9 (→ liboqs.so.0.15.0) Stable (rebuilt May 27)
liboqs dev (removed) /usr/local/lib/liboqs.so.8 Removed
OpenSSL config (dev) /usr/local/ssl/openssl.cnf Still exists but not referenced
Global env /etc/environment OPENSSL_CONF removed
gryphgen service /etc/systemd/system/gryphgen-agentic.service Environment=OPENSSL_CONF=... scoped
Failing service network-queue-optimization.service Disabled May 29
Core dumps /var/lib/systemd/coredump/ 12 dumps (May 28-29)

Reproduction Notes

To reproduce the ABI confusion crash (in a safe test environment):

# Build two versions of liboqs with different SONAME
# Install both to /usr/local/lib/
# Create openssl.cnf pointing to oqsprovider compiled against v1
# but with RPATH/NEEDED referencing v2
# Set OPENSSL_CONF=/path/to/that/cnf
# Run: openssl list -providers  → SIGSEGV

# DO NOT do this on a production system
# The crash will affect every SSL process on the machine

To reproduce the detection gap:

# Even with a "malicious" provider, this shows it as active:
openssl list -providers
# Output: default (active), oqsprovider (active) ← no behavioral info

# Behavioral check (the right way):
strace -f -e trace=network openssl speed kyber768 2>&1 | grep -E "connect|send|recv"
# A clean provider: no output
# A malicious exfil provider: connect() to attacker IP

References


File Index

Category Files
Session doc session.md
Logo logo.svg, logo.png
Threat Vectors (7) tv1tv7 × .dot + .png + .svg
Architecture (5) arch1arch5 × .dot + .png + .svg
Topology (5) topo1topo5 × .dot + .png + .svg
Empirical (5) emp1emp5 × .dot + .png + .svg
Causality (5) cause1cause5 × .dot + .png + .svg
Future (5) future1future5 × .dot + .png + .svg
Total 32 diagrams × 3 formats = 96 diagram files

Generated 2026-05-29 on worlock (Linux 6.8.12). All artifact paths verified against live system. No fabricated CVEs. Intended for defensive security research and operator awareness.

About

OQS SSL provider threat vector analysis — 7 attack vectors, 32 diagrams, grounded in a real Linux crash incident (worlock, May 2026)

Topics

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors