FDO Voucher Signature Verification and Domain Separation AAD Across Protocol Versions

This version:
https://fidoalliance.org/specs/fidoiot/fdo-appnote-8-voucher-aad-versioning-v1.0-20261001.html
Issue Tracking:
GitHub
Editor:
(Dell Technologies)
Version:
1.0

Abstract

FDO 2.0 introduces domain separation via COSE external Additional Authenticated Data (AAD) for all signing operations, including Ownership Voucher entry signatures and to1d signatures. FDO 1.x does not use AAD in any signing operations. When FDO 2.0 implementations encounter Ownership Vouchers that were created or extended by FDO 1.x systems, signature verification will fail if the verifier unconditionally applies FDO 2.0 AAD fields. This note explains the issue, its root cause, and the correct approach: inspecting the voucher’s OVProtVer field to determine whether AAD should be included during verification.

1. Introduction

FDO 2.0 introduces a significant security enhancement: domain separation for COSE_Sign1 signatures using the external_aad field (see RFC 9052 Section 4.3, "Externally Supplied Data"). Domain separation ensures that a signature produced for one protocol operation (e.g., TO0.OwnerSign) cannot be replayed as a valid signature for a different operation (e.g., TO2.ProveOVHdr), even if the same key is used for both.

This enhancement applies to all FDO 2.0 signing operations, including:

FDO 1.x (versions 1.0 and 1.1) does not use external_aad in any signing operation. All COSE_Sign1 signatures in FDO 1.x are produced and verified with an empty (nil) AAD value.

This difference creates an interoperability concern when FDO 2.0 implementations process Ownership Vouchers that were originally created or extended by FDO 1.x systems.

2. The Problem

In real-world deployments, it is common for Ownership Vouchers to be created and extended through multiple supply-chain entities over a period of time. Not all entities in the supply chain will upgrade to FDO 2.0 simultaneously. The following scenarios can arise:

In all of these cases, an FDO 2.0 verifier that unconditionally includes domain-specific AAD (e.g., the CBOR-encoded tag "FDO-OVEntry-v1" for OVEntry signatures, or "FDO-TO0-OwnerSign-v1" for to1d signatures) will fail to verify signatures that were originally produced with empty AAD under FDO 1.x.

The symptom is straightforward: COSE_Sign1 signature verification fails, even though the signatures are valid and the keys are correct. The root cause is a mismatch in the external_aad value used during signing (empty, under 1.x) versus verification (domain-tagged, under 2.0).

3. Background: COSE Domain Separation

COSE_Sign1 signatures (RFC 9052) incorporate an external_aad field into the Sig_structure that is hashed and signed. This field is not transmitted in the COSE_Sign1 output; both the signer and verifier must independently construct the same value based on the protocol context.

FDO 2.0 defines domain separation tags as CBOR-encoded arrays containing a domain string. For example:

FDOExternalAAD = [FDODomainTag]
FDODomainTag = tstr

; Example values:
AADOwnerSign   = FDOExternalAAD with tag "FDO-TO0-OwnerSign-v1"
AADOVEntry     = FDOExternalAAD with tag "FDO-OVEntry-v1"
AADProveToRV   = FDOExternalAAD with tag "FDO-TO1-ProveToRV-v1"
AADProveOVHdr  = FDOExternalAAD with tag "FDO-TO2-ProveOVHdr-v1"
AADProveDevice = FDOExternalAAD with tag "FDO-TO2-ProveDevice-v1"
AADSetupDevice = FDOExternalAAD with tag "FDO-TO2-SetupDevice-v1"

When external_aad is included, it becomes part of the data that is signed. If the verifier uses a different external_aad value than the signer used, the signature will not verify, even if the key and payload are identical.

4. The Correct Approach

The correct approach is to use the Ownership Voucher’s version field (OVProtVer) to determine whether domain-specific AAD should be applied during signature verification.

The Ownership Voucher structure includes a protocol version at the top level:

OwnershipVoucher = [
    OVProtVer:      protver,           ;; protocol version
    OVHeaderTag:    bstr .cbor OVHeader,
    OVHeaderHMac:   HMac,
    OVDevCertChain: OVDevCertChainOrNull,
    OVEntryArray:   OVEntries
]

The OVProtVer field records the protocol version under which the voucher was created. This field is set at Device Initialization (DI) and does not change as the voucher is extended through the supply chain.

4.1. Rule for Verification

When verifying Ownership Voucher entry signatures or to1d signatures:

In pseudocode:

if voucher.OVProtVer >= 200:
    aad = domain_specific_aad   // e.g., AADOVEntry or AADOwnerSign
else:
    aad = nil                   // empty AAD, as used by FDO 1.x

verify_cose_sign1(signature, key, aad)

This rule applies to:

4.2. Rule for Signing

When producing new signatures:

5. Why This is Non-Obvious

This issue is easy to overlook for several reasons:

  1. All endpoints may be running 2.0. An operator who has upgraded all systems to FDO 2.0 may reasonably expect everything to "just work." However, if existing Ownership Vouchers were created under 1.x, their embedded signatures use empty AAD. The protocol version running on the endpoints is irrelevant; what matters is the version recorded in the voucher.

  2. The failure mode is cryptographic. When AAD is mismatched, the error manifests as a signature verification failure. There is no clear indication that the root cause is an AAD mismatch rather than a corrupted voucher or wrong key.

  3. Domain separation is an "invisible" field. The external_aad value is not transmitted in the COSE_Sign1 structure. It is not visible in the voucher data itself. Both signer and verifier must independently agree on its value. When they disagree, there is no obvious diagnostic clue in the on-wire data.

  4. Mixed supply chains are common. In practice, Ownership Vouchers pass through many entities, and not all will upgrade on the same schedule. A voucher may have been created years before the Owner endpoint is upgraded.

6. Example Scenario

Consider the following timeline:

  1. In 2024, a device manufacturer running FDO 1.1 creates a batch of 1000 devices. Each device receives an Ownership Voucher with OVProtVer = 101. All voucher entry signatures are produced with empty AAD.

  2. The vouchers are extended through the supply chain by distributors also running FDO 1.1. Additional entries are signed with empty AAD.

  3. In 2025, the end-customer (Owner) upgrades their onboarding infrastructure to FDO 2.0.

  4. Devices begin arriving and attempting onboarding. During TO2, the Owner’s FDO 2.0 implementation verifies the Ownership Voucher.

  5. If the implementation naively applies AADOVEntry to all voucher entry verifications (because it is running FDO 2.0), every signature check will fail. The devices cannot onboard.

  6. The correct behavior is to inspect OVProtVer in each voucher. Since these vouchers have OVProtVer = 101, verification proceeds with empty AAD, and the signatures verify successfully.

7. Recommendations

8. Conclusion

Domain separation via COSE external_aad is a valuable security improvement in FDO 2.0. However, its introduction creates a backward compatibility concern for Ownership Vouchers produced under FDO 1.x. The key insight is that the voucher’s own version field (OVProtVer) -- not the running protocol version of the endpoints —​determines whether AAD should be applied during voucher signature operations. Implementations must inspect this field and apply AAD accordingly to ensure seamless interoperability across protocol versions.