1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-04-26 12:09:02 +00:00
trezor-firmware/docs/core/misc/optiga.md
2025-04-14 17:10:07 +02:00

10 KiB

Optiga data object configuration

The following table outlines the Optiga data object configuration used in Trezor Safe 3 and Trezor Safe 5.

OID Name Read Write Execute Type/Usage Size (bytes) Notes Storage version
E0E0 CERT_INF Always Never Always DEVCERT Infineon certificate.
E0E1 CERT_DEV Always Never Always DEVCERT Device certificate chain.
E0E2 CERT_FIDO Always Never Always DEVCERT FIDO attestation certificate.
E0E3 DEVCERT ≤ 1728 Unused public key certificate.
E0E8 TA ≤ 1200 Unused root CA public key certificate.
E0E9 TA ≤ 1200 Unused root CA public key certificate.
E0F0 KEY_DEV Never Never Conf(KEY_PAIRING) Sign NIST P-256 device private key.
E0F1 Unused private ECC key.
E0F2 KEY_FIDO Never Never Conf(KEY_PAIRING) Sign NIST P-256 FIDO attestation private key.
E0F3 PIN_ECDH Never Always Luc(PIN_TOTAL_CTR) KeyAgree NIST P-256 key for ECDH PIN stretching step. ≥ 3
E120 STRETCHED_PIN_CTR Always Auto(PIN_SECRET) Always UPCTR 8 Counter which limits the guesses at STRETCHED_PIN. Limit set to 16. ≥ 3
E121 PIN_TOTAL_CTR Always Never Always UPCTR 8 Counter which limits the total number of PIN stretching operations over the lifetime of the device. Limit set to 600000, meaning 150000 unlock attempts. ≥ 3
E122 PIN_HMAC_CTR Always Auto(STRETCHED_PIN) Always UPCTR 8 Counter which limits the use of PIN_HMAC. Limit set to 16. ≥ 5
E123 UPCTR 8 Unused monotonic counter.
E140 KEY_PAIRING Never Never Always PTFBIND 32 Shared platform binding secret.
E200 PIN_CMAC Never Always Luc(PIN_TOTAL_CTR) Enc 32 Key for AES-CMAC PIN stretching step. ≥ 3
F1D0 PIN_SECRET Auto(STRETCHED_PIN) Always Always AUTOREF 32 Counter-protected PIN secret and reset key for STRETCHED_PIN_CTR. ≥ 3
F1D1 PIN_HMAC_V4 Never Never Luc(PIN_TOTAL_CTR) PRESSEC 32 Deprecated key for HMAC-SHA256 PIN stretching step. 3, 4
F1D2 ≤ 140 Unused data object.
F1D3 ≤ 140 Unused data object.
F1D4 STRETCHED_PIN Never Auto(PIN_SECRET) Luc(STRETCHED_PIN_CTR) AUTOREF 32 Digest of the stretched PIN. ≥ 3
F1D5 ≤ 140 Unused data object.
F1D6 ≤ 140 Unused data object.
F1D7 ≤ 140 Unused data object.
F1D8 PIN_HMAC Never Auto(STRETCHED_PIN) Luc(PIN_HMAC_CTR) PRESSEC 32 Counter-protected key for HMAC-SHA256 PIN stretching step. ≥ 5
F1D9 ≤ 140 Unused data object.
F1DA ≤ 140 Unused data object.
F1DB ≤ 140 Unused data object.
F1E0 ≤ 1500 Unused data object.
F1E1 ≤ 1500 Unused data object.

Optiga PIN protection

The diagram below summarizes the main relationships between the data objects that play a role in PIN protection. An arrow from X to Y indicates that X authorizes the specified operation on Y.

  • If X is a monotonic counter, then the specified operation on Y is allowed only if the counter value is below the threshold. The operation causes X to be incremented.
  • If X is a secret, then the specified operation on Y is allowed only if the host MCU proves knowledge of the value stored in X.
  • If X is Always, then the specified operation is always allowed.
graph LR
Always -- Write --> PIN_SECRET
PIN_SECRET -- Write --> STRETCHED_PIN
PIN_SECRET -- Write --> STRETCHED_PIN_CTR
STRETCHED_PIN_CTR -- Execute --> STRETCHED_PIN
STRETCHED_PIN -- Read --> PIN_SECRET
STRETCHED_PIN -- Write --> PIN_HMAC_CTR
PIN_HMAC_CTR -- Execute --> PIN_HMAC
STRETCHED_PIN -- Write --> PIN_HMAC

Stretching pattern

The Optiga's role in PIN protection is to add a series of PIN stretching steps to the process of computing the storage key encryption key (KEK). All stretching operations are limited either by the global counter PIN_TOTAL_CTR or by one of the PIN attempt counters PIN_HMAC_CTR and STRETCHED_PIN_CTR. Each stretching step is wrapped in the following pattern:

digest = hmac_sha256(stretched_pin, "")
output = optiga_operation(..., digest)
stretched_pin = hmac_sha256(stretched_pin, output)

In this pattern, the stretched PIN is first processed using a one-way function before sending it to the Optiga. This ensures that in the unlikely case of an attacker recording communication between the MCU and Optiga or extracting the secret in STRETCHED_PIN, they will not gain knowledge of the stretched PIN, only its digest. Second, the digest is sent to the Optiga which uses it to generate an output. That output is then used to stretch the PIN. This method ensures that if the user chooses a high-entropy PIN or if at least one of the preceding stretching operations remains secure, then even if the communication link or the Optiga is completely compromised, possibly even malicious, it will not reduce the security of the Trezor any more than if the Optiga was not integrated into the Trezor in the first place.

Optiga stretching process

The following pseudocode outlines the process of stretching the PIN by Optiga.

optiga_pin_verify(stretched_pin):
    # Stretch the PIN with the secrets in PIN_CMAC and PIN_ECDH.
    PIN_STRETCH_ITERATIONS = 2
    for _ in range(PIN_STRETCH_ITERATIONS):
        # Stretch the PIN with PIN_CMAC and PIN_ECDH secrets in the Optiga.
        digest = hmac_sha256(stretched_pin, "")
        cmac_out = encrypt_sym(SYM_MODE_CMAC, PIN_CMAC, digest)
        point = hash_to_curve(digest)
        ecdh_out = calc_ssec(CURVE_P256, PIN_ECDH, point)
        stretched_pin = hmac_sha256(stretched_pin, cmac_out + ecdh_out)

    # Stretch the PIN with the secret in PIN_HMAC.
    digest = hmac_sha256(stretched_pin, "")
    hmac_buffer = encrypt_sym(SYM_MODE_HMAC_SHA256, PIN_HMAC, digest)
    stretched_pin = hmac_sha256(stretched_pin, hmac_buffer)

    # Authorise using STRETCHED_PIN so that we can read from PIN_SECRET and reset PIN_HMAC_CTR.
    digest = hmac_sha256(stretched_pin, "")
    if not set_auto_state(STRETCHED_PIN, digest):
        raise InvalidPinError
    pin_secret = get_data_object(PIN_SECRET)
    stretched_pin = hmac_sha256(stretched_pin, pin_secret)
    set_data_object(PIN_HMAC_CTR, COUNTER_RESET)

    # Authorise using PIN_SECRET so that we can reset STRETCHED_PIN_CTR.
    set_auto_state(PIN_SECRET, pin_secret)
    set_data_object(STRETCHED_PIN_CTR, COUNTER_RESET)

    return stretched_pin

The first step of the stretching process hardens the PIN protection in case a vulnerability is discovered that allows the extraction of the secret value of a data object in Optiga that has a particular configuration, but does not allow extraction for other kinds of data objects. An attacker would need to be able to extract each of the secrets in PIN_CMAC, PIN_ECDH, PIN_HMAC and PIN_SECRET to conduct an offline brute-force search for the PIN. Thus it reduces the number of PIN values that the attacker can test in a unit of time by forcing them to involve the Optiga in each attempt, and restricts the overall number of attempts using PIN_TOTAL_CTR.

The rest of the process makes use of the data objects that are depicted in the diagram. The configuration of these data objects is designed with the goal of making the system resettable under all circumstances, i.e. even if the previous PIN is forgotten, flash storage is wiped and counters are depleted. There are two PIN attempt counters STRETCHED_PIN_CTR and PIN_HMAC_CTR, which both have a limit of 16 attempts and have identical values under normal circumstances.

PIN_HMAC_CTR limits the number of possible PIN attempts, but together with PIN_HMAC it also serves to mitigate a so called PIN-only attack. Without this counter it would be possible to partially reset the system by overwriting PIN_SECRET and resetting STRETCHED_PIN_CTR to gain an unlimited number of attempts at checking for the correct PIN, but without the possibility to derive the correct storage key encryption key, since the PIN_SECRET is overwritten. This attack is dangerous in case a user has two devices with the same PIN, because one of the devices could be used to determine the correct PIN and the other could then be unlocked. Note that in order for the mitigation to be effective, write access to PIN_HMAC_CTR must be authorized by STRETCHED_PIN. This implies that the attacker cannot reset PIN_HMAC_CTR without first overwriting STRETCHED_PIN, thus ruining the ability of checking for the correct PIN.

STRETCHED_PIN_CTR also limits the number of possible PIN attempts. Its presence is actually not necessary, but serves as an additional countermeasure in case a vulnerability is discovered that allows an attacker to read data objects of type PRESSEC, specifically PIN_HMAC. In that case, the attacker would still be restricted by the STRETCHED_PIN_CTR in the number of PIN attempts they can make. After they depleted the counter, the worst they could do is overwrite PIN_SECRET to execute the aforementioned PIN-only attack.

PIN_SECRET and STRETCHED_PIN play an essential role in making the system resettable, yet secure. Since PIN_SECRET is used in the last PIN stretching step, there needs to be a data object that grants read access to PIN_SECRET, which is why STRETCHED_PIN is needed in the system. Anyone attempting to reset the system must first overwrite PIN_SECRET thus losing the value that is necessary to complete the PIN stretching. Suppose there was no PIN_SECRET in the system and the PIN, stretched by PIN_HMAC, was used directly as the storage key encryption key. Then STRETCHED_PIN would have to be writable always, and an attacker could rewrite STRETCHED_PIN, reset the PIN_HMAC_CTR, and gain an unlimited number of attempts to guess the PIN.