• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.download;
18 
19 import static com.android.adservices.service.common.JsonUtils.getStringFromJson;
20 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__ENCRYPTION_KEYS_INCORRECT_JSON_VERSION;
21 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__ENCRYPTION_KEYS_JSON_PARSING_ERROR;
22 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__COMMON;
23 
24 import android.net.Uri;
25 
26 import com.android.adservices.LoggerFactory;
27 import com.android.adservices.errorlogging.ErrorLogUtil;
28 import com.android.adservices.service.encryptionkey.EncryptionKey;
29 
30 import org.json.JSONException;
31 import org.json.JSONObject;
32 
33 import java.util.Locale;
34 import java.util.Optional;
35 import java.util.UUID;
36 
37 /** Util class to convert JSON string to {@link EncryptionKey} based on version. */
38 public final class EncryptionKeyConverterUtil {
39     private static final LoggerFactory.Logger LOGGER = LoggerFactory.getLogger();
40     private static final int VERSION_3 = 3;
41 
42     private static final String KEY_TYPE_KEY = "keyType";
43     private static final String ENROLLMENT_ID_KEY = "enrollmentId";
44     private static final String REPORTING_ORIGIN_KEY = "reportingOrigin";
45     private static final String ENCRYPTION_KEY_URL_KEY = "encryptionKeyUrl";
46     private static final String PROTOCOL_TYPE_KEY = "protocolType";
47     private static final String KEY_ID_KEY = "keyId";
48     private static final String BODY_KEY = "body";
49     private static final String EXPIRATION_KEY = "expiration";
50     private static final String VERSION_KEY = "version";
51 
52     /**
53      * Converts {@link JSONObject} to the corresponding {@link EncryptionKey}.
54      *
55      * <p>Returns {@link Optional#empty()} if conversion fails.
56      */
createEncryptionKeyFromJson(JSONObject jsonObject)57     static Optional<EncryptionKey> createEncryptionKeyFromJson(JSONObject jsonObject) {
58         try {
59             if (jsonObject.has(VERSION_KEY)) {
60                 // Only version 3 is supported.
61                 int version = jsonObject.getInt(VERSION_KEY);
62                 if (version == VERSION_3) {
63                     return convertVersion3Key(jsonObject);
64                 } else {
65                     ErrorLogUtil.e(
66                             AD_SERVICES_ERROR_REPORTED__ERROR_CODE__ENCRYPTION_KEYS_INCORRECT_JSON_VERSION,
67                             AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__COMMON);
68                     LOGGER.d("Unsupported encryption key version %d", version);
69                 }
70             }
71         } catch (JSONException e) {
72             ErrorLogUtil.e(
73                     e,
74                     AD_SERVICES_ERROR_REPORTED__ERROR_CODE__ENCRYPTION_KEYS_JSON_PARSING_ERROR,
75                     AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__COMMON);
76         }
77         return Optional.empty();
78     }
79 
80     /** Converts version 3 {@link JSONObject} to the corresponding {@link EncryptionKey}. */
convertVersion3Key(JSONObject jsonObject)81     private static Optional<EncryptionKey> convertVersion3Key(JSONObject jsonObject) {
82         /* Expected Version 3 JSON example:
83          * { "keyType": "Signing", "enrollmentId": "TEST0", "reportingOrigin":
84          * "https://adtech.example.com/reporting", "encryptionKeyUrl":
85          * "https://adtech.example.com/keys/fetch/98765", "protocolType": "ECDSA", "keyId": 98765,
86          * "body": "MIIBCgKCAQEAwVACPi9w23nBqQn+BTdRSmYXZGUtIuEhJhTVUZCmYR
87          * +BNdKaIbMnzj2nXmG7nXkJaWUYnmRRhk2XnTKSWbMVzpEtqSIrGxuZUXH9DQ
88          * +3VJXO0BQvScj9KQVcrKPpTZeJrAjj8aS8FmI2+tQvSwFUJNQvPgOODYtveSZVC5YH+kIWC2LSFJQYrGBqDf
89          * +IqhQPjwFUO4T7NUzl7++YigOzMOgAoO5+SxWGOjPNsWt26CkGNzYv+8IfeYZJG3LQs+38dhCSG1qA==",
90          * "expiration": 1682516522000, "version": 3 }
91          */
92         try {
93             EncryptionKey.Builder builder = new EncryptionKey.Builder();
94             // Generate UUID for this key
95             builder.setId(UUID.randomUUID().toString());
96             builder.setKeyType(
97                     EncryptionKey.KeyType.valueOf(
98                             getStringFromJson(jsonObject, KEY_TYPE_KEY)
99                                     .toUpperCase(Locale.ENGLISH)));
100             builder.setEnrollmentId(getStringFromJson(jsonObject, ENROLLMENT_ID_KEY));
101             builder.setReportingOrigin(
102                     Uri.parse(getStringFromJson(jsonObject, REPORTING_ORIGIN_KEY)));
103             builder.setEncryptionKeyUrl(getStringFromJson(jsonObject, ENCRYPTION_KEY_URL_KEY));
104             builder.setProtocolType(
105                     EncryptionKey.ProtocolType.valueOf(
106                             getStringFromJson(jsonObject, PROTOCOL_TYPE_KEY)
107                                     .toUpperCase(Locale.ENGLISH)));
108             builder.setKeyCommitmentId(jsonObject.getInt(KEY_ID_KEY));
109             builder.setBody(getStringFromJson(jsonObject, BODY_KEY));
110             builder.setExpiration(jsonObject.getLong(EXPIRATION_KEY));
111             builder.setLastFetchTime(System.currentTimeMillis());
112 
113             EncryptionKey encryptionKey = builder.build();
114             LOGGER.v(
115                     "Successfully built EncryptionKey = %s for enrollment id = %s",
116                     encryptionKey.getBody(), encryptionKey.getEnrollmentId());
117             return Optional.of(encryptionKey);
118         } catch (JSONException | IllegalArgumentException e) {
119             LOGGER.e(e, "Failed parsing for %s", jsonObject);
120             ErrorLogUtil.e(
121                     e,
122                     AD_SERVICES_ERROR_REPORTED__ERROR_CODE__ENCRYPTION_KEYS_JSON_PARSING_ERROR,
123                     AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__COMMON);
124             return Optional.empty();
125         }
126     }
127 }
128