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.data.adselection; 18 19 import androidx.annotation.NonNull; 20 import androidx.annotation.Nullable; 21 import androidx.room.ColumnInfo; 22 import androidx.room.Entity; 23 import androidx.room.Index; 24 import androidx.room.PrimaryKey; 25 26 import com.google.auto.value.AutoValue; 27 28 import java.time.Instant; 29 30 /** 31 * Table representing Encryption keys with a field for coordinator to specify where the key was 32 * fetched from. 33 */ 34 @AutoValue 35 @AutoValue.CopyAnnotations 36 @Entity( 37 tableName = "protected_servers_encryption_config", 38 indices = { 39 @Index(value = {"coordinator_url", "encryption_key_type", "expiry_instant"}), 40 @Index( 41 value = {"coordinator_url", "encryption_key_type", "key_identifier"}, 42 unique = true) 43 }) 44 public abstract class DBProtectedServersEncryptionConfig { 45 46 /** 47 * Unique ID per key record. This is different from {@link #getKeyIdentifier()} which is only 48 * unique per coordinator. 49 * 50 * <p>This ID is only used internally in the table and does not need to be stable or 51 * reproducible. It is auto-generated by Room if set to {@code null} on insertion. 52 */ 53 @AutoValue.CopyAnnotations 54 @PrimaryKey(autoGenerate = true) 55 @ColumnInfo(name = "row_id") 56 @Nullable getRowId()57 public abstract Long getRowId(); 58 59 /** The coordinator URL from which this key was fetched. */ 60 @NonNull 61 @AutoValue.CopyAnnotations 62 @ColumnInfo(name = "coordinator_url") getCoordinatorUrl()63 public abstract String getCoordinatorUrl(); 64 65 /** Type of Key. */ 66 @NonNull 67 @AutoValue.CopyAnnotations 68 @EncryptionKeyConstants.EncryptionKeyType 69 @ColumnInfo(name = "encryption_key_type") getEncryptionKeyType()70 public abstract int getEncryptionKeyType(); 71 72 /** KeyIdentifier used for versioning the keys. */ 73 @NonNull 74 @AutoValue.CopyAnnotations 75 @ColumnInfo(name = "key_identifier") getKeyIdentifier()76 public abstract String getKeyIdentifier(); 77 78 /** 79 * The actual public key. Encoding and parsing of this key is dependent on the keyType and will 80 * be managed by the Key Client. 81 */ 82 @NonNull 83 @AutoValue.CopyAnnotations 84 @ColumnInfo(name = "public_key") getPublicKey()85 public abstract String getPublicKey(); 86 87 /** Instant this EncryptionKey entry was created. */ 88 @AutoValue.CopyAnnotations 89 @ColumnInfo(name = "creation_instant") getCreationInstant()90 public abstract Instant getCreationInstant(); 91 92 /** 93 * Expiry TTL for this encryption key in seconds. This is sent by the server and stored on 94 * device for computing expiry Instant. Clients should directly read the expiryInstant unless 95 * they specifically need to know the expiry ttl seconds reported by the server. 96 */ 97 @NonNull 98 @AutoValue.CopyAnnotations getExpiryTtlSeconds()99 public abstract Long getExpiryTtlSeconds(); 100 101 /** 102 * Expiry Instant for this encryption key computed as 103 * creationInstant.plusSeconds(expiryTtlSeconds). Clients should use this field to read the key 104 * expiry value instead of computing it from creation instant and expiry ttl seconds. 105 */ 106 @NonNull 107 @AutoValue.CopyAnnotations 108 @ColumnInfo(name = "expiry_instant") getExpiryInstant()109 public abstract Instant getExpiryInstant(); 110 111 /** Returns an AutoValue builder for a {@link DBProtectedServersEncryptionConfig} entity. */ 112 @NonNull builder()113 public static DBProtectedServersEncryptionConfig.Builder builder() { 114 return new AutoValue_DBProtectedServersEncryptionConfig.Builder() 115 .setCreationInstant(Instant.now()); 116 } 117 118 /** 119 * Creates a {@link DBProtectedServersEncryptionConfig} object using the builder. 120 * 121 * <p>Required for Room SQLite integration. 122 */ 123 @NonNull create( Long rowId, @EncryptionKeyConstants.EncryptionKeyType int encryptionKeyType, String coordinatorUrl, String keyIdentifier, String publicKey, Instant creationInstant, Long expiryTtlSeconds, Instant expiryInstant)124 public static DBProtectedServersEncryptionConfig create( 125 Long rowId, 126 @EncryptionKeyConstants.EncryptionKeyType int encryptionKeyType, 127 String coordinatorUrl, 128 String keyIdentifier, 129 String publicKey, 130 Instant creationInstant, 131 Long expiryTtlSeconds, 132 Instant expiryInstant) { 133 134 return builder() 135 .setRowId(rowId) 136 .setEncryptionKeyType(encryptionKeyType) 137 .setCoordinatorUrl(coordinatorUrl) 138 .setKeyIdentifier(keyIdentifier) 139 .setPublicKey(publicKey) 140 .setCreationInstant(creationInstant) 141 .setExpiryInstant(expiryInstant) 142 .setExpiryTtlSeconds(expiryTtlSeconds) 143 .build(); 144 } 145 146 /** Builder class for a {@link DBProtectedServersEncryptionConfig}. */ 147 @AutoValue.Builder 148 public abstract static class Builder { 149 150 /** 151 * Sets the unique ID per key record. This is different from {@link #getKeyIdentifier()} 152 * which is only unique per coordinator. 153 * 154 * <p>This ID is only used internally in the table and does not need to be stable or 155 * reproducible. It is auto-generated by Room if set to {@code null} on insertion. 156 */ setRowId(Long rowId)157 abstract Builder setRowId(Long rowId); 158 159 /** Sets encryption key tupe. */ setEncryptionKeyType( @ncryptionKeyConstants.EncryptionKeyType int encryptionKeyType)160 public abstract Builder setEncryptionKeyType( 161 @EncryptionKeyConstants.EncryptionKeyType int encryptionKeyType); 162 163 /** Identifier used to identify the encryptionKey. */ setKeyIdentifier(String keyIdentifier)164 public abstract Builder setKeyIdentifier(String keyIdentifier); 165 166 /** Sets the coordinator URL from which the key is fetched. */ setCoordinatorUrl(String coordinatorUrl)167 public abstract Builder setCoordinatorUrl(String coordinatorUrl); 168 169 /** Public key of an asymmetric key pair represented by this encryptionKey. */ setPublicKey(String publicKey)170 public abstract Builder setPublicKey(String publicKey); 171 172 /** Ttl in seconds for the EncryptionKey. */ setExpiryTtlSeconds(Long expiryTtlSeconds)173 public abstract Builder setExpiryTtlSeconds(Long expiryTtlSeconds); 174 175 /** Creation instant for the key. */ setCreationInstant(Instant creationInstant)176 public abstract Builder setCreationInstant(Instant creationInstant); 177 178 /** Expiry instant for the key. */ setExpiryInstant(Instant expiryInstant)179 abstract Builder setExpiryInstant(Instant expiryInstant); 180 getCreationInstant()181 abstract Instant getCreationInstant(); 182 getExpiryTtlSeconds()183 abstract Long getExpiryTtlSeconds(); 184 autoBuild()185 abstract DBProtectedServersEncryptionConfig autoBuild(); 186 187 /** Builds the key based on the set values after validating the input. */ build()188 public final DBProtectedServersEncryptionConfig build() { 189 // TODO(b/284445328): Set creation Instant as the instant key was fetched. 190 // This would allow accurate computation of expiry instant as fetchInstant + maxage. 191 setExpiryInstant(getCreationInstant().plusSeconds(getExpiryTtlSeconds())); 192 return autoBuild(); 193 } 194 } 195 } 196