Mutable Attestation or Measurement Reporting Data

Description

Mutable Attestation or Measurement Reporting Data occurs when attestation or measurement registers used in secure boot processes can be modified by adversaries, allowing them to spoof boot flow integrity measurements. During SoC secure/verified boot, systems calculate cryptographic hashes of code binaries and extend them sequentially. These final hash values—stored in registers for later attestation—can be read to detect tampering. The weakness occurs when these registers lack proper protections, enabling attackers to write arbitrary hash values and falsify boot integrity claims.

Risk

Mutable attestation data has severe security implications. Boot integrity can be spoofed. Measurement chains can be falsified. Attestation reports become unreliable. Malicious boot goes undetected. Trust verification is bypassed. Remote attestation is compromised. TPM-like guarantees are lost. Secure boot can be defeated.

Solution

Store measurement data in registers with read-only access protections. Ensure immutability against direct or indirect modification. Implement proper access controls preventing untrusted agent modification. Use extend-only operations for measurements. Lock measurement registers after boot completes. Verify measurement register protection in security audits.

Common Consequences

ImpactDetails
ConfidentialityScope: Confidentiality

Read Application Data - False attestation enables unauthorized access.
IntegrityScope: Integrity

Modify Memory - Measurement data can be falsified.
Access ControlScope: Access Control

Bypass Protection Mechanism - Attestation verification is bypassed.

Example Code

Vulnerable Code

// Vulnerable: Measurement registers without write protection

module vulnerable_measurement_engine (
    input wire clk,
    input wire reset_n,
    input wire [255:0] hash_input,
    input wire extend_command,
    input wire [7:0] pcr_select,
    input wire [255:0] direct_write_data,
    input wire direct_write_enable,
    input wire [3:0] requester_id,
    output reg [255:0] pcr_read_data,
    output reg measurement_done
);

    // Platform Configuration Registers (PCRs)
    reg [255:0] pcr [0:23];

    // VULNERABLE: PCRs can be directly written
    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            // Initialize PCRs to zero
            integer i;
            for (i = 0; i < 24; i = i + 1) begin
                pcr[i] <= 256'h0;
            end
            measurement_done <= 1'b0;
        end
        else begin
            measurement_done <= 1'b0;

            if (extend_command) begin
                // Normal extend operation: PCR = Hash(PCR || new_data)
                pcr[pcr_select] <= sha256({pcr[pcr_select], hash_input});
                measurement_done <= 1'b1;
            end

            // VULNERABLE: Direct write to PCRs allowed
            if (direct_write_enable) begin
                // Any requester can write arbitrary values!
                pcr[pcr_select] <= direct_write_data;

                // Attacker can:
                // 1. Set PCR to expected "good" value
                // 2. Hide malicious boot components
                // 3. Pass attestation with compromised system
            end
        end
    end

    // Read PCR value
    always @(*) begin
        pcr_read_data = pcr[pcr_select];
    end

endmodule

// Vulnerable: Attestation report from mutable source
module vulnerable_attestation (
    input wire clk,
    input wire reset_n,
    input wire generate_report,
    input wire [7:0] pcr_mask,
    output reg [2047:0] attestation_report,
    output reg report_valid
);

    // VULNERABLE: Measurement registers can be modified
    reg [255:0] measurements [0:7];

    // VULNERABLE: Anyone can update measurements
    input wire [255:0] measurement_update;
    input wire [2:0] measurement_select;
    input wire update_measurement;

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            report_valid <= 1'b0;
        end
        else begin
            // VULNERABLE: No access control on measurement updates
            if (update_measurement) begin
                measurements[measurement_select] <= measurement_update;
            end

            if (generate_report) begin
                // Generate report from mutable measurements
                // Report is untrustworthy!
                attestation_report <= {measurements[0], measurements[1],
                                       measurements[2], measurements[3],
                                       measurements[4], measurements[5],
                                       measurements[6], measurements[7]};
                report_valid <= 1'b1;
            end
        end
    end

endmodule
// Vulnerable: Software with mutable measurement storage

#include <stdint.h>

// VULNERABLE: Measurements stored in writable memory
static uint8_t pcr_values[24][32];  // In .bss - writable

// VULNERABLE: Direct PCR write function
void vulnerable_pcr_write(uint8_t pcr_index, const uint8_t* value) {
    // VULNERABLE: No access control
    // Any code can write arbitrary values to PCRs
    if (pcr_index < 24) {
        memcpy(pcr_values[pcr_index], value, 32);
    }
}

// VULNERABLE: Extend function that can be bypassed
void vulnerable_pcr_extend(uint8_t pcr_index, const uint8_t* data, size_t len) {
    if (pcr_index >= 24) return;

    // Normal extend: new_value = SHA256(old_value || data)
    uint8_t buffer[64];
    memcpy(buffer, pcr_values[pcr_index], 32);
    memcpy(buffer + 32, data, len > 32 ? 32 : len);

    sha256(buffer, 64, pcr_values[pcr_index]);

    // Problem: Attacker can call vulnerable_pcr_write() directly
    // to set PCR to any value, bypassing the extend chain
}

// VULNERABLE: Attestation using mutable PCRs
bool vulnerable_generate_attestation(uint8_t* report, size_t* report_len) {
    // Quote PCR values (which may have been tampered)
    for (int i = 0; i < 24; i++) {
        memcpy(report + i * 32, pcr_values[i], 32);
    }

    // Sign with attestation key
    sign_report(report, 24 * 32);

    *report_len = 24 * 32 + 64;  // PCRs + signature
    return true;

    // Report is signed but PCR values are untrustworthy
}

Fixed Code

// Fixed: Measurement registers with write protection

module secure_measurement_engine (
    input wire clk,
    input wire reset_n,
    input wire [255:0] hash_input,
    input wire extend_command,
    input wire [7:0] pcr_select,
    input wire [3:0] requester_id,
    input wire boot_complete,
    output reg [255:0] pcr_read_data,
    output reg measurement_done,
    output reg access_denied,
    output reg pcrs_locked
);

    // Platform Configuration Registers (PCRs)
    reg [255:0] pcr [0:23];

    // FIXED: PCR lock status - once locked, cannot be modified
    reg [23:0] pcr_lock;

    // FIXED: Trusted requesters for different PCRs
    parameter SECURE_BOOT_ROM = 4'd0;
    parameter SECURE_BOOT_LOADER = 4'd1;
    parameter OS_KERNEL = 4'd2;

    // PCR assignments
    // PCR 0-3: Boot ROM measurements (ROM only)
    // PCR 4-7: Bootloader measurements (Bootloader only)
    // PCR 8-15: OS measurements (Kernel only)
    // PCR 16-23: Application measurements (various)

    function automatic is_pcr_writable;
        input [7:0] pcr_idx;
        input [3:0] requester;
        begin
            is_pcr_writable = 1'b0;

            // Check PCR range and requester
            if (pcr_idx < 4 && requester == SECURE_BOOT_ROM) begin
                is_pcr_writable = 1'b1;
            end
            else if (pcr_idx >= 4 && pcr_idx < 8 && requester == SECURE_BOOT_LOADER) begin
                is_pcr_writable = 1'b1;
            end
            else if (pcr_idx >= 8 && pcr_idx < 16 && requester == OS_KERNEL) begin
                is_pcr_writable = 1'b1;
            end
            // PCR 16-23 have more flexible policies
        end
    endfunction

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            integer i;
            for (i = 0; i < 24; i = i + 1) begin
                pcr[i] <= 256'h0;
            end
            pcr_lock <= 24'h0;
            measurement_done <= 1'b0;
            access_denied <= 1'b0;
            pcrs_locked <= 1'b0;
        end
        else begin
            measurement_done <= 1'b0;
            access_denied <= 1'b0;

            // FIXED: Lock PCRs after boot
            if (boot_complete) begin
                pcr_lock <= 24'hFFFFFF;  // Lock all PCRs
                pcrs_locked <= 1'b1;
            end

            if (extend_command) begin
                // FIXED: Check if PCR is locked
                if (pcr_lock[pcr_select]) begin
                    access_denied <= 1'b1;
                end
                // FIXED: Check requester authorization
                else if (!is_pcr_writable(pcr_select, requester_id)) begin
                    access_denied <= 1'b1;
                end
                else begin
                    // FIXED: Only extend operation - no direct write
                    pcr[pcr_select] <= sha256({pcr[pcr_select], hash_input});
                    measurement_done <= 1'b1;
                end
            end

            // FIXED: No direct write interface
            // PCRs can only be modified through extend operation
        end
    end

    // Read PCR value (always allowed)
    always @(*) begin
        pcr_read_data = pcr[pcr_select];
    end

endmodule

// Fixed: Secure attestation with protected measurements
module secure_attestation (
    input wire clk,
    input wire reset_n,
    input wire generate_report,
    input wire [23:0] pcr_mask,
    input wire [255:0] nonce,
    input wire [3:0] requester_id,
    output reg [2047:0] attestation_report,
    output reg report_valid,
    output reg report_signed
);

    // FIXED: Measurements from protected PCR engine
    wire [255:0] pcr_values [0:23];
    wire pcrs_locked;

    secure_measurement_engine pcr_engine (
        // ... connections ...
        .pcrs_locked(pcrs_locked)
    );

    // FIXED: Attestation key in hardware
    wire [255:0] attestation_private_key;  // From secure key storage

    // State machine for attestation
    reg [2:0] attest_state;
    parameter IDLE = 3'd0;
    parameter COLLECT = 3'd1;
    parameter HASH = 3'd2;
    parameter SIGN = 3'd3;
    parameter DONE = 3'd4;

    reg [7:0] pcr_index;
    reg [2047:0] report_buffer;

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            report_valid <= 1'b0;
            report_signed <= 1'b0;
            attest_state <= IDLE;
        end
        else begin
            case (attest_state)
                IDLE: begin
                    report_valid <= 1'b0;
                    report_signed <= 1'b0;

                    if (generate_report) begin
                        // FIXED: Only generate report if PCRs are locked
                        if (pcrs_locked) begin
                            attest_state <= COLLECT;
                            pcr_index <= 8'h0;
                            report_buffer <= {nonce, 1792'h0};  // Include nonce
                        end
                    end
                end

                COLLECT: begin
                    // FIXED: Collect PCR values from protected engine
                    if (pcr_mask[pcr_index]) begin
                        // Include this PCR in report
                        report_buffer <= {report_buffer, pcr_values[pcr_index]};
                    end

                    pcr_index <= pcr_index + 1;
                    if (pcr_index >= 23) begin
                        attest_state <= HASH;
                    end
                end

                HASH: begin
                    // Hash the report for signing
                    attest_state <= SIGN;
                end

                SIGN: begin
                    // FIXED: Sign with protected attestation key
                    // Signature proves report came from this device
                    attestation_report <= sign_ecdsa(report_buffer,
                                                     attestation_private_key);
                    report_signed <= 1'b1;
                    attest_state <= DONE;
                end

                DONE: begin
                    report_valid <= 1'b1;
                    attest_state <= IDLE;
                end
            endcase
        end
    end

endmodule
// Fixed: Software with protected measurement storage

#include <stdint.h>
#include <stdbool.h>

// FIXED: PCR operations go through hardware TPM-like module
#define TPM_PCR_EXTEND_REG 0x50001000
#define TPM_PCR_READ_REG   0x50001004
#define TPM_PCR_SELECT_REG 0x50001008
#define TPM_STATUS_REG     0x5000100C
#define TPM_PCR_LOCKED_BIT 0x01

// FIXED: PCRs are in hardware, software only has extend interface
static bool pcr_extend(uint8_t pcr_index, const uint8_t* data, size_t len) {
    volatile uint32_t* pcr_select = (volatile uint32_t*)TPM_PCR_SELECT_REG;
    volatile uint32_t* status = (volatile uint32_t*)TPM_STATUS_REG;
    volatile uint32_t* extend_reg = (volatile uint32_t*)TPM_PCR_EXTEND_REG;

    if (pcr_index >= 24) {
        return false;
    }

    // Check if PCRs are locked
    if (*status & TPM_PCR_LOCKED_BIT) {
        log_error("PCRs are locked");
        return false;
    }

    // Select PCR
    *pcr_select = pcr_index;

    // FIXED: Only extend operation available - no direct write
    // Hardware performs: PCR = SHA256(PCR || data)
    for (size_t i = 0; i < len; i += 4) {
        uint32_t word;
        memcpy(&word, data + i, 4);
        *extend_reg = word;
    }

    // Wait for operation to complete
    while (!(*status & TPM_EXTEND_COMPLETE_BIT)) {
        // Wait
    }

    return true;
}

// FIXED: Read PCR from hardware
static bool pcr_read(uint8_t pcr_index, uint8_t* value) {
    volatile uint32_t* pcr_select = (volatile uint32_t*)TPM_PCR_SELECT_REG;
    volatile uint32_t* read_reg = (volatile uint32_t*)TPM_PCR_READ_REG;

    if (pcr_index >= 24) {
        return false;
    }

    *pcr_select = pcr_index;

    // Read 32 bytes (256 bits)
    for (int i = 0; i < 8; i++) {
        uint32_t word = read_reg[i];
        memcpy(value + i * 4, &word, 4);
    }

    return true;
}

// FIXED: No direct PCR write function
// void pcr_write(...) - DOES NOT EXIST

// FIXED: Attestation using hardware-protected PCRs
bool secure_generate_attestation(const uint8_t* nonce, size_t nonce_len,
                                 uint8_t* report, size_t* report_len) {
    attestation_request_t req;
    attestation_response_t resp;

    // Build request with nonce (for freshness)
    memcpy(req.nonce, nonce, nonce_len);
    req.pcr_mask = 0x00FFFFFF;  // All 24 PCRs

    // FIXED: Request attestation from hardware TPM
    // Hardware reads PCRs and signs with protected key
    if (!tpm_generate_quote(&req, &resp)) {
        return false;
    }

    // FIXED: Verify signature came from this TPM
    if (!verify_quote_signature(&resp)) {
        log_error("Quote signature verification failed");
        return false;
    }

    memcpy(report, resp.quote, resp.quote_len);
    *report_len = resp.quote_len;

    return true;
}

// FIXED: Lock PCRs after boot
void finalize_measurements(void) {
    volatile uint32_t* tpm_ctrl = (volatile uint32_t*)TPM_CONTROL_REG;

    // Lock all PCRs - cannot be unlocked without reset
    *tpm_ctrl |= TPM_LOCK_PCRS;

    // Verify lock
    volatile uint32_t* status = (volatile uint32_t*)TPM_STATUS_REG;
    if (!(*status & TPM_PCR_LOCKED_BIT)) {
        log_error("Failed to lock PCRs");
        secure_halt();
    }
}

CVE Examples

Mutable attestation vulnerabilities have been found in TPM-like implementations where PCR registers could be directly written instead of only extended, allowing attackers to forge attestation reports.


  • CWE-284: Improper Access Control (parent)
  • CWE-1196: Security Flow Issues (category)
  • CWE-1282: Assumed-Immutable Data is Stored in Writable Memory (related)
  • CAPEC-680: Exploitation of Improperly Controlled Registers (attack pattern)

References

  1. MITRE Corporation. "CWE-1283: Mutable Attestation or Measurement Reporting Data." https://cwe.mitre.org/data/definitions/1283.html
  2. TCG. "TPM 2.0 Library Specification"
  3. Intel. "PCIe Device Measurement Requirements"