Skip to content

Commit 16a1b65

Browse files
docs(protocol): update fido-u2f attestation (#575)
This updates the docs for attestation_u2f.go and renames it to attestation_fido_u2f.go.
1 parent fbb9a04 commit 16a1b65

2 files changed

Lines changed: 36 additions & 31 deletions

File tree

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,13 @@ import (
3030
//
3131
// See: https://www.w3.org/TR/webauthn/#sctn-fido-u2f-attestation
3232
func attestationFormatValidationHandlerFIDOU2F(att AttestationObject, clientDataHash []byte, _ metadata.Provider) (attestationType string, x5cs []any, err error) {
33+
// Non-normative verification procedure of expected requirement.
3334
if !bytes.Equal(att.AuthData.AttData.AAGUID, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) {
3435
return "", nil, ErrUnsupportedAlgorithm.WithDetails("U2F attestation format AAGUID not set to 0x00")
3536
}
3637

37-
// Signing procedure step - If the credential public key of the given credential is not of
38-
// algorithm -7 ("ES256"), stop and return an error.
38+
// Signing procedure. Non-normative verification procedure of expected requirement.
39+
// If the credential public key of the attested credential is not of algorithm -7 ("ES256"), stop and return an error.
3940
var key webauthncose.EC2PublicKeyData
4041
if err = webauthncbor.Unmarshal(att.AuthData.AttData.CredentialPublicKey, &key); err != nil {
4142
return "", nil, ErrAttestationCertificate.WithDetails("Error parsing public key").WithError(err)
@@ -51,36 +52,40 @@ func attestationFormatValidationHandlerFIDOU2F(att AttestationObject, clientData
5152
x5c []any
5253
ok bool
5354
)
54-
// U2F Step 1. Verify that attStmt is valid CBOR conforming to the syntax defined above
55-
// and perform CBOR decoding on it to extract the contained fields.
55+
56+
// Step 1. Verify that attStmt is valid CBOR conforming to the syntax defined above and perform CBOR decoding on it
57+
// to extract the contained fields.
5658

5759
// Check for "x5c" which is a single element array containing the attestation certificate in X.509 format.
5860
if x5c, ok = att.AttStatement[stmtX5C].([]any); !ok {
5961
return "", nil, ErrAttestationFormat.WithDetails("Missing properly formatted x5c data")
6062
}
6163

64+
// Note: Packed Attestation, FIDO U2F Attestation, and Assertion Signatures require ASN.1 DER sig values, but it is
65+
// RECOMMENDED that any new attestation formats defined not use ASN.1 encodings, but instead represent signatures as
66+
// equivalent fixed-length byte arrays without internal structure, using the same representations as used by COSE
67+
// signatures as defined in [RFC9053](https://www.rfc-editor.org/rfc/rfc9053.html) and
68+
// [RFC8230](https://www.rfc-editor.org/rfc/rfc8230.html).
69+
// This is described in §6.5.5 https://www.w3.org/TR/webauthn-3/#sctn-signature-attestation-types.
70+
6271
// Check for "sig" which is The attestation signature. The signature was calculated over the (raw) U2F
6372
// registration response message https://www.w3.org/TR/webauthn/#biblio-fido-u2f-message-formats]
6473
// received by the client from the authenticator.
6574
if sig, ok = att.AttStatement[stmtSignature].([]byte); !ok {
6675
return "", nil, ErrAttestationFormat.WithDetails("Missing sig data")
6776
}
6877

69-
// U2F Step 2. (1) Check that x5c has exactly one element and let attCert be that element. (2) Let certificate public
70-
// key be the public key conveyed by attCert. (3) If certificate public key is not an Elliptic Curve (EC) public
71-
// key over the P-256 curve, terminate this algorithm and return an appropriate error.
78+
// Step 2.
79+
// 1. Check that x5c has exactly one element and let attCert be that element.
80+
// 2. Let certificate public key be the public key conveyed by attCert.
81+
// 3. If certificate public key is not an Elliptic Curve (EC) public key over the P-256 curve, terminate this
82+
// algorithm and return an appropriate error.
7283

7384
// Step 2.1.
7485
if len(x5c) > 1 {
7586
return "", nil, ErrAttestationFormat.WithDetails("Received more than one element in x5c values")
7687
}
7788

78-
// Note: Packed Attestation, FIDO U2F Attestation, and Assertion Signatures support ASN.1,but it is recommended
79-
// that any new attestation formats defined not use ASN.1 encodings, but instead represent signatures as equivalent
80-
// fixed-length byte arrays without internal structure, using the same representations as used by COSE signatures
81-
// as defined in RFC8152 (https://www.w3.org/TR/webauthn/#biblio-rfc8152)
82-
// and RFC8230 (https://www.w3.org/TR/webauthn/#biblio-rfc8230).
83-
8489
// Step 2.2.
8590
if raw, ok = x5c[0].([]byte); !ok {
8691
return "", nil, ErrAttestationFormat.WithDetails("Error decoding ASN.1 data from x5c")
@@ -96,31 +101,27 @@ func attestationFormatValidationHandlerFIDOU2F(att AttestationObject, clientData
96101
return "", nil, ErrAttestationFormat.WithDetails("Attestation certificate public key algorithm is not ECDSA")
97102
}
98103

99-
ecdsaPub, ok := attCert.PublicKey.(*ecdsa.PublicKey)
100-
if !ok || ecdsaPub.Curve != elliptic.P256() {
101-
return "", nil, ErrAttestationFormat.WithDetails("Attestation certificate does not contain a P-256 ECDSA public key")
102-
}
103-
104104
// Step 3. Extract the claimed rpIdHash from authenticatorData, and the claimed credentialId and credentialPublicKey
105105
// from authenticatorData.attestedCredentialData.
106-
107106
rpIdHash := att.AuthData.RPIDHash
108-
109107
credentialID := att.AuthData.AttData.CredentialID
110108

111-
// The credentialPublicKey is handled earlier.
112-
113109
// Step 4. Convert the COSE_KEY formatted credentialPublicKey (see Section 7 of RFC8152 [https://www.w3.org/TR/webauthn/#biblio-rfc8152])
114110
// to Raw ANSI X9.62 public key format (see ALG_KEY_ECC_X962_RAW in Section 3.6.2 Public Key
115-
// Representation Formats of FIDO-Registry [https://www.w3.org/TR/webauthn/#biblio-fido-registry]).
111+
// Representation Formats of
112+
// [FIDO-Registry](https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-registry-v2.0-id-20180227.html#public-key-representation-formats)).
116113

117114
// Let x be the value corresponding to the "-2" key (representing x coordinate) in credentialPublicKey, and confirm
118-
// its size to be of 32 bytes. If size differs or "-2" key is not found, terminate this algorithm and
119-
// return an appropriate error.
115+
// its size to be of 32 bytes. If size differs or "-2" key is not found, terminate this algorithm and return an
116+
// appropriate error.
120117

121118
// Let y be the value corresponding to the "-3" key (representing y coordinate) in credentialPublicKey, and confirm
122-
// its size to be of 32 bytes. If size differs or "-3" key is not found, terminate this algorithm and
123-
// return an appropriate error.
119+
// its size to be of 32 bytes. If size differs or "-3" key is not found, terminate this algorithm and return an
120+
// appropriate error.
121+
credentialPublicKey, ok := attCert.PublicKey.(*ecdsa.PublicKey)
122+
if !ok || credentialPublicKey.Curve != elliptic.P256() {
123+
return "", nil, ErrAttestationFormat.WithDetails("Attestation certificate does not contain a P-256 ECDSA public key")
124+
}
124125

125126
if len(key.XCoord) > 32 || len(key.YCoord) > 32 {
126127
return "", nil, ErrAttestation.WithDetails("X or Y Coordinate for key is invalid length")
@@ -132,20 +133,24 @@ func attestationFormatValidationHandlerFIDOU2F(att AttestationObject, clientData
132133
publicKeyU2F.Write(key.YCoord)
133134

134135
// Step 5. Let verificationData be the concatenation of (0x00 || rpIdHash || clientDataHash || credentialId || publicKeyU2F)
135-
// (see §4.3 of FIDO-U2F-Message-Formats [https://www.w3.org/TR/webauthn/#biblio-fido-u2f-message-formats]).
136-
136+
// (see Section 4.3 of [FIDO-U2F-Message-Formats](https://fidoalliance.org/specs/fido-u2f-v1.1-id-20160915/fido-u2f-raw-message-formats-v1.1-id-20160915.html#registration-response-message-success)).
137137
verificationData := bytes.NewBuffer([]byte{0x00})
138138
verificationData.Write(rpIdHash)
139139
verificationData.Write(clientDataHash)
140140
verificationData.Write(credentialID)
141141
verificationData.Write(publicKeyU2F.Bytes())
142142

143-
// Step 6. Verify the sig using verificationData and certificate public key per SEC1[https://www.w3.org/TR/webauthn/#biblio-sec1].
143+
// Step 6. Verify the sig using verificationData and the certificate public key per section 4.1.4 of [SEC1] with
144+
// SHA-256 as the hash function used in step two.
144145
if err = attCert.CheckSignature(x509.ECDSAWithSHA256, verificationData.Bytes(), sig); err != nil {
145146
return "", nil, err
146147
}
147148

148-
// Step 7. If successful, return attestation type Basic with the attestation trust path set to x5c.
149+
// TODO: Step 7. Optionally, inspect x5c and consult externally provided knowledge to determine whether attStmt
150+
// conveys a Basic or AttCA attestation.
151+
152+
// Step 8. If successful, return implementation-specific values representing attestation type Basic, AttCA or
153+
// uncertainty, and attestation trust path x5c.
149154
return string(metadata.BasicFull), x5c, nil
150155
}
151156

0 commit comments

Comments
 (0)