Summary
On Windows 11 Hello (platform authenticator) with direct attestation (fmt: "tpm"), Wax raises:
(Wax.AttestationVerificationError) Failed to verify attestation of type tpm (reason: invalid_pub_area)
Root cause: in the ECC branch of parse_pub_area/1, the code reads an extra 2-byte length before the ECC point coordinates (x, y). That extra length does not exist in the TPM’s TPMT_PUBLIC encoding for ECC, so valid pubArea values (like Windows Hello’s) fail to parse. You can verify this with the pubArea key I got back in the parsed response below.
Parsed attestationObject (x5c data for brevity)
{
"fmt": "tpm",
"attStmt": {
"alg": "RS1 (-65535)",
"sig": "KZdEuRgthOo7pRTE0k4IwZB76_lIEi0hrel8ifLazDC7caHzm7tXeErovFhbuF086F33zlOzyneI9x74SK27pXBciwDImXq_-FfU5yIYhkYNHVVk7KHfNYGlN_xqbWbnCvy-Jt66RBSMNTCOfqmG62SwyzjP4Gc-ckoSv1kzJTR1FTK_-pUvGrnZSqVys1nWyUpPG5_UXqdOyLRImHwaASbKu26Ce4zkWfp1v7lKo-5Wh0PhihZCxWqsi2ZW4S2v-SgpdiYFgRQHmfblK9sHJbYoPJ3VsCkDxKZwRuWHSn1GklyBZe1V0vyX4FJgMQF4yS6tnSfjsHAecK2YQlMjTw",
"x5c": [],
"ver": "2.0",
"certInfo": "_1RDR4AXACIAC86eZELTxXtiaYmxvCMg1tnI_xPpQRccdPWPy_GD35XlABQQQTmX2bXpT6ZbF81SI5KvwYbDCAAAAAAx7b2KLGE1DWdjq-8BikYVrwyQfwQAIgALBecDy19UewMVshMFfdDIQoSfm3XuSXDGRMBXosm1OqoAIgALQ9haTPfwkEvFJLFi3rA2QKDaG21N4D4ce3aGfveWmeo",
"pubArea": "ACMACwAEAHIAIJ3_y_NsODrmmfuYaNxty4nXFTiEvigDkiwSQVi_rSKuABAAEAADABAAIB1OjbHkSpSgqpLtt9WvqRYQVtyAk7ke-hwPZ_LpPYbsACB4u-L3TI-64HtHRbz0upEldzwTrq6Th7AAII-0UizA0g"
},
"authData": {
"rpIdHash": "SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2M",
"flags": {
"userPresent": true,
"userVerified": true,
"backupEligible": false,
"backupStatus": false,
"attestedData": true,
"extensionData": false
},
"counter": 0,
"aaguid": {
"raw": "08987058-cadc-4b81-b6e1-30de50dcbe96",
"name": "Windows Hello"
},
"credentialID": "GbzVebwHup3tafa6l3zWvcJK5Mqrh113-0Du8jJtGFE",
"credentialPublicKey": "pQECAyYgASFYIB1OjbHkSpSgqpLtt9WvqRYQVtyAk7ke-hwPZ_LpPYbsIlggeLvi90yPuuB7R0W89LqRJXc8E66uk4ewACCPtFIswNI",
"parsedCredentialPublicKey": {
"keyType": "EC2 (2)",
"algorithm": "ES256 (-7)",
"curve": 1,
"x": "HU6NseRKlKCqku231a-pFhBW3ICTuR76HA9n8uk9huw",
"y": "eLvi90yPuuB7R0W89LqRJXc8E66uk4ewACCPtFIswNI"
}
}
}
Problem in the code (exact line)
File: lib/wax/attestation_statement_format/tpm.ex
The ECC clause of parse_pub_area/1 currently reads a stray length named _unique_length before the X coordinate:
defp parse_pub_area(<<
@tpm_alg_ecc::unsigned-big-integer-size(16),
name_alg::unsigned-big-integer-size(16),
_object_attributes::binary-size(4),
auth_policy_length::unsigned-big-integer-size(16),
_auth_policy::binary-size(auth_policy_length),
# symmetric
@tpm_alg_null::unsigned-big-integer-size(16),
_alg_ecc_scheme::unsigned-big-integer-size(16),
alg_ecc_curve_id::unsigned-big-integer-size(16),
# kdf
@tpm_alg_null::unsigned-big-integer-size(16),
_unique_length::unsigned-big-integer-size(16), # <-- ❌ stray length (should not be here)
unique_x_length::unsigned-big-integer-size(16),
unique_x::binary-size(unique_x_length),
unique_y_length::unsigned-big-integer-size(16),
unique_y::binary-size(unique_y_length)
>>) do
pub_area =
{:ok,
%{
type: :ecc,
name_alg: name_alg,
curve: to_erlang_curve(alg_ecc_curve_id),
x: unique_x,
y: unique_y
}}
pub_area
end
Why this is incorrect (short spec trail)
From the Trusted Platform Module Library Part 2: Structures (Version 184, published March 20, 2025)
Section 12.2.4 details the public area structure (TPMT_PUBLIC) via Table 219:
- Table 219: For the unique parameter, its type is
TPMU_PUBLIC_ID
- Table 212: In the case of the
ecc algorithm, the value of the TPMU_PUBLIC_ID is TPMS_ECC_POINT
- Table 197:
TPMS_ECC_POINT has two parameters: x and y. Each have the type TPM2B_ECC_PARAMETER
- Table 196:
TPM2B_ECC_PARAMETER has two parameters: size (16 bits) and buffer (bits based on size parameter)
- No further tables
I couldn't find a 16 bit length value before the x and y parameters. Though I did notice Table 198 for TPM2B_ECC_POINT does have an extra 16 bits beforehand, but it's not referenced by any other type (it's used several times in part 3 of the TPM spec). Maybe it was used by mistake here?
Summary
On Windows 11 Hello (platform authenticator) with direct attestation (
fmt: "tpm"), Wax raises:Root cause: in the ECC branch of
parse_pub_area/1, the code reads an extra 2-byte length before the ECC point coordinates(x, y). That extra length does not exist in the TPM’sTPMT_PUBLICencoding for ECC, so validpubAreavalues (like Windows Hello’s) fail to parse. You can verify this with thepubAreakey I got back in the parsed response below.Parsed attestationObject (x5c data for brevity)
{ "fmt": "tpm", "attStmt": { "alg": "RS1 (-65535)", "sig": "KZdEuRgthOo7pRTE0k4IwZB76_lIEi0hrel8ifLazDC7caHzm7tXeErovFhbuF086F33zlOzyneI9x74SK27pXBciwDImXq_-FfU5yIYhkYNHVVk7KHfNYGlN_xqbWbnCvy-Jt66RBSMNTCOfqmG62SwyzjP4Gc-ckoSv1kzJTR1FTK_-pUvGrnZSqVys1nWyUpPG5_UXqdOyLRImHwaASbKu26Ce4zkWfp1v7lKo-5Wh0PhihZCxWqsi2ZW4S2v-SgpdiYFgRQHmfblK9sHJbYoPJ3VsCkDxKZwRuWHSn1GklyBZe1V0vyX4FJgMQF4yS6tnSfjsHAecK2YQlMjTw", "x5c": [], "ver": "2.0", "certInfo": "_1RDR4AXACIAC86eZELTxXtiaYmxvCMg1tnI_xPpQRccdPWPy_GD35XlABQQQTmX2bXpT6ZbF81SI5KvwYbDCAAAAAAx7b2KLGE1DWdjq-8BikYVrwyQfwQAIgALBecDy19UewMVshMFfdDIQoSfm3XuSXDGRMBXosm1OqoAIgALQ9haTPfwkEvFJLFi3rA2QKDaG21N4D4ce3aGfveWmeo", "pubArea": "ACMACwAEAHIAIJ3_y_NsODrmmfuYaNxty4nXFTiEvigDkiwSQVi_rSKuABAAEAADABAAIB1OjbHkSpSgqpLtt9WvqRYQVtyAk7ke-hwPZ_LpPYbsACB4u-L3TI-64HtHRbz0upEldzwTrq6Th7AAII-0UizA0g" }, "authData": { "rpIdHash": "SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2M", "flags": { "userPresent": true, "userVerified": true, "backupEligible": false, "backupStatus": false, "attestedData": true, "extensionData": false }, "counter": 0, "aaguid": { "raw": "08987058-cadc-4b81-b6e1-30de50dcbe96", "name": "Windows Hello" }, "credentialID": "GbzVebwHup3tafa6l3zWvcJK5Mqrh113-0Du8jJtGFE", "credentialPublicKey": "pQECAyYgASFYIB1OjbHkSpSgqpLtt9WvqRYQVtyAk7ke-hwPZ_LpPYbsIlggeLvi90yPuuB7R0W89LqRJXc8E66uk4ewACCPtFIswNI", "parsedCredentialPublicKey": { "keyType": "EC2 (2)", "algorithm": "ES256 (-7)", "curve": 1, "x": "HU6NseRKlKCqku231a-pFhBW3ICTuR76HA9n8uk9huw", "y": "eLvi90yPuuB7R0W89LqRJXc8E66uk4ewACCPtFIswNI" } } }Problem in the code (exact line)
File:
lib/wax/attestation_statement_format/tpm.exThe ECC clause of
parse_pub_area/1currently reads a stray length named_unique_lengthbefore the X coordinate:Why this is incorrect (short spec trail)
From the Trusted Platform Module Library Part 2: Structures (Version 184, published March 20, 2025)
Section 12.2.4 details the public area structure (
TPMT_PUBLIC) via Table 219:TPMU_PUBLIC_IDeccalgorithm, the value of theTPMU_PUBLIC_IDisTPMS_ECC_POINTTPMS_ECC_POINThas two parameters:xandy. Each have the typeTPM2B_ECC_PARAMETERTPM2B_ECC_PARAMETERhas two parameters:size(16 bits) andbuffer(bits based onsizeparameter)I couldn't find a 16 bit length value before the
xandyparameters. Though I did notice Table 198 forTPM2B_ECC_POINTdoes have an extra 16 bits beforehand, but it's not referenced by any other type (it's used several times in part 3 of the TPM spec). Maybe it was used by mistake here?