1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.adservices.service.adselection.encryption; 18 19 import static com.android.adservices.service.common.httpclient.AdServicesHttpUtil.REQUEST_PROPERTIES_PROTOBUF_CONTENT_TYPE; 20 import static com.android.adservices.service.common.httpclient.AdServicesHttpUtil.RESPONSE_PROPERTIES_CONTENT_TYPE; 21 import static com.android.adservices.service.stats.AdsRelevanceStatusUtils.SERVER_AUCTION_ENCRYPTION_KEY_SOURCE_NETWORK; 22 23 import android.net.Uri; 24 25 import androidx.annotation.NonNull; 26 import androidx.annotation.Nullable; 27 28 import com.android.adservices.LoggerFactory; 29 import com.android.adservices.data.adselection.DBEncryptionKey; 30 import com.android.adservices.data.adselection.EncryptionKeyConstants; 31 import com.android.adservices.ohttp.ObliviousHttpKeyConfig; 32 import com.android.adservices.service.Flags; 33 import com.android.adservices.service.common.httpclient.AdServicesHttpClientRequest; 34 import com.android.adservices.service.common.httpclient.AdServicesHttpClientResponse; 35 import com.android.adservices.service.common.httpclient.AdServicesHttpsClient; 36 import com.android.adservices.service.devapi.DevContext; 37 import com.android.adservices.service.stats.AdServicesLogger; 38 import com.android.adservices.service.stats.FetchProcessLogger; 39 40 import com.google.common.collect.ImmutableList; 41 import com.google.common.util.concurrent.FluentFuture; 42 import com.google.common.util.concurrent.ListenableFuture; 43 44 import java.security.spec.InvalidKeySpecException; 45 import java.time.Clock; 46 import java.time.Instant; 47 import java.util.List; 48 import java.util.Objects; 49 import java.util.Set; 50 import java.util.concurrent.ExecutorService; 51 52 public abstract class ProtectedServersEncryptionConfigManagerBase { 53 protected static final LoggerFactory.Logger sLogger = LoggerFactory.getFledgeLogger(); 54 protected final Clock mClock; 55 protected final ExecutorService mLightweightExecutor; 56 57 protected final Flags mFlags; 58 protected final AdServicesLogger mAdServicesLogger; 59 60 protected final AuctionEncryptionKeyParser mAuctionEncryptionKeyParser; 61 protected final JoinEncryptionKeyParser mJoinEncryptionKeyParser; 62 protected final AdServicesHttpsClient mAdServicesHttpsClient; 63 64 @Nullable getLatestOhttpKeyConfigOfType( @dSelectionEncryptionKey.AdSelectionEncryptionKeyType int adSelectionEncryptionKeyType, long timeoutMs, @Nullable Uri coordinatorUrl, DevContext devContext)65 abstract FluentFuture<ObliviousHttpKeyConfig> getLatestOhttpKeyConfigOfType( 66 @AdSelectionEncryptionKey.AdSelectionEncryptionKeyType int adSelectionEncryptionKeyType, 67 long timeoutMs, 68 @Nullable Uri coordinatorUrl, 69 DevContext devContext); 70 fetchAndPersistActiveKeysOfType( @dSelectionEncryptionKey.AdSelectionEncryptionKeyType int adSelectionKeyType, Instant keyExpiryInstant, long timeoutMs, @Nullable Uri coordinatorUrl, DevContext devContext, FetchProcessLogger keyFetchLogger)71 abstract FluentFuture<List<DBEncryptionKey>> fetchAndPersistActiveKeysOfType( 72 @AdSelectionEncryptionKey.AdSelectionEncryptionKeyType int adSelectionKeyType, 73 Instant keyExpiryInstant, 74 long timeoutMs, 75 @Nullable Uri coordinatorUrl, 76 DevContext devContext, 77 FetchProcessLogger keyFetchLogger); 78 getExpiredAdSelectionEncryptionKeyTypes(Instant keyExpiryInstant)79 abstract Set<Integer> getExpiredAdSelectionEncryptionKeyTypes(Instant keyExpiryInstant); 80 getAbsentAdSelectionEncryptionKeyTypes()81 abstract Set<Integer> getAbsentAdSelectionEncryptionKeyTypes(); 82 ProtectedServersEncryptionConfigManagerBase( @onNull Flags flags, @NonNull Clock clock, @NonNull AuctionEncryptionKeyParser auctionEncryptionKeyParser, @NonNull JoinEncryptionKeyParser joinEncryptionKeyParser, @NonNull AdServicesHttpsClient adServicesHttpsClient, @NonNull ExecutorService lightweightExecutor, @NonNull AdServicesLogger adServicesLogger)83 protected ProtectedServersEncryptionConfigManagerBase( 84 @NonNull Flags flags, 85 @NonNull Clock clock, 86 @NonNull AuctionEncryptionKeyParser auctionEncryptionKeyParser, 87 @NonNull JoinEncryptionKeyParser joinEncryptionKeyParser, 88 @NonNull AdServicesHttpsClient adServicesHttpsClient, 89 @NonNull ExecutorService lightweightExecutor, 90 @NonNull AdServicesLogger adServicesLogger) { 91 Objects.requireNonNull(flags); 92 Objects.requireNonNull(clock); 93 Objects.requireNonNull(auctionEncryptionKeyParser); 94 Objects.requireNonNull(joinEncryptionKeyParser); 95 Objects.requireNonNull(adServicesHttpsClient); 96 Objects.requireNonNull(lightweightExecutor); 97 Objects.requireNonNull(adServicesLogger); 98 99 this.mFlags = flags; 100 this.mClock = clock; 101 this.mAuctionEncryptionKeyParser = auctionEncryptionKeyParser; 102 this.mJoinEncryptionKeyParser = joinEncryptionKeyParser; 103 this.mAdServicesHttpsClient = adServicesHttpsClient; 104 this.mLightweightExecutor = lightweightExecutor; 105 this.mAdServicesLogger = adServicesLogger; 106 } 107 parseKeyResponse( AdServicesHttpClientResponse keyFetchResponse, @AdSelectionEncryptionKey.AdSelectionEncryptionKeyType int encryptionKeyType)108 protected List<DBEncryptionKey> parseKeyResponse( 109 AdServicesHttpClientResponse keyFetchResponse, 110 @AdSelectionEncryptionKey.AdSelectionEncryptionKeyType int encryptionKeyType) { 111 switch (encryptionKeyType) { 112 case AdSelectionEncryptionKey.AdSelectionEncryptionKeyType.AUCTION: 113 return mAuctionEncryptionKeyParser.getDbEncryptionKeys(keyFetchResponse); 114 case AdSelectionEncryptionKey.AdSelectionEncryptionKeyType.JOIN: 115 return mJoinEncryptionKeyParser.getDbEncryptionKeys(keyFetchResponse); 116 case AdSelectionEncryptionKey.AdSelectionEncryptionKeyType.UNASSIGNED: 117 default: 118 return ImmutableList.of(); 119 } 120 } 121 parseDbEncryptionKey(DBEncryptionKey dbEncryptionKey)122 protected AdSelectionEncryptionKey parseDbEncryptionKey(DBEncryptionKey dbEncryptionKey) { 123 switch (dbEncryptionKey.getEncryptionKeyType()) { 124 case EncryptionKeyConstants.EncryptionKeyType.ENCRYPTION_KEY_TYPE_AUCTION: 125 return mAuctionEncryptionKeyParser.parseDbEncryptionKey(dbEncryptionKey); 126 case EncryptionKeyConstants.EncryptionKeyType.ENCRYPTION_KEY_TYPE_JOIN: 127 return mJoinEncryptionKeyParser.parseDbEncryptionKey(dbEncryptionKey); 128 case EncryptionKeyConstants.EncryptionKeyType.ENCRYPTION_KEY_TYPE_QUERY: 129 default: 130 return null; 131 } 132 } 133 getKeyCountForType( @dSelectionEncryptionKey.AdSelectionEncryptionKeyType int type)134 protected int getKeyCountForType( 135 @AdSelectionEncryptionKey.AdSelectionEncryptionKeyType int type) { 136 switch (type) { 137 case AdSelectionEncryptionKey.AdSelectionEncryptionKeyType.AUCTION: 138 // For auctions, more than one key is fetched from the DB to mitigate impact 139 // due to key leakage. 140 return mFlags.getFledgeAuctionServerAuctionKeySharding(); 141 case AdSelectionEncryptionKey.AdSelectionEncryptionKeyType.JOIN: 142 return 1; 143 case AdSelectionEncryptionKey.AdSelectionEncryptionKeyType.UNASSIGNED: 144 default: 145 return 0; 146 } 147 } 148 getOhttpKeyConfigForKey(AdSelectionEncryptionKey encryptionKey)149 protected ObliviousHttpKeyConfig getOhttpKeyConfigForKey(AdSelectionEncryptionKey encryptionKey) 150 throws InvalidKeySpecException { 151 Objects.requireNonNull(encryptionKey); 152 switch (encryptionKey.keyType()) { 153 case AdSelectionEncryptionKey.AdSelectionEncryptionKeyType.AUCTION: 154 return mAuctionEncryptionKeyParser.getObliviousHttpKeyConfig(encryptionKey); 155 case AdSelectionEncryptionKey.AdSelectionEncryptionKeyType.JOIN: 156 return mJoinEncryptionKeyParser.getObliviousHttpKeyConfig(encryptionKey); 157 case AdSelectionEncryptionKey.AdSelectionEncryptionKeyType.UNASSIGNED: 158 default: 159 throw new IllegalArgumentException( 160 "Encryption Key of given type is not supported."); 161 } 162 } 163 fetchKeyPayload( @dSelectionEncryptionKey.AdSelectionEncryptionKeyType int adSelectionKeyType, Uri fetchUri, DevContext devContext, FetchProcessLogger keyFetchLogger)164 protected ListenableFuture<AdServicesHttpClientResponse> fetchKeyPayload( 165 @AdSelectionEncryptionKey.AdSelectionEncryptionKeyType int adSelectionKeyType, 166 Uri fetchUri, 167 DevContext devContext, 168 FetchProcessLogger keyFetchLogger) { 169 keyFetchLogger.setEncryptionKeySource(SERVER_AUCTION_ENCRYPTION_KEY_SOURCE_NETWORK); 170 switch (adSelectionKeyType) { 171 case AdSelectionEncryptionKey.AdSelectionEncryptionKeyType.AUCTION: 172 return mAdServicesHttpsClient.fetchPayloadWithLogging( 173 fetchUri, devContext, keyFetchLogger); 174 case AdSelectionEncryptionKey.AdSelectionEncryptionKeyType.JOIN: 175 AdServicesHttpClientRequest fetchKeyRequest = 176 AdServicesHttpClientRequest.builder() 177 .setUri(fetchUri) 178 .setRequestProperties(REQUEST_PROPERTIES_PROTOBUF_CONTENT_TYPE) 179 .setResponseHeaderKeys(RESPONSE_PROPERTIES_CONTENT_TYPE) 180 .setDevContext(devContext) 181 .build(); 182 return mAdServicesHttpsClient.performRequestGetResponseInBase64StringWithLogging( 183 fetchKeyRequest, keyFetchLogger); 184 case AdSelectionEncryptionKey.AdSelectionEncryptionKeyType.UNASSIGNED: 185 default: 186 throw new IllegalStateException( 187 "AdSelectionEncryptionKeyType: " 188 + adSelectionKeyType 189 + " is not supported."); 190 } 191 } 192 } 193