Skip to content

Chain of Custody

2.1 Blockchain Ledger Architecture

Abhavtech implements a private blockchain ledger specifically designed for digital evidence chain of custody. This blockchain provides tamper-proof, auditable records of all evidence handling from collection through legal proceedings.

2.1.1 Why Blockchain for Digital Evidence?

Traditional Chain of Custody Challenges:

Challenge Traditional Method Blockchain Solution
Evidence Tampering Paper logs, spreadsheets (easily modified) Immutable ledger with cryptographic verification
Timestamp Verification System clocks (can be manipulated) Distributed consensus with NTP validation
Custodian Tracking Manual signatures, access logs Automated digital signatures with public key infrastructure
Access Auditing Limited logging, often incomplete Complete audit trail with every read/write operation logged
Long-Term Integrity Re-hashing periodically, manual verification Continuous verification via blockchain consensus
Court Admissibility Dependent on witness testimony Self-validating cryptographic proof

Blockchain Benefits for Legal Proceedings:

  1. Immutability: Once evidence is recorded on the blockchain, it cannot be altered without detection
  2. Transparency: Complete audit trail visible to authorized parties (legal, auditors, court)
  3. Timestamp Proof: Distributed nodes provide consensus on exact time of evidence collection
  4. Non-Repudiation: Digital signatures prevent custodians from denying actions
  5. Automation: Reduces human error in chain of custody documentation

2.1.2 Blockchain Platform Selection

Technology Stack:

Component Technology Justification
Blockchain Framework Hyperledger Fabric 2.5 Enterprise-grade, permissioned blockchain; proven in legal/compliance use cases
Consensus Algorithm RAFT Crash fault tolerant; suitable for private networks; faster than Byzantine algorithms
Smart Contracts Chaincode (Go language) Define evidence lifecycle rules, automated custody transfers
Hash Algorithm SHA-256 NIST-approved, court-accepted standard for digital evidence
Timestamp Authority RFC 3161-compliant TSA Legally recognized timestamp service
Node Deployment 5 nodes (3 DCs + 2 cloud) Distributed consensus, DR capability

Blockchain Network Architecture:

┌─────────────────────────────────────────────────────────────────────────┐
│          ABHAVTECH BLOCKCHAIN EVIDENCE NETWORK TOPOLOGY                 │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  PEER NODES (Endorsing + Committing)                                   │
│  ────────────────────────────────────                                   │
│                                                                         │
│  ┌───────────────────┐     ┌───────────────────┐     ┌──────────────┐ │
│  │   NJ-DC-PEER01    │     │   LON-DC-PEER01   │     │ MUM-DC-PEER01│ │
│  │ ───────────────── │     │ ───────────────── │     │ ────────────│  │
│  │ • Primary orderer │     │ • Secondary node  │     │ • Tertiary   │  │
│  │ • Ledger storage  │     │ • Ledger replica  │     │ • Ledger     │  │
│  │ • Chaincode exec  │     │ • DR capability   │     │ • APAC node  │  │
│  │ • Certificate CA  │     │ • Certificate CA  │     │ • Cert CA    │  │
│  └─────────┬─────────┘     └─────────┬─────────┘     └──────┬───────┘ │
│            │                         │                      │         │
│            └─────────────┬───────────┴──────────────────────┘         │
│                          │ Gossip Protocol (State Sync)               │
│                          │                                            │
│  CLOUD WITNESS NODES (Validation Only)                                │
│  ──────────────────────────────────────                                │
│                          │                                            │
│            ┌─────────────┴───────────┐                                │
│            │                         │                                │
│  ┌─────────▼─────────┐     ┌─────────▼─────────┐                     │
│  │   AWS-WITNESS01   │     │   AZURE-WITNESS01 │                     │
│  │ ───────────────── │     │ ───────────────── │                     │
│  │ • Read-only       │     │ • Read-only       │                     │
│  │ • No chaincode    │     │ • No chaincode    │                     │
│  │ • Ledger copy     │     │ • Ledger copy     │                     │
│  │ • External audit  │     │ • External audit  │                     │
│  └───────────────────┘     └───────────────────┘                     │
│                                                                         │
│  CLIENT APPLICATIONS                                                   │
│  ────────────────────                                                   │
│                                                                         │
│  ┌──────────────────┐     ┌──────────────────┐     ┌────────────────┐│
│  │ Forensics        │     │ Legal Portal     │     │ Audit Console  ││
│  │ Workstation      │────▶│ (Read-Only)      │────▶│ (Read-Only)    ││
│  │ (Write Access)   │     │ (Hash Verify)    │     │ (Chain Verify) ││
│  └──────────────────┘     └──────────────────┘     └────────────────┘│
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

Node Specifications:

Node Location Role CPU RAM Storage OS
NJ-DC-PEER01 New Jersey DC Primary Peer + Orderer 8 vCPU 32 GB 2 TB SSD Ubuntu 22.04 LTS
LON-DC-PEER01 London DC Secondary Peer 8 vCPU 32 GB 2 TB SSD Ubuntu 22.04 LTS
MUM-DC-PEER01 Mumbai DC Tertiary Peer 8 vCPU 32 GB 2 TB SSD Ubuntu 22.04 LTS
AWS-WITNESS01 AWS us-east-1 Witness Node (Cloud) 4 vCPU 16 GB 1 TB SSD Ubuntu 22.04 LTS
AZURE-WITNESS01 Azure East US Witness Node (Cloud) 4 vCPU 16 GB 1 TB SSD Ubuntu 22.04 LTS

2.1.3 Evidence Blockchain Schema

Block Structure:

{
  "block_number": 12345,
  "timestamp": "2026-01-18T14:45:22.123Z",
  "previous_block_hash": "a1b2c3d4e5f6...",
  "merkle_root": "f6e5d4c3b2a1...",
  "transactions": [
    {
      "tx_id": "EVIDENCE-2026-001-00012",
      "tx_type": "evidence_collection",
      "timestamp": "2026-01-18T14:45:22.000Z",
      "payload": {
        "evidence_id": "EVD-20260118-001",
        "case_id": "CASE-2026-001",
        "investigation_type": "malware_c2",
        "evidence_type": "pcap",
        "file_name": "mumbai-border-span-20260118-1445.pcap",
        "file_size_bytes": 2847392847,
        "sha256_hash": "8f7e6d5c4b3a2918f7e6d5c4b3a2918f7e6d5c4b3a2918f7e6d5c4b3a2918f7e",
        "collector": "forensics-ws01.abhavtech.com",
        "custodian": "SOC-Analyst-Rajesh-Kumar",
        "custodian_pubkey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...",
        "collection_location": "Mumbai-DC-Forensics-Lab",
        "source_platform": "Catalyst-C9500-Border-01",
        "source_ip": "10.252.1.1",
        "legal_hold": false,
        "retention_days": 365,
        "access_list": ["SOC-Team", "Legal-Team", "Audit-Team"]
      },
      "digital_signature": "MEUCIQDx1...",
      "signature_algorithm": "ECDSA-SHA256"
    }
  ],
  "block_hash": "9a8b7c6d5e4f...",
  "validator_signatures": [
    {"node": "NJ-DC-PEER01", "signature": "MEYCIQCx..."},
    {"node": "LON-DC-PEER01", "signature": "MEUCIQD1..."},
    {"node": "MUM-DC-PEER01", "signature": "MEQCIBx..."}
  ]
}

Transaction Types:

Transaction Type Description Trigger Required Fields
evidence_collection Initial evidence capture Evidence collected from network/platform evidence_id, file_name, sha256_hash, custodian
evidence_transfer Custody change Evidence transferred between custodians evidence_id, from_custodian, to_custodian, transfer_reason
evidence_access Read access logged User views/downloads evidence evidence_id, accessor, access_type (view/download)
evidence_analysis Analysis performed Forensics tool processes evidence evidence_id, tool_name, analysis_type, findings_hash
evidence_modification Evidence altered (with justification) Rare - requires approval evidence_id, modification_type, justification, approver
legal_hold_enable Legal hold activated Court order, subpoena, litigation evidence_id, hold_reason, court_case_number, expiration_date
legal_hold_release Legal hold removed Case closed, settlement evidence_id, release_reason, approver
evidence_destruction Evidence deleted (post-retention) Retention period expired evidence_id, destruction_method, approver

2.1.4 Chaincode (Smart Contract) Logic

Evidence Lifecycle Chaincode:

package main

import (
    "crypto/sha256"
    "encoding/json"
    "fmt"
    "time"

    "github.com/hyperledger/fabric-contract-api-go/contractapi"
)

// EvidenceContract defines smart contract for evidence lifecycle
type EvidenceContract struct {
    contractapi.Contract
}

// Evidence represents digital evidence structure
type Evidence struct {
    EvidenceID       string    `json:"evidence_id"`
    CaseID           string    `json:"case_id"`
    EvidenceType     string    `json:"evidence_type"`
    FileName         string    `json:"file_name"`
    FileSizeBytes    int64     `json:"file_size_bytes"`
    SHA256Hash       string    `json:"sha256_hash"`
    Collector        string    `json:"collector"`
    Custodian        string    `json:"custodian"`
    CollectionTime   time.Time `json:"collection_time"`
    SourcePlatform   string    `json:"source_platform"`
    LegalHold        bool      `json:"legal_hold"`
    RetentionDays    int       `json:"retention_days"`
    AccessList       []string  `json:"access_list"`
    TransferHistory  []Transfer `json:"transfer_history"`
    AccessLog        []Access  `json:"access_log"`
}

// Transfer represents custody transfer
type Transfer struct {
    Timestamp     time.Time `json:"timestamp"`
    FromCustodian string    `json:"from_custodian"`
    ToCustodian   string    `json:"to_custodian"`
    Reason        string    `json:"reason"`
    Approver      string    `json:"approver"`
}

// Access represents evidence access event
type Access struct {
    Timestamp   time.Time `json:"timestamp"`
    Accessor    string    `json:"accessor"`
    AccessType  string    `json:"access_type"` // view, download, analyze
    Purpose     string    `json:"purpose"`
}

// CollectEvidence - Initial evidence collection transaction
func (ec *EvidenceContract) CollectEvidence(ctx contractapi.TransactionContextInterface,
    evidenceID string, caseID string, evidenceType string, fileName string,
    fileSizeBytes int64, sha256Hash string, collector string, custodian string,
    sourcePlatform string, retentionDays int, accessListJSON string) error {

    // Verify evidence doesn't already exist
    existing, err := ctx.GetStub().GetState(evidenceID)
    if err != nil {
        return fmt.Errorf("failed to read from world state: %v", err)
    }
    if existing != nil {
        return fmt.Errorf("evidence %s already exists", evidenceID)
    }

    // Verify SHA-256 hash format (64 hex characters)
    if len(sha256Hash) != 64 {
        return fmt.Errorf("invalid SHA-256 hash length")
    }

    // Parse access list
    var accessList []string
    err = json.Unmarshal([]byte(accessListJSON), &accessList)
    if err != nil {
        return fmt.Errorf("invalid access list JSON: %v", err)
    }

    // Create evidence record
    evidence := Evidence{
        EvidenceID:      evidenceID,
        CaseID:          caseID,
        EvidenceType:    evidenceType,
        FileName:        fileName,
        FileSizeBytes:   fileSizeBytes,
        SHA256Hash:      sha256Hash,
        Collector:       collector,
        Custodian:       custodian,
        CollectionTime:  time.Now(),
        SourcePlatform:  sourcePlatform,
        LegalHold:       false,
        RetentionDays:   retentionDays,
        AccessList:      accessList,
        TransferHistory: []Transfer{},
        AccessLog:       []Access{},
    }

    // Write to ledger
    evidenceJSON, err := json.Marshal(evidence)
    if err != nil {
        return err
    }

    return ctx.GetStub().PutState(evidenceID, evidenceJSON)
}

// TransferCustody - Transfer evidence to new custodian
func (ec *EvidenceContract) TransferCustody(ctx contractapi.TransactionContextInterface,
    evidenceID string, newCustodian string, reason string, approver string) error {

    // Retrieve evidence
    evidenceJSON, err := ctx.GetStub().GetState(evidenceID)
    if err != nil {
        return fmt.Errorf("failed to read evidence: %v", err)
    }
    if evidenceJSON == nil {
        return fmt.Errorf("evidence %s does not exist", evidenceID)
    }

    var evidence Evidence
    err = json.Unmarshal(evidenceJSON, &evidence)
    if err != nil {
        return err
    }

    // Create transfer record
    transfer := Transfer{
        Timestamp:     time.Now(),
        FromCustodian: evidence.Custodian,
        ToCustodian:   newCustodian,
        Reason:        reason,
        Approver:      approver,
    }

    // Update evidence
    evidence.TransferHistory = append(evidence.TransferHistory, transfer)
    evidence.Custodian = newCustodian

    // Write back to ledger
    updatedJSON, err := json.Marshal(evidence)
    if err != nil {
        return err
    }

    return ctx.GetStub().PutState(evidenceID, updatedJSON)
}

// LogAccess - Log evidence access (read, download, analyze)
func (ec *EvidenceContract) LogAccess(ctx contractapi.TransactionContextInterface,
    evidenceID string, accessor string, accessType string, purpose string) error {

    // Retrieve evidence
    evidenceJSON, err := ctx.GetStub().GetState(evidenceID)
    if err != nil {
        return fmt.Errorf("failed to read evidence: %v", err)
    }
    if evidenceJSON == nil {
        return fmt.Errorf("evidence %s does not exist", evidenceID)
    }

    var evidence Evidence
    err = json.Unmarshal(evidenceJSON, &evidence)
    if err != nil {
        return err
    }

    // Verify accessor is in access list
    authorized := false
    for _, allowedUser := range evidence.AccessList {
        if accessor == allowedUser {
            authorized = true
            break
        }
    }
    if !authorized {
        return fmt.Errorf("accessor %s not authorized for evidence %s", accessor, evidenceID)
    }

    // Create access record
    access := Access{
        Timestamp:  time.Now(),
        Accessor:   accessor,
        AccessType: accessType,
        Purpose:    purpose,
    }

    // Update evidence
    evidence.AccessLog = append(evidence.AccessLog, access)

    // Write back to ledger
    updatedJSON, err := json.Marshal(evidence)
    if err != nil {
        return err
    }

    return ctx.GetStub().PutState(evidenceID, updatedJSON)
}

// EnableLegalHold - Activate legal hold on evidence
func (ec *EvidenceContract) EnableLegalHold(ctx contractapi.TransactionContextInterface,
    evidenceID string, courtCaseNumber string, approver string) error {

    // Retrieve evidence
    evidenceJSON, err := ctx.GetStub().GetState(evidenceID)
    if err != nil {
        return fmt.Errorf("failed to read evidence: %v", err)
    }
    if evidenceJSON == nil {
        return fmt.Errorf("evidence %s does not exist", evidenceID)
    }

    var evidence Evidence
    err = json.Unmarshal(evidenceJSON, &evidence)
    if err != nil {
        return err
    }

    // Enable legal hold
    evidence.LegalHold = true
    evidence.RetentionDays = -1 // Indefinite retention

    // Log action
    access := Access{
        Timestamp:  time.Now(),
        Accessor:   approver,
        AccessType: "legal_hold_enable",
        Purpose:    fmt.Sprintf("Court Case: %s", courtCaseNumber),
    }
    evidence.AccessLog = append(evidence.AccessLog, access)

    // Write back to ledger
    updatedJSON, err := json.Marshal(evidence)
    if err != nil {
        return err
    }

    return ctx.GetStub().PutState(evidenceID, updatedJSON)
}

// VerifyIntegrity - Verify evidence hash matches blockchain record
func (ec *EvidenceContract) VerifyIntegrity(ctx contractapi.TransactionContextInterface,
    evidenceID string, providedHash string) (bool, error) {

    // Retrieve evidence
    evidenceJSON, err := ctx.GetStub().GetState(evidenceID)
    if err != nil {
        return false, fmt.Errorf("failed to read evidence: %v", err)
    }
    if evidenceJSON == nil {
        return false, fmt.Errorf("evidence %s does not exist", evidenceID)
    }

    var evidence Evidence
    err = json.Unmarshal(evidenceJSON, &evidence)
    if err != nil {
        return false, err
    }

    // Compare hashes
    return evidence.SHA256Hash == providedHash, nil
}

// QueryEvidence - Retrieve complete evidence record
func (ec *EvidenceContract) QueryEvidence(ctx contractapi.TransactionContextInterface,
    evidenceID string) (*Evidence, error) {

    evidenceJSON, err := ctx.GetStub().GetState(evidenceID)
    if err != nil {
        return nil, fmt.Errorf("failed to read evidence: %v", err)
    }
    if evidenceJSON == nil {
        return nil, fmt.Errorf("evidence %s does not exist", evidenceID)
    }

    var evidence Evidence
    err = json.Unmarshal(evidenceJSON, &evidence)
    if err != nil {
        return nil, err
    }

    return &evidence, nil
}

func main() {
    chaincode, err := contractapi.NewChaincode(new(EvidenceContract))
    if err != nil {
        fmt.Printf("Error creating evidence chaincode: %s", err.Error())
        return
    }

    if err := chaincode.Start(); err != nil {
        fmt.Printf("Error starting evidence chaincode: %s", err.Error())
    }
}

2.1.5 Evidence Collection with Blockchain Integration

Automated Evidence Collection Script:

#!/usr/bin/env python3
"""
Forensics Evidence Collection with Blockchain Integration
Abhavtech Security Operations
"""

import hashlib
import json
import subprocess
import requests
from datetime import datetime
import os

# Blockchain Fabric SDK connection
from hfc.fabric import Client

class BlockchainEvidenceCollector:
    def __init__(self, case_id, investigation_type):
        self.case_id = case_id
        self.investigation_type = investigation_type
        self.evidence_vault = "/mnt/evidence_vault"
        self.blockchain_client = Client(net_profile="network-profile.json")

    def collect_pcap(self, interface, duration_seconds, description):
        """
        Collect packet capture and register on blockchain
        """
        timestamp = datetime.utcnow().strftime("%Y%m%d-%H%M%S")
        evidence_id = f"EVD-{timestamp}-PCAP"
        filename = f"{self.evidence_vault}/{evidence_id}.pcap"

        print(f"[+] Collecting PCAP from {interface} for {duration_seconds} seconds...")

        # Capture packets using tcpdump
        cmd = [
            "tcpdump",
            "-i", interface,
            "-w", filename,
            "-G", str(duration_seconds),
            "-W", "1"
        ]

        subprocess.run(cmd, check=True)

        # Calculate SHA-256 hash
        sha256_hash = self.calculate_hash(filename)
        file_size = os.path.getsize(filename)

        print(f"[+] PCAP captured: {filename}")
        print(f"[+] File size: {file_size} bytes")
        print(f"[+] SHA-256: {sha256_hash}")

        # Register on blockchain
        self.register_evidence_blockchain(
            evidence_id=evidence_id,
            evidence_type="pcap",
            filename=os.path.basename(filename),
            file_size=file_size,
            sha256_hash=sha256_hash,
            source_platform=description
        )

        return evidence_id, filename, sha256_hash

    def collect_logs_from_splunk(self, search_query, earliest, latest, description):
        """
        Export logs from Splunk and register on blockchain
        """
        timestamp = datetime.utcnow().strftime("%Y%m%d-%H%M%S")
        evidence_id = f"EVD-{timestamp}-SPLUNK"
        filename = f"{self.evidence_vault}/{evidence_id}.json"

        print(f"[+] Exporting logs from Splunk...")
        print(f"    Query: {search_query}")
        print(f"    Time range: {earliest} to {latest}")

        # Splunk REST API call
        splunk_url = "https://splunk.abhavtech.com:8089"
        splunk_user = "forensics-api"
        splunk_password = os.environ.get("SPLUNK_API_KEY")

        search_job = requests.post(
            f"{splunk_url}/services/search/jobs",
            auth=(splunk_user, splunk_password),
            verify=False,
            data={
                "search": f"search {search_query}",
                "earliest_time": earliest,
                "latest_time": latest,
                "output_mode": "json"
            }
        )

        job_sid = search_job.json()["sid"]

        # Poll for job completion
        while True:
            status = requests.get(
                f"{splunk_url}/services/search/jobs/{job_sid}",
                auth=(splunk_user, splunk_password),
                verify=False
            ).json()

            if status["entry"][0]["content"]["dispatchState"] == "DONE":
                break

        # Download results
        results = requests.get(
            f"{splunk_url}/services/search/jobs/{job_sid}/results",
            auth=(splunk_user, splunk_password),
            verify=False,
            params={"output_mode": "json"}
        )

        # Save to file
        with open(filename, 'w') as f:
            json.dump(results.json(), f, indent=2)

        # Calculate hash
        sha256_hash = self.calculate_hash(filename)
        file_size = os.path.getsize(filename)

        print(f"[+] Logs exported: {filename}")
        print(f"[+] Event count: {len(results.json()['results'])}")
        print(f"[+] SHA-256: {sha256_hash}")

        # Register on blockchain
        self.register_evidence_blockchain(
            evidence_id=evidence_id,
            evidence_type="splunk_export",
            filename=os.path.basename(filename),
            file_size=file_size,
            sha256_hash=sha256_hash,
            source_platform=description
        )

        return evidence_id, filename, sha256_hash

    def collect_dnac_timeline(self, issue_id, description):
        """
        Export DNAC Assurance timeline and register on blockchain
        """
        timestamp = datetime.utcnow().strftime("%Y%m%d-%H%M%S")
        evidence_id = f"EVD-{timestamp}-DNAC"
        filename = f"{self.evidence_vault}/{evidence_id}.json"

        print(f"[+] Exporting DNAC timeline for issue {issue_id}...")

        # DNAC REST API call
        dnac_url = "https://dnac.abhavtech.com"
        dnac_token = self.get_dnac_token()

        response = requests.get(
            f"{dnac_url}/dna/intent/api/v1/issues/{issue_id}",
            headers={"X-Auth-Token": dnac_token},
            verify=False
        )

        # Save to file
        with open(filename, 'w') as f:
            json.dump(response.json(), f, indent=2)

        # Calculate hash
        sha256_hash = self.calculate_hash(filename)
        file_size = os.path.getsize(filename)

        print(f"[+] DNAC timeline exported: {filename}")
        print(f"[+] SHA-256: {sha256_hash}")

        # Register on blockchain
        self.register_evidence_blockchain(
            evidence_id=evidence_id,
            evidence_type="dnac_timeline",
            filename=os.path.basename(filename),
            file_size=file_size,
            sha256_hash=sha256_hash,
            source_platform=description
        )

        return evidence_id, filename, sha256_hash

    def calculate_hash(self, filename):
        """
        Calculate SHA-256 hash of file
        """
        sha256 = hashlib.sha256()
        with open(filename, 'rb') as f:
            while True:
                data = f.read(65536)  # 64KB chunks
                if not data:
                    break
                sha256.update(data)
        return sha256.hexdigest()

    def register_evidence_blockchain(self, evidence_id, evidence_type, filename,
                                    file_size, sha256_hash, source_platform):
        """
        Register evidence on Hyperledger Fabric blockchain
        """
        print(f"[+] Registering evidence on blockchain...")

        # Prepare transaction
        access_list = ["SOC-Team", "Legal-Team", "Audit-Team"]

        # Invoke chaincode
        response = self.blockchain_client.chaincode_invoke(
            requestor='forensics-user',
            channel_name='evidence-channel',
            peer_names=['NJ-DC-PEER01'],
            args=[
                evidence_id,
                self.case_id,
                evidence_type,
                filename,
                str(file_size),
                sha256_hash,
                "forensics-ws01.abhavtech.com",
                "SOC-Analyst-" + os.environ.get("USER"),
                source_platform,
                "365",  # retention days
                json.dumps(access_list)
            ],
            cc_name='evidence-contract',
            fcn='CollectEvidence',
        )

        print(f"[+] Blockchain transaction ID: {response}")
        print(f"[+] Evidence {evidence_id} registered successfully")

    def get_dnac_token(self):
        """
        Authenticate to DNAC and get token
        """
        dnac_url = "https://dnac.abhavtech.com"
        dnac_user = os.environ.get("DNAC_USER")
        dnac_pass = os.environ.get("DNAC_PASS")

        response = requests.post(
            f"{dnac_url}/dna/system/api/v1/auth/token",
            auth=(dnac_user, dnac_pass),
            verify=False
        )

        return response.json()["Token"]

# Usage example
if __name__ == "__main__":
    collector = BlockchainEvidenceCollector(
        case_id="CASE-2026-001",
        investigation_type="malware_c2"
    )

    # Collect PCAP from border node
    collector.collect_pcap(
        interface="eth0",
        duration_seconds=300,
        description="Mumbai-Border-C9500-01"
    )

    # Export Splunk logs
    collector.collect_logs_from_splunk(
        search_query='index=firewall src_ip="10.252.80.45" earliest=-1h',
        earliest="-1h",
        latest="now",
        description="FTD-Mumbai-Firewall-Logs"
    )

    # Export DNAC timeline
    collector.collect_dnac_timeline(
        issue_id="AWcR...",
        description="DNAC-Client-Health-Issue"
    )

2.2 Blockchain Operations Procedures

2.2.1 Evidence Registration (Step-by-Step)

When to Register Evidence: - Immediately upon collection from any network platform - Before any analysis or manipulation - As part of automated collection scripts - Manual collection requires manual registration within 15 minutes

Registration Procedure:

# Step 1: Collect evidence (example: PCAP file)
sudo tcpdump -i eth0 -w /tmp/evidence.pcap -G 300 -W 1

# Step 2: Calculate SHA-256 hash
sha256sum /tmp/evidence.pcap > /tmp/evidence.pcap.sha256
# Output: 8f7e6d5c4b3a2918... evidence.pcap

# Step 3: Move to evidence vault
sudo mv /tmp/evidence.pcap /mnt/evidence_vault/EVD-20260118-001.pcap
sudo mv /tmp/evidence.pcap.sha256 /mnt/evidence_vault/EVD-20260118-001.pcap.sha256

# Step 4: Set immutable flag (ext4 filesystem)
sudo chattr +i /mnt/evidence_vault/EVD-20260118-001.pcap

# Step 5: Register on blockchain using Fabric CLI
peer chaincode invoke \
  -n evidence-contract \
  -C evidence-channel \
  -c '{"Args":["CollectEvidence",
      "EVD-20260118-001",
      "CASE-2026-001",
      "pcap",
      "EVD-20260118-001.pcap",
      "2847392847",
      "8f7e6d5c4b3a2918f7e6d5c4b3a2918f7e6d5c4b3a2918f7e6d5c4b3a2918f7e",
      "forensics-ws01.abhavtech.com",
      "SOC-Analyst-Rajesh-Kumar",
      "Mumbai-Border-C9500-01",
      "365",
      "[\"SOC-Team\",\"Legal-Team\",\"Audit-Team\"]"
    ]}'

# Step 6: Verify registration
peer chaincode query \
  -n evidence-contract \
  -C evidence-channel \
  -c '{"Args":["QueryEvidence","EVD-20260118-001"]}'

# Expected output: Full evidence record with blockchain timestamp

2.2.2 Evidence Integrity Verification

Verification Scenarios: - Before presenting evidence in court - Quarterly integrity audits - When evidence is transferred between custodians - Upon request from legal department

Verification Procedure:

# Step 1: Calculate current file hash
sha256sum /mnt/evidence_vault/EVD-20260118-001.pcap
# Output: 8f7e6d5c4b3a2918...

# Step 2: Query blockchain for original hash
peer chaincode query \
  -n evidence-contract \
  -C evidence-channel \
  -c '{"Args":["QueryEvidence","EVD-20260118-001"]}' \
  | jq '.sha256_hash'

# Step 3: Compare hashes (automated)
CURRENT_HASH=$(sha256sum /mnt/evidence_vault/EVD-20260118-001.pcap | awk '{print $1}')
BLOCKCHAIN_HASH=$(peer chaincode query -n evidence-contract -C evidence-channel \
  -c '{"Args":["QueryEvidence","EVD-20260118-001"]}' | jq -r '.sha256_hash')

if [ "$CURRENT_HASH" == "$BLOCKCHAIN_HASH" ]; then
  echo "✅ Evidence integrity VERIFIED"
  echo "   File has not been tampered since collection"
else
  echo "❌ Evidence integrity FAILED"
  echo "   File has been modified or corrupted"
  echo "   Current:    $CURRENT_HASH"
  echo "   Blockchain: $BLOCKCHAIN_HASH"
  # Alert security team
  /usr/local/bin/send-alert-to-secops.sh "Evidence tampering detected: EVD-20260118-001"
fi

# Step 4: Verify blockchain ledger consistency across nodes
for NODE in NJ-DC-PEER01 LON-DC-PEER01 MUM-DC-PEER01; do
  echo "Checking $NODE..."
  HASH=$(ssh $NODE "peer chaincode query -n evidence-contract -C evidence-channel \
    -c '{\"Args\":[\"QueryEvidence\",\"EVD-20260118-001\"]}' | jq -r '.sha256_hash'")
  echo "  Hash: $HASH"
done

# All nodes should return identical hashes

2.2.3 Chain of Custody Transfer

Transfer Scenarios: - SOC analyst transfers to senior investigator - Forensics team transfers to legal department - Legal department transfers to external auditor - Evidence returned from court

Transfer Procedure:

# Step 1: Verify current custodian (must match blockchain record)
CURRENT_CUSTODIAN=$(whoami)
echo "Current user: $CURRENT_CUSTODIAN"

# Step 2: Verify authorization to transfer
peer chaincode query \
  -n evidence-contract \
  -C evidence-channel \
  -c '{"Args":["QueryEvidence","EVD-20260118-001"]}' \
  | jq '.custodian'

# Expected: Should match $CURRENT_CUSTODIAN

# Step 3: Execute transfer on blockchain
peer chaincode invoke \
  -n evidence-contract \
  -C evidence-channel \
  -c '{"Args":["TransferCustody",
      "EVD-20260118-001",
      "Legal-Team-Sarah-Johnson",
      "Transfer to legal for case CASE-2026-001 court preparation",
      "SOC-Manager-Amit-Patel"
    ]}'

# Step 4: Physical/digital handoff
# - If physical media: Obtain signature on transfer form
# - If digital: Send encrypted link with transfer notification

# Step 5: New custodian verifies receipt
# (New custodian runs verification procedure from Section 2.2.2)

# Step 6: Log access by new custodian
peer chaincode invoke \
  -n evidence-contract \
  -C evidence-channel \
  -c '{"Args":["LogAccess",
      "EVD-20260118-001",
      "Legal-Team-Sarah-Johnson",
      "download",
      "Downloaded for case preparation"
    ]}'

Legal Hold Triggers: - Litigation initiated - Subpoena received - Regulatory investigation - Internal investigation escalation

Legal Hold Procedure:

# Step 1: Receive legal hold request (from Legal Department)
# Document court case number, matter name, scope

# Step 2: Activate legal hold on blockchain
peer chaincode invoke \
  -n evidence-contract \
  -C evidence-channel \
  -c '{"Args":["EnableLegalHold",
      "EVD-20260118-001",
      "CASE-2026-CA-12345",
      "Legal-Counsel-David-Lee"
    ]}'

# Step 3: Enable SnapLock Compliance on Evidence Vault
ssh storage-admin@netapp-nj-dc01 \
  "snaplock compliance-clock set EVD-20260118-001.pcap retention=indefinite"

# Step 4: Notify all relevant parties
cat << EOF | mail -s "Legal Hold Activated - EVD-20260118-001" \
  soc-team@abhavtech.com,legal-team@abhavtech.com
LEGAL HOLD NOTICE

Evidence ID: EVD-20260118-001
Court Case: CASE-2026-CA-12345
Activated by: Legal-Counsel-David-Lee
Date: $(date)

This evidence is now under legal hold. Do not delete, modify, or
destroy. Retention period: INDEFINITE until court case conclusion.

Blockchain transaction: $(peer chaincode query -n evidence-contract \
  -C evidence-channel -c '{"Args":["QueryEvidence","EVD-20260118-001"]}' \
  | jq -r '.access_log[-1].timestamp')

Contact legal@abhavtech.com for questions.
EOF

# Step 5: Quarterly verification while under legal hold
# (Automated cron job runs integrity checks monthly)

This completes Part 1. Shall I proceed with Part 2A: SD-WAN Forensics Scenarios next?