<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE bugzilla SYSTEM "https://bugs.webkit.org/page.cgi?id=bugzilla.dtd">

<bugzilla version="5.0.4.1"
          urlbase="https://bugs.webkit.org/"
          
          maintainer="admin@webkit.org"
>

    <bug>
          <bug_id>311099</bug_id>
          
          <creation_ts>2026-03-30 05:16:18 -0700</creation_ts>
          <short_desc>[WebAuthn] PRF extension returns encrypted hmac-secret output for CTAP2 security keys (missing decryption step)</short_desc>
          <delta_ts>2026-04-09 07:36:56 -0700</delta_ts>
          <reporter_accessible>1</reporter_accessible>
          <cclist_accessible>1</cclist_accessible>
          <classification_id>1</classification_id>
          <classification>Unclassified</classification>
          <product>WebKit</product>
          <component>WebCore Misc.</component>
          <version>WebKit Nightly Build</version>
          <rep_platform>All</rep_platform>
          <op_sys>macOS 26</op_sys>
          <bug_status>NEW</bug_status>
          <resolution></resolution>
          
          
          <bug_file_loc></bug_file_loc>
          <status_whiteboard></status_whiteboard>
          <keywords>InRadar</keywords>
          <priority>P2</priority>
          <bug_severity>Critical</bug_severity>
          <target_milestone>---</target_milestone>
          
          
          <everconfirmed>1</everconfirmed>
          <reporter name="Berni">bsoft</reporter>
          <assigned_to name="Nobody">webkit-unassigned</assigned_to>
          <cc>joost.vandijk</cc>
    
    <cc>nvoutsin</cc>
    
    <cc>webkit-bug-importer</cc>
          

      

      

      

          <comment_sort_order>oldest_to_newest</comment_sort_order>  
          <long_desc isprivate="0" >
    <commentid>2195123</commentid>
    <comment_count>0</comment_count>
    <who name="Berni">bsoft</who>
    <bug_when>2026-03-30 05:16:18 -0700</bug_when>
    <thetext>SUMMARY                                                   

  When using the PRF extension with CTAP2 security keys (USB/NFC), Safari returns                                                                                                                                               
  the AES-256-CBC encrypted hmac-secret output directly as PRF results without
  decrypting it. Platform authenticators (Touch ID, Face ID via ASAuthorization)                                                                                                                                                
  are unaffected.                                           
                                                                                                                                                                                                                                
  STEPS TO REPRODUCE
                                                                                                                                                                                                                                
  1. Register a credential with PRF extension using a FIDO2 security key (e.g. YubiKey) on Safari
  2. Authenticate with the same credential and salt on Safari
  3. Authenticate with the same credential and salt on Chrome                                                                                                                                                                   
  4. Compare derived keys or encrypt/decrypt across browsers
                                                                                                                                                                                                                                
  Test page: https://b-straub.github.io/BlazorPRF/                                                                                                                                                                              
   
  EXPECTED                                                                                                                                                                                                                      
                                                            
  PRF output matches across browsers for the same credential + salt (deterministic, per spec).
  Cross-browser encryption/decryption works.
                                                                                                                                                                                                                                
  ACTUAL
                                                                                                                                                                                                                                
  - Safari macOS &lt;-&gt; Safari iPadOS: PRF outputs match (both apply the same code path, producing identical but still encrypted values)                                                                                           
  - Safari &lt;-&gt; Chrome: PRF outputs differ (Chrome correctly decrypts the hmac-secret response)
  - Cross-browser encryption/decryption fails                                                                                                                                                                                   
                                                            
  ROOT CAUSE                                                                                                                                                                                                                    
   
  In DeviceResponseConverter.cpp, parseAuthenticatorDataExtensions() takes the raw                                                                                                                                              
  hmac-secret byte string from the CTAP2 response and directly creates ArrayBuffers
  without decrypting:
                                                                                                                                                                                                                                
    } else if (hmacIt-&gt;second.isByteString()) {
        auto&amp; hmacOutput = hmacIt-&gt;second.getByteString();                                                                                                                                                                      
        // BUG: hmacOutput is still AES-256-CBC encrypted!  
        RefPtr&lt;ArrayBuffer&gt; first = ArrayBuffer::tryCreate(                                                                                                                                                                     
            hmacOutput.span().first(std::min&lt;size_t&gt;(32, hmacOutput.size())));
        outputs.prf = AuthenticationExtensionsClientOutputs::PRFOutputs { };                                                                                                                                                    
        outputs.prf-&gt;results = AuthenticationExtensionsClientOutputs::PRFValues { first, second };                                                                                                                              
    }
                                                                                                                                                                                                                                
  The decryption logic already exists in HmacSecretResponse::parse() (Pin.cpp),                                                                                                                                                 
  which correctly calls decryptForProtocol(). However, it is never invoked in the
  response processing pipeline.                                                                                                                                                                                                 
                                                            
  CtapAuthenticator (CtapAuthenticator.cpp) stores the shared key in                                                                                                                                                            
  m_hmacSecretRequest but never uses it to decrypt the hmac-secret response.
                                                                                                                                                                                                                                
  SUGGESTED FIX                                             

  Either:
  1. readCTAPGetAssertionResponse() accepts the shared key and calls
     HmacSecretResponse::parse() to decrypt before constructing PRF output, or
  2. CtapAuthenticator post-processes the response using its stored                                                                                                                                                             
     m_hmacSecretRequest to decrypt the extension output
                                                                                                                                                                                                                                
  WHY SAFARI-TO-SAFARI APPEARS CONSISTENT                                                                                                                                                                                       
   
  Safari produces deterministic (but wrong) PRF output because the platform key                                                                                                                                                 
  agreement results in the same shared secret across sessions. Both macOS and iPadOS
  run the same WebKit code path, so both return identical encrypted values. This
  gives false confidence that cross-device PRF works, when in fact the values are
  not interoperable with any correctly implementing browser.                                                                                                                                                                    
   
  ENVIRONMENT                                                                                                                                                                                                                   
                                                            
  - Safari 26.4 on macOS Tahoe / iPadOS
  - FIDO2 security key (YubiKey) via CTAP2/HID
  - Platform authenticators (ASAuthorization path) are NOT affected                                                                                                                                                             
   
  RELATED                                                                                                                                                                                                                       
                                                            
  - PR #53734 (original PRF implementation):
    https://github.com/WebKit/WebKit/pull/53734
  - Review comment by @joostd:                                                                                                                                                                                                  
    https://github.com/WebKit/WebKit/pull/53734#pullrequestreview-4020705594</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>2197231</commentid>
    <comment_count>1</comment_count>
    <who name="Radar WebKit Bug Importer">webkit-bug-importer</who>
    <bug_when>2026-04-06 05:17:11 -0700</bug_when>
    <thetext>&lt;rdar://problem/174154188&gt;</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>2197988</commentid>
    <comment_count>2</comment_count>
    <who name="Joost van Dijk">joost.vandijk</who>
    <bug_when>2026-04-08 08:10:17 -0700</bug_when>
    <thetext>It seems this has already been fixed in branch WebKit-7624.1.16.13. https://github.com/WebKit/WebKit/tree/WebKit-7624.1.16.13.2/
In particular, here:
https://github.com/WebKit/WebKit/blob/dd80a9e46546e49c4a5da9115458077a51220f49/Source/WebCore/Modules/webauthn/fido/DeviceResponseConverter.cpp#L151

Any idea when we can expect a fix to land in Safari?</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>2198334</commentid>
    <comment_count>3</comment_count>
    <who name="Joost van Dijk">joost.vandijk</who>
    <bug_when>2026-04-09 05:13:10 -0700</bug_when>
    <thetext>(In reply to Joost van Dijk from comment #2)
&gt; It seems this has already been fixed in branch WebKit-7624.1.16.13.
&gt; https://github.com/WebKit/WebKit/tree/WebKit-7624.1.16.13.2/
&gt; In particular, here:
&gt; https://github.com/WebKit/WebKit/blob/
&gt; dd80a9e46546e49c4a5da9115458077a51220f49/Source/WebCore/Modules/webauthn/
&gt; fido/DeviceResponseConverter.cpp#L151
&gt; 
&gt; Any idea when we can expect a fix to land in Safari?

Great! I see it has landed in Safari Technology Preview Release 241 (WebKit 21625.1.12)</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>2198361</commentid>
    <comment_count>4</comment_count>
    <who name="Berni">bsoft</who>
    <bug_when>2026-04-09 07:36:56 -0700</bug_when>
    <thetext>Confirmed to be fixed in Safari TP 241. Safari-Chrome roundtrip with FIDO key is working.</thetext>
  </long_desc>
      
      

    </bug>

</bugzilla>