Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Review privacy concerns around error conditions #2132

Open
emlun opened this issue Aug 28, 2024 · 3 comments · May be fixed by #2134
Open

Review privacy concerns around error conditions #2132

emlun opened this issue Aug 28, 2024 · 3 comments · May be fixed by #2134
Assignees
Labels
@Risk Items that are at risk for L3 stat:pr-open type:technical
Milestone

Comments

@emlun
Copy link
Member

emlun commented Aug 28, 2024

The spec contains privacy concerns such as this in the final steps of §5.1.3. Create a New Credential and §5.1.4. Use an Existing Credential to Make an Assertion:

Throw a "NotAllowedError" DOMException. In order to prevent information leak that could identify the user without consent, this step MUST NOT be executed before lifetimeTimer has expired. See § 14.5.1 Registration Ceremony Privacy for details.

These privacy concerns were written for an architecture of these operations that is no longer relevant, and may in fact not have been relevant even at the time the privacy concerns were written (see: #2095 (comment)). We should review whether these privacy concerns are still valid, or if they can be shown to be redundant under the current specification of these operations and thus removed. This would simplify initiatives such as #2096 and #2095.

Proposed Change

Review the validity of these privacy concerns. If they can be shown redundant, delete the prohibition against returning certain errors due to these privacy concerns.

@emlun emlun self-assigned this Aug 28, 2024
@emlun
Copy link
Member Author

emlun commented Aug 28, 2024

I aim to do a thorough review of this by the 2024-09-11 WG meeting.

@emlun emlun mentioned this issue Aug 28, 2024
3 tasks
@emlun
Copy link
Member Author

emlun commented Sep 4, 2024

Enumeration of errors

The following errors may be thrown during create() as of commit a871f79 (2024-09-04):

During init:

  • (If sameOriginWithAncestors is false) and (If options.mediation is present with the value conditional): Throw a "NotAllowedError" DOMException
  • (If sameOriginWithAncestors is false) and (If the relevant global object, as determined by the calling create() implementation, does not have transient activation:): Throw a "NotAllowedError" DOMException
  • (If the length of pkOptions.user.id is not between 1 and 64 bytes (inclusive)): throw a TypeError
  • (If callerOrigin is an opaque origin): throw a "NotAllowedError" DOMException
  • (If effective domain is not a valid domain): throw a "SecurityError" DOMException
  • (If pkOptions.rp.id is present) and (If pkOptions.rp.id is not a registrable domain suffix of and is not equal to effectiveDomain) and (if the client supports related origin requests) and (Run the related origins validation procedure with arguments callerOrigin and rpIdRequested. If the result is false): throw a "SecurityError" DOMException
  • (If pkOptions.rp.id is present) and (If pkOptions.rp.id is not a registrable domain suffix of and is not equal to effectiveDomain) and (if the client does not support related origin requests): throw a "SecurityError" DOMException
  • (If pkOptions.pubKeyCredParams’s size is non-zero) and (after filtering pkOptions.pubKeyCredParams: If credTypesAndPubKeyAlgs is empty): throw a "NotSupportedError" DOMException
  • (Extensions may throw unspecified errors)
  • (If options.signal is present and aborted): throw the options.signal’s abort reason
  • (If options.mediation is present with the value conditional) and (If the user agent has not recently mediated an authentication, the origin of said authentication is not callerOrigin, or the user does not consent to this type of credential creation): throw a "NotAllowedError" DOMException.

During lifetimeTimer wait loop:

  • (If the user exercises a user agent user-interface option to cancel the process): throw a "NotAllowedError" DOMException
  • (If options.signal is present and aborted): throw the options.signal’s abort reason
  • (If pkOptions.authenticatorSelection.userVerification is set to required) and (If options.mediation is set to conditional and user verification cannot be collected during the ceremony): throw a ConstraintError DOMException
  • (If any authenticator returns an error status equivalent to "InvalidStateError"): throw an "InvalidStateError" DOMException
  • (If lifetimeTimer expires): throw a "NotAllowedError" DOMException

Rearranging this as a map of errors to causes of that error, and assigning numbers to each for easy reference:

  • "ConstraintError" DOMException:
    • C1: During lifetimeTimer wait loop: (If pkOptions.authenticatorSelection.userVerification is set to required) and (If options.mediation is set to conditional and user verification cannot be collected during the ceremony)
  • "InvalidStateError" DOMException:
    • I2: During lifetimeTimer wait loop: (If any authenticator returns an error status equivalent to "InvalidStateError")
  • "NotAllowedError" DOMException:
    • NA3: During init: (If options.mediation is present with the value conditional) and (If the user agent has not recently mediated an authentication, the origin of said authentication is not callerOrigin, or the user does not consent to this type of credential creation)
    • NA4: During init: (If callerOrigin is an opaque origin)
    • NA5: During init: (If sameOriginWithAncestors is false) and (If options.mediation is present with the value conditional)
    • NA6: During init: (If sameOriginWithAncestors is false) and (If the relevant global object, as determined by the calling create() implementation, does not have transient activation:)
    • NA7: During lifetimeTimer wait loop: (If lifetimeTimer expires)
    • NA8: During lifetimeTimer wait loop: (If the user exercises a user agent user-interface option to cancel the process)
  • "NotSupportedError" DOMException:
    • NS9: During init: (If pkOptions.pubKeyCredParams’s size is non-zero) and (after filtering pkOptions.pubKeyCredParams: If credTypesAndPubKeyAlgs is empty)
  • "SecurityError" DOMException:
    • S10: During init: (If effective domain is not a valid domain)
    • S11: During init: (If pkOptions.rp.id is present) and (If pkOptions.rp.id is not a registrable domain suffix of and is not equal to effectiveDomain) and (if the client does not support related origin requests)
    • S12: During init: (If pkOptions.rp.id is present) and (If pkOptions.rp.id is not a registrable domain suffix of and is not equal to effectiveDomain) and (if the client supports related origin requests) and (Run the related origins validation procedure with arguments callerOrigin and rpIdRequested. If the result is false)
  • TypeError:
    • T13: During init: (If the length of pkOptions.user.id is not between 1 and 64 bytes (inclusive))
  • (Unspecified error):
    • X14: During init: (Extensions may throw unspecified errors)
    • X15: During init: (If options.signal is present and aborted)
    • X16: During lifetimeTimer wait loop: (If options.signal is present and aborted)

Analysis

  • Concern 1: (NA8) could cause an information leak that could identify the user without consent (§14.5.1. Registration Ceremony Privacy). The information leak occurs if the Relying Party can distinguish between these cases:

    1. No authenticators are present.
    2. At least one authenticator is present, and at least one present authenticator is excluded.

    Preconditions:
    Case (ii) requires that the client has first probed the authenticator for any credentials listed in excludeCredentials.

    Observations:
    The only preconditions for (NA8) are that the client successfully runs through the initialization steps 1-22, then offers the user an option to cancel, and the user exercising that option. There is no precondition of probing for excluded credentials.

    Conclusion:
    (NA8) cannot cause an information leak that could identify the user without consent.

  • Concern 2: (NA7) and (NA8) should be indistinghishable in order to not facilitate the information leak in Concern 1.

    Observations:
    (NA7) and (NA8) are already distinguishable, since (NA7) likely occurs around options.publicKey.timeout milliseconds after create() was invoked, especially if options.publicKey.timeout falls within the recommended reasonable range.

    Since in Concern 1 we already concluded that (NA8) cannot cause the relevant information leak, the information leak cannot be made worse by (NA7) and (NA8) being distinguishable.

    Conclusion:
    (NA7) and (NA8) do not need to be indistinguishable. (NA7) can be safely changed to a distinct TimeoutError.

  • Remark 3:
    (I2) does allow the Relying Party to detect that an excluded credential is available to the user. However, this error has an explicit consent precondition in the authenticator operation: (If looking up descriptor.id in this authenticator returns non-null, and the returned item's RP ID and type match rpEntity.id and excludeCredentialDescriptorList.type respectively) and (If the user confirms consent to create a new credential). If the user does not consent to this, then the authenticator instead returns an error code equivalent to "NotAllowedError", which does not immediately cause an error on the client layer but most likely eventually results in (NA7) or (NA8) instead.

@emlun
Copy link
Member Author

emlun commented Sep 4, 2024

Enumeration of errors

The following errors may be thrown during get() as of commit a871f79 (2024-09-04):

During init:

  • (If callerOrigin is an opaque origin): throw a "NotAllowedError" DOMException
  • (If effective domain is not a valid domain): throw a "SecurityError" DOMException
  • (If pkOptions.rpId is present) and (If pkOptions.rpId is not a registrable domain suffix of and is not equal to effectiveDomain) and (if the client supports related origin requests) and (Run the related origins validation procedure with arguments callerOrigin and rpIdRequested. If the result is false): throw a "SecurityError" DOMException
  • (If pkOptions.rpId is present) and (If pkOptions.rpId is not a registrable domain suffix of and is not equal to effectiveDomain) and (if the client does not support related origin requests): throw a "SecurityError" DOMException
  • (Extensions may throw unspecified errors): throw a (Unspecified error)
  • (If options.signal is present and aborted): throw the options.signal’s abort reason

During lifetimeTimer wait loop:

  • (If lifetimeTimer expires): throw a "NotAllowedError" DOMException
  • (If the user exercises a user agent user-interface option to cancel the process): throw a "NotAllowedError" DOMException
  • (If options.signal is present and aborted): throw the options.signal’s abort reason
  • (If options.mediation is not conditional, issuedRequests is empty, pkOptions.allowCredentials is not empty, and no authenticator will become available for any public key credentials therein) and (Indicate to the user that no eligible credential could be found. When the user acknowledges the dialog): throw a "NotAllowedError" DOMException

Rearranging this as a map of errors to causes of that error, and assigning numbers to each for easy reference:

  • "NotAllowedError" DOMException:
    • (NA17): During init: (If callerOrigin is an opaque origin)
    • (NA18): During lifetimeTimer wait loop: (If lifetimeTimer expires)
    • (NA19): During lifetimeTimer wait loop: (If options.mediation is not conditional, issuedRequests is empty, pkOptions.allowCredentials is not empty, and no authenticator will become available for any public key credentials therein) and (When the user acknowledges the dialog)
    • (NA20): During lifetimeTimer wait loop: (If the user exercises a user agent user-interface option to cancel the process)
  • "SecurityError" DOMException:
    • (S21): During init: (If effective domain is not a valid domain)
    • (S22): During init: (If pkOptions.rpId is present) and (If pkOptions.rpId is not a registrable domain suffix of and is not equal to effectiveDomain) and (if the client does not support related origin requests)
    • (S23): During init: (If pkOptions.rpId is present) and (If pkOptions.rpId is not a registrable domain suffix of and is not equal to effectiveDomain) and (if the client supports related origin requests) and (Run the related origins validation procedure with arguments callerOrigin and rpIdRequested. If the result is false)
  • (Unspecified error):
    • (X24): During init: (Extensions may throw unspecified errors)
    • (X25): During init: (If options.signal is present and aborted)
    • (X26): During lifetimeTimer wait loop: (If options.signal is present and aborted)

Analysis

  • Concern 4: (NA20) could cause an information leak that could identify the user without consent (§14.5.2. Authentication Ceremony Privacy). The information leak occurs if the Relying Party can distinguish between these cases:

    1. A named credential is not available.
    2. A named credential is available, but the user does not consent to use it.

    Preconditions:
    Both case (i) and case (ii) require that the client has first probed the authenticator for any credentials listed in allowCredentials.

    Observations:
    The only preconditions for (NA20) are that the client successfully runs through the initialization steps 1-20, then offers the user an option to cancel, and the user exercising that option. There is no precondition of probing for eligible credentials.

    Conclusion:
    (NA20) cannot cause an information leak that could identify the user without consent.

  • Concern 5: (NA18) and (NA20) should be indistinghishable in order to not facilitate the information leak in Concern 4.

    Observations:
    (NA18) and (NA20) are already distinguishable, since (NA18) likely occurs around options.publicKey.timeout milliseconds after get() was invoked, especially if options.publicKey.timeout falls within the recommended reasonable range.

    Since in Concern 4 we already concluded that (NA20) cannot cause the relevant information leak, the information leak cannot be made worse by (NA18) and (NA20) being distinguishable.

    Conclusion:
    (NA18) and (NA20) do not need to be indistinguishable. (NA18) can be safely changed to a distinct TimeoutError.

@emlun emlun linked a pull request Sep 4, 2024 that will close this issue
1 task
@nadalin nadalin added this to the L3-WD-02 milestone Sep 11, 2024
@nadalin nadalin added the @Risk Items that are at risk for L3 label Sep 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
@Risk Items that are at risk for L3 stat:pr-open type:technical
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants