Skip to content

Implement secure OpenTimestamp proof verification #412

Description

@kevalyq

🚨 Security Review: Implementation Reverted

After implementing the "hybrid approach" (PR #413), a critical security review by GitHub Copilot identified severe vulnerabilities that make the implementation cryptographically unsound.


Critical Security Flaws

1. Trivial Proof Forgery Attack

The implementation is vulnerable to attackers constructing fake proofs:

// An attacker can create a "valid" proof without any blockchain anchoring:
$fakeProof = "OpenTimestamps proof\0" 
           . hex2bin($arbitrary_digest) 
           . str_repeat("\0", 50)  // padding
           . "\x05\x88\x96\x0d\x73\xd7\x19\x01\x03";  // Bitcoin attestation magic bytes

// This fake proof would pass all checks in the hybrid implementation!

2. No Cryptographic Validation

  • extractCommitment() method blindly extracts first 32 bytes after header
  • NO operation tree parsing
  • NO SHA256 operation chain validation
  • NO cryptographic proof of linkage to digest

3. No Blockchain Verification

  • hasAttestation() only performs substring search for magic bytes
  • NO Bitcoin block height verification
  • NO Merkle proof validation against actual blockchain
  • NO cross-check with Bitcoin transaction data
  • Attestation bytes can be fabricated

4. Broken Security Model

  • Relies on heuristics (pattern matching) instead of cryptographic proofs
  • Does NOT provide tamper-evident guarantees
  • Does NOT ensure blockchain anchoring actually occurred
  • Violates fundamental security principle: never roll your own crypto

Impact Analysis

Aspect Status Notes
Audit trail integrity ❌ BROKEN Proofs can be forged
Legal admissibility ❌ INVALID Verification not cryptographically sound
BewachV § 21 Abs. 4 compliance ❌ FAILS Tamper-evidence not guaranteed
Bitcoin anchoring ✅ WORKS submit/upgrade methods are safe
Proof storage ✅ WORKS Proofs stored, can verify later

Decision: Revert to Fail-Closed

PR #413 has been updated with security revert:

verify() method now returns false (fail-closed)
✅ Comprehensive security documentation added
✅ All tests updated to expect false
✅ CHANGELOG moved entry to "Security" section

Rationale: Better to reject valid proofs than accept forged ones.


Correct Implementation Path

This issue remains OPEN and requires one of the following approaches:

✅ RECOMMENDED: Option B - External Verification Service

Delegate verification to vetted OTS implementation:

Approach 1: HTTP API

public function verify(string $proof, string $digest): bool
{
    // Use opentimestamps.org/verify API
    $response = Http::post('https://opentimestamps.org/verify', [
        'proof' => base64_encode($proof),
        'digest' => $digest,
    ]);
    
    return $response->json('verified') === true;
}

Approach 2: CLI Wrapper

public function verify(string $proof, string $digest): bool
{
    // Use opentimestamps-client CLI tool
    $process = new Process([
        'ots', 'verify', 
        '-f', $proofFile,
        '-d', $digest
    ]);
    
    return $process->run() === 0;
}

Approach 3: Python Library via Process

public function verify(string $proof, string $digest): bool
{
    // Use opentimestamps-python library
    $process = new Process([
        'python3', '-m', 'opentimestamps.core',
        'verify', $proofFile, $digest
    ]);
    
    return $process->run() === 0;
}

Advantages:

  • ✅ Cryptographically sound (uses official OTS library)
  • ✅ Maintained by OpenTimestamps experts
  • ✅ Includes full operation tree parsing
  • ✅ Blockchain verification included
  • ✅ Can cache verified proofs (result immutable)

⚠️ NOT RECOMMENDED: Option A - Pure PHP Implementation

Would require:

  • Full OTS proof format parser (operation tree traversal)
  • Cryptographic operation chain validator
  • Bitcoin blockchain API integration
  • Merkle proof validator
  • Extensive security testing

Why not recommended:

  • ❌ Extremely complex (high risk of subtle bugs)
  • ❌ Requires deep cryptography expertise
  • ❌ Difficult to audit/maintain
  • ❌ Violates "don't roll your own crypto"

Next Steps

  1. Create sub-issue for Option B implementation
  2. Evaluate external services:
    • opentimestamps.org API (rate limits?)
    • opentimestamps-client CLI (installation?)
    • opentimestamps-python (Python dependency?)
  3. Implement chosen approach with caching layer
  4. Test with real Bitcoin-anchored proofs
  5. Security audit of new implementation

Lessons Learned

  1. Security First: Always prioritize cryptographic soundness over convenience
  2. Expert Review: External security review caught critical flaws
  3. Fail Closed: When in doubt, reject (don't accept potentially forged proofs)
  4. Use Libraries: Delegate crypto to experts (don't implement yourself)
  5. Test Assumptions: "Passing tests" ≠ "secure implementation"

References


Status: ❌ Implementation REVERTED for security
Priority: 🔴 CRITICAL (blocks Level 3 audit trail)
Next: Create sub-issue for Option B implementation

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    ✅ Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions