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