webauthn::WebAuthn method reg attestation_verify (public)

 <instance of webauthn::WebAuthn[i]> reg attestation_verify \
    [ -st st ] [ -req req ]

Defined in packages/webauthn/tcl/webauthn-procs.tcl

Switches:
-st (optional)
-req (optional)

Testcases:
No testcase defined.
Source code:
set return_url        [dict get $st return_url]
set user_id           [dict get $st user_id]

if {![dict exists $req response clientDataJSON]
    || ![dict exists $req response attestationObject]} {
    throw {validation fields-missing} "missing required fields"
}

# ---- clientDataJSON
:assert_clientdata_json  -clientData_raw      [dict get $req response clientDataJSON]  -expected_type       "webauthn.create"  -expected_challenge  [dict get $st challenge]  -expected_origin     [dict get $st origin]

# ---- attestationObject (CBOR) -> authData -> credId + COSE_Key
set attObj_b64u [dict get $req response attestationObject]
set attObj_bin [ns_base64urldecode -binary -- $attObj_b64u]

try {
    set ao [ns_cbor decode -binary -encoding binary $attObj_bin]
} on error {e} {
    throw {validation attobj-cbor} "bad attestationObject CBOR: $e"
}

if {![dict exists $ao fmt] || ![dict exists $ao authData]} {
    throw {validation attobj-invalid} "attestationObject missing fmt/authData"
}

set fmt [dict get $ao fmt]
if {$fmt ne "none"} {
    ns_log notice "registration attestation fmt=$fmt"
}

set authData [dict get $ao authData]
if {[string length $authData] < 55} {
    throw {validation authdata-invalid} "authData too short"
}

set rpIdHash [string range $authData 0 31]
:assert_rpidhash -rpIdHash $rpIdHash -rpId ${:rp_id} -context "attestation"

binary scan [string range $authData 32 32] cu flags
if {($flags & 0x40) == 0} {
    throw {validation attesteddata-missing} "no attested credential data"
}

binary scan [string range $authData 33 36] Iu signCount

# fixed offsets from WebAuthn authData layout
set aaguid [string range $authData 37 37+15]
binary scan [string range $authData 53 53+1] S credIdLen

if {$credIdLen <= 0 || (55+$credIdLen) > [string length $authData]} {
    throw {validation credidlen-invalid} "credentialId length out of range"
}

set credId  [string range $authData 55 54+$credIdLen]
set coseKey [string range $authData 55+$credIdLen end]

try {
    set cose [ns_cbor decode -binary -encoding binary $coseKey]
} on error {e} {
    throw {validation cose-cbor} "bad COSE_Key CBOR: $e"
}

# Basic COSE sanity (ES256 / P-256)
if {![dict exists $cose 3] || [dict get $cose 3] != -7} {
    throw {validation alg-unsupported} "unsupported COSE alg (expected -7 ES256)"
}
if {![dict exists $cose 1] || [dict get $cose 1] != 2} {
    throw {validation keytype-unsupported} "unsupported COSE kty (expected 2 EC2)"
}
if {![dict exists $cose -1] || [dict get $cose -1] != 1} {
    throw {validation curve-unsupported} "unsupported COSE crv (expected 1 P-256)"
}

# Build DB values
set credential_id [ns_base64urlencode -binary -- $credId]
set public_key [dict create  format cose  fmt $fmt  aaguid_b64u [ns_base64urlencode -binary -- $aaguid]  alg [dict get $cose 3]  crv [dict get $cose -1]  cose_b64u [ns_base64urlencode -binary -- $coseKey]  sign_count $signCount  rp_id ${:rp_id}]

return [dict create  user_id $user_id  return_url $return_url  credential_id $credential_id  public_key $public_key  origin [dict get $st origin]  sign_count $signCount]
XQL Not present:
Generic, PostgreSQL, Oracle
[ hide source ] | [ make this the default ]
Show another procedure: