diff --git a/spec.bs b/spec.bs index 667c66282..c133b130c 100644 --- a/spec.bs +++ b/spec.bs @@ -4558,14 +4558,16 @@ dictionary StorageInterestGroup : AuctionAdInterestGroup { *This first introductory paragraph is non-normative.* -{{Window/navigator}}.{{Navigator/createAuctionNonce()}} creates an auction nonce, a -one-time [=version 4 UUID=] uniquely associated with a single call to -{{Window/navigator}}.{{Navigator/runAdAuction()}}. For multi-seller auctions, this ID is uniquely -associated with all {{AuctionAdConfig/componentAuctions}}. This nonce will need to be passed back in -via a subsequent call to {{Window/navigator}}.{{Navigator/runAdAuction()}} via the -{{AuctionAdConfig}}. This is currently only needed for [=auctions=] that use [=additional bids=], -for which the [=auction nonce=] will be included in each [=additional bid=] as a way of ensuring -that those bids are only used in the [=auctions=] for which they were intended. +{{Window/navigator}}.{{Navigator/createAuctionNonce()}} creates an auction nonce, which +is a one-time canonical [=string=] representation of a [=version 4 UUID=] that is uniquely +associated with a single call to {{Window/navigator}}.{{Navigator/runAdAuction()}}. For multi-seller +auctions, a distinct auction nonce can be uniquely associated with each of the +{{AuctionAdConfig/componentAuctions}}. The auction nonce(s) will need to be passed back in via a +subsequent call to {{Window/navigator}}.{{Navigator/runAdAuction()}} via the {{AuctionAdConfig}}. +This is currently only needed for [=auctions=] that use [=additional bids=], in which the auction +nonce is combined with a [=signed additional bid with metadata/seller nonce=] to construct a bid +nonce that must be included in each [=additional bid=]. For backwards compatibility, [=additional +bids=] may include an auction nonce directly in place of a bid nonce. [SecureContext] @@ -4647,15 +4649,19 @@ a [=reporting context map=] |reportingContextMap|, and a [=global object=] |glob 1. Let |auctionNonce| be the [=string representation=] of |auctionConfig|'s [=auction config/auction nonce=]. 1. Let |capturedAdditionalBidsHeaders| be |global|'s [=associated Document's=] - [=node navigable's=] [=traversable navigable's=] [=captured additional bids headers=]. + [=node navigable's=] [=traversable navigable's=] [=traversable navigable/captured ad auction + additional bids headers=]. 1. Let |additionalBids| be a new [=list=] of [=decoded additional bids=]. - 1. [=list/For each=] |encodedSignedAdditionalBid| of |capturedAdditionalBidsHeaders|[|auctionNonce|]: + 1. [=list/For each=] |encodedSignedAdditionalBidWithMetadata| of + |capturedAdditionalBidsHeaders|[|auctionNonce|]: 1. Let |signedAdditionalBid| be the result of running [=forgiving-base64 decode=] with - |encodedSignedAdditionalBid|. + |encodedSignedAdditionalBidWithMetadata|'s [=signed additional bid with metadata/signed + additional bid=]. 1. If |signedAdditionalBid| is failure, then [=iteration/continue=]. 1. Let |additionalBid| be the result of running [=parse a signed additional bid=] given - |signedAdditionalBid|, |reportingContextMap|, |auctionConfig|, |topLevelAuctionConfig|, and - |negativeTargetInfo|. + |signedAdditionalBid|, |reportingContextMap|, |encodedSignedAdditionalBidWithMetadata|'s + [=signed additional bid with metadata/seller nonce=], |auctionConfig|, + |topLevelAuctionConfig|, and |negativeTargetInfo|. 1. If |additionalBid| is not null: 1. [=list/Append=] |additionalBid| to |additionalBids|. 1. Let |bidCopy| be a clone of |additionalBid|. @@ -4665,9 +4671,9 @@ a [=reporting context map=] |reportingContextMap|, and a [=global object=] |glob <div algorithm> To <dfn>parse a signed additional bid</dfn> given a [=byte sequence=] |signedAdditionalBid|, -a [=reporting context map=] |reportingContextMap|, an [=auction config=] |auctionConfig|, -an [=auction config=]-or-null |topLevelAuctionConfig|, and a [=negative target info=] -|negativeTargetInfo|: +a [=reporting context map=] |reportingContextMap|, a [=string=]-or-null |sellerNonce|, an [=auction +config=] |auctionConfig|, an [=auction config=]-or-null |topLevelAuctionConfig|, and a [=negative +target info=] |negativeTargetInfo|: 1. [=Assert=] that these steps are running [=in parallel=]. 1. Let |parsedSignedAdditionalBid| be the result of running [=parse a JSON string to an infra value=] @@ -4697,8 +4703,8 @@ an [=auction config=]-or-null |topLevelAuctionConfig|, and a [=negative target i 1. [=list/Append=] |signature| to |signatures|. 1. If |decodeSignatureFailed| is true, then return null. 1. Let |decodedAdditionalBid| be the result of [=decode an additional bid json=] given - |parsedSignedAdditionalBid|["bid"], |reportingContextMap|, |auctionConfig| and - |topLevelAuctionConfig|. + |parsedSignedAdditionalBid|["bid"], |reportingContextMap|, |auctionConfig|, + |topLevelAuctionConfig|, and |sellerNonce|. 1. Return null if any of the following conditions hold: * |decodedAdditionalBid| is failure; * The result of [=checking a currency tag=] with |decodedAdditionalBid|'s @@ -4718,8 +4724,8 @@ an [=auction config=]-or-null |topLevelAuctionConfig|, and a [=negative target i <div algorithm> To <dfn>decode an additional bid json</dfn> given a [=string=] |additionalBidJson|, -a [=reporting context map=] |reportingContextMap|, an [=auction config=] |auctionConfig|, and an -[=auction config=]-or-null |topLevelAuctionConfig|: +a [=reporting context map=] |reportingContextMap|, an [=auction config=] |auctionConfig|, an +[=auction config=]-or-null |topLevelAuctionConfig|, and a [=string=]-or-null |sellerNonce|: 1. [=Assert=] that these steps are running [=in parallel=]. 1. Let |parsedAdditionalBid| be the result of [=parse a JSON string to an infra value=] given @@ -4727,12 +4733,25 @@ a [=reporting context map=] |reportingContextMap|, an [=auction config=] |auctio 1. If |parsedAdditionalBid| is not a [=map=], then return failure. 1. Let |result| be a new [=decoded additional bid=]. 1. Return failure if any of the following conditions hold: - * |parsedAdditionalBid|["auctionNonce"] does not [=map/exist=]; - * |parsedAdditionalBid|["auctionNonce"] is not the [=string representation=] of - |auctionConfig|'s [=auction config/auction nonce=]; + * |parsedAdditionalBid|["auctionNonce"] [=map/exists=] and |parsedAdditionalBid|["bidNonce"] + [=map/exists=]; + * |parsedAdditionalBid|["auctionNonce"] does not [=map/exist=] and + |parsedAdditionalBid|["bidNonce"] does not [=map/exist=]; * |parsedAdditionalBid|["seller"] does not [=map/exist=]; * The result of running the [=parse an https origin=] with |parsedAdditionalBid|["seller"] is failure, or not [=same origin=] with |auctionConfig|'s [=auction config/seller=]. + 1. If |sellerNonce| is not null: + 1. Return failure if any of the following conditions hold: + 1. |parsedAdditionalBid|["bidNonce"] does not [=map/exist=]; + 1. |parsedAdditionalBid|["bidNonce"] is not the result of [=calculate expected bid nonce=] + given the [=string representation=] of |auctionConfig|'s [=auction config/auction nonce=] + and |sellerNonce|. + 1. Otherwise: + 1. Return failure if any of the following conditions hold: + * |parsedAdditionalBid|["auctionNonce"] does not [=map/exist=]; + * |parsedAdditionalBid|["auctionNonce"] is not the [=string representation=] of + |auctionConfig|'s [=auction config/auction nonce=]; + 1. If |topLevelAuctionConfig| is null: 1. If |parsedAdditionalBid|["topLevelSeller"] [=map/exists=], then return failure. 1. Otherwise: @@ -4857,6 +4876,15 @@ a [=reporting context map=] |reportingContextMap|, an [=auction config=] |auctio 1. Return |result|. </div> +<div algorithm> +To <dfn>calculate expected bid nonce</dfn> given a [=string=] |auctionNonce| and a [=string=] +|sellerNonce|: + + 1. Return the result of [=forgiving-base64 encoding=] the [=SHA-256=] hash of the result of + [=string/concatenating=] «|auctionNonce|, |sellerNonce|». + +</div> + A <dfn>signed additional bid signature</dfn> is a [=struct=] with the following [=struct/items=]: <dl dfn-for="signed additional bid signature"> : <dfn>key</dfn> @@ -4876,10 +4904,6 @@ A <dfn>decoded additional bid</dfn> is a [=struct=] with the following [=struct/ [=decoded additional bid/negative target interest group names=]. </dl> -Each [=traversable navigable=] has a <dfn>captured additional bids headers</dfn>, which is a [=map=] -whose [=map/keys=] are [=strings=] for [=auction nonces=], and whose values are [=list=] of -[=strings=] for encoded additional bids. - ## Negative Targeting ## {#negative-targeting-section} *This first introductory paragraph is non-normative.* @@ -4893,7 +4917,7 @@ Protected Audience [=auctions=], each [=additional bid=] is allowed to identify that specifies no [=negative interest groups=] is always accepted into the [=auction=]. <div algorithm> -To <dfn>check whether negative targeted</dfn> given an [=decoded additional bid=] |additionalBid|, a +To <dfn>check whether negative targeted</dfn> given a [=decoded additional bid=] |additionalBid|, a [=set=] of [=byte sequences=] |verifiedSignatureKeys|, and a [=negative target info=] |negativeTargetInfo|: @@ -6864,7 +6888,7 @@ request with the <{iframe/adauctionheaders}> Each [=traversable navigable=] has a <dfn for="traversable navigable">captured ad auction additional bids headers</dfn>, which is a [=map=] whose [=map/keys=] are [=auction nonces=] and whose -[=map/values=] are [=strings=]. +[=map/values=] are [=lists=] of [=signed additional bid with metadata=]. NOTE: This is only captured during a [=request=] whose [=request/initiator type=] is `"fetch"`, made with the {{RequestInit/adAuctionHeaders}} option set to `true`, or during an @@ -6876,11 +6900,11 @@ Each [=traversable navigable=] has a <dfn for="traversable navigable">saved Bidd and Auction request context</dfn>, which is a [=map=] whose [=map/keys=] are the [=string representation=] of a [=version 4 UUID=] and whose [=map/values=] are [=server auction request contexts=]. -</div> Each [=traversable navigable=] has a <dfn for="traversable navigable">captured ad auction result headers</dfn>, which is a [=map=] whose [=map/keys=] are [=origins=] and [=map/values=] are [=strings=]. +</div> <div algorithm="fetch capture adAuctionHeaders boolean patch"> Modify the definition of a [=request=]: @@ -6971,9 +6995,12 @@ component, and top-level auctions may specify which signals to load by the `adSl HTTP response header.</h3> The \`<dfn http-header><code>Ad-Auction-Additional-Bid</code></dfn>\` response header provides value -of a string in the format of `<auction nonce>:<base64-encoding of the signed additional bid>`, which -corresponds to a single [=additional bid=]. The response may include more than one [=additional bid=] -by specifying multiple instances of the [:Ad-Auction-Additional-Bid:] response header. +of a string in the format of `<auction nonce>:<seller nonce>:<base64-encoding of the signed +additional bid>`, or the legacy format of `<auction nonce>:<base64-encoding of the signed additional +bid>`, either of which corresponds to a single [=additional bid=]. In the format that provides a +seller nonce, the seller nonce must be as described in [=signed additional bid with metadata/seller +nonce=]. The response may include more than one [=additional bid=] by specifying multiple instances +of the [:Ad-Auction-Additional-Bid:] response header. </div> <h3 id=ad-auction-result-header>The \`<a http-header><code>Ad-Auction-Result</code></a>\` @@ -7050,11 +7077,24 @@ The following algorithm will be added to the [[FETCH#fetching]] section: that is, scripts making the {{WindowOrWorkerGlobalScope/fetch()}} request aren't able to load the header value. 1. [=list/For each=] |bid| of |additionalBids|: - 1. Let |nonceAndAdditionalBid| be the result of [=strictly splitting=] |bid| on U+003A (:). - 1. If |nonceAndAdditionalBid|'s [=list/size=] is not 2, then [=iteration/continue=]. - 1. Let |nonce| be |nonceAndAdditionalBid|[0]. - 1. If |nonce|'s [=string/length=] is not 36, then [=iteration/continue=]. - 1. Set |storedAdditionalBidsHeaders|[|nonce|] to |nonceAndAdditionalBid|[1]. + 1. Let |parts| be the result of [=strictly splitting=] |bid| on U+003A (:). + 1. Let |bidWithMetadata| be a new [=signed additional bid with metadata=]. + 1. If |parts|'s [=list/size=] is 3: + 1. Let |auctionNonce| be |parts|[0]. + 1. If |auctionNonce|'s [=string/length=] is not 36, then [=iteration/continue=]. + 1. Let |sellerNonce| be |parts|[1]. + 1. If |sellerNonce|'s [=string/length=] is not 36, then [=iteration/continue=]. + 1. Let |bidWithMetadata|'s [=signed additional bid with metadata/seller nonce=] be + |sellerNonce|. + 1. Let |bidWithMetadata|'s [=signed additional bid with metadata/signed additional bid=] be + |parts|[2]. + 1. [=list/Append=] |bidWithMetadata| to |storedAdditionalBidsHeaders|[|auctionNonce|]. + 1. Otherwise, if |parts|'s [=list/size=] is 2: + 1. Let |auctionNonce| be |parts|[0]. + 1. If |auctionNonce|'s [=string/length=] is not 36, then [=iteration/continue=]. + 1. Let |bidWithMetadata|'s [=signed additional bid with metadata/signed additional bid=] be + |parts|[1]. + 1. [=list/Append=] |bidWithMetadata| to |storedAdditionalBidsHeaders|[|auctionNonce|]. 1. Let |adAuctionResults| be the result of [=header list/getting, decoding, and splitting=] [:Ad-Auction-Result:] from |responseHeaders|. @@ -7731,8 +7771,10 @@ An <dfn export>auction config</dfn> is a [=struct=] with the following [=struct/ uniquely associated with all {{AuctionAdConfig/componentAuctions}}. This must come from a prior call to {{Window/navigator}}.{{Navigator/createAuctionNonce()}}. This is only required for auctions that provide [=additional bids=], and each of those - [=additional bids=] must use the same auction nonce to ensure that each of them was intended for - this and only this auction. + [=additional bids=] must include the bid nonce derived from that auction nonce as computed by + [=calculate expected bid nonce=] to ensure that each [=additional bid=] was intended for this + and only this auction. For backwards compatibility, an [=additional bid=] may include the + [=auction nonce=] directly in place of a bid nonce. : <dfn>expects additional bids</dfn> :: A [=boolean=] or failure, initially false. Specifies whether some bids will be provided as signed exchanges. Sets to failure if the @@ -8640,6 +8682,20 @@ A <dfn>direct from seller signals</dfn> is a [=struct=] with the following [=str JSON data passed to corresponding buyer's [=script runner=]. </dl> +<h3 id=additional-bids-structs-section>Additional bids</h3> + +A <dfn>signed additional bid with metadata</dfn> is a [=struct=] with the following +[=struct/items=]: + +<dl dfn-for="signed additional bid with metadata"> + : <dfn>signed additional bid</dfn> + :: A [=string=] for an encoded additional bid. + : <dfn>seller nonce</dfn> + :: Null or a [=string=]. If present, represents the randomly-generated seller nonce returned in + the [:Ad-Auction-Additional-Bid:] response header. This must be 36 characters, and should be the + canonoical [=string=] representation of a [=version 4 UUID=]. +</dl> + <h3 id=score-ad-output-header>Score ad output</h3> The output of running a Protected Audience `scoreAd()` script, is represented using the following type: