1 /* 2 * Copyright (C) 2017 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 package com.android.internal.telephony; 17 18 import android.app.DownloadManager; 19 import android.content.Context; 20 import android.content.Intent; 21 import android.content.SharedPreferences; 22 import android.os.HandlerThread; 23 import android.os.PersistableBundle; 24 import android.telephony.CarrierConfigManager; 25 import android.telephony.ImsiEncryptionInfo; 26 import android.test.suitebuilder.annotation.SmallTest; 27 import android.util.Pair; 28 29 import com.android.org.bouncycastle.util.io.pem.PemReader; 30 31 import org.junit.After; 32 import org.junit.Before; 33 import org.junit.Test; 34 import org.mockito.Matchers; 35 import org.mockito.MockitoAnnotations; 36 37 import java.io.BufferedReader; 38 import java.io.ByteArrayInputStream; 39 import java.io.InputStreamReader; 40 import java.io.Reader; 41 import java.security.PublicKey; 42 import java.text.SimpleDateFormat; 43 import java.util.Calendar; 44 import java.util.Date; 45 import java.util.GregorianCalendar; 46 47 import static android.preference.PreferenceManager.getDefaultSharedPreferences; 48 49 import static org.junit.Assert.assertFalse; 50 import static org.junit.Assert.assertTrue; 51 import static org.junit.Assert.fail; 52 import static org.mockito.ArgumentMatchers.any; 53 import static org.mockito.Mockito.anyInt; 54 import static org.mockito.Mockito.times; 55 import static org.mockito.Mockito.verify; 56 import static org.mockito.Mockito.when; 57 58 public class CarrierKeyDownloadMgrTest extends TelephonyTest { 59 60 private static final String LOG_TAG = "CarrierKeyDownloadManager"; 61 62 private CarrierKeyDownloadManager mCarrierKeyDM; 63 private CarrierActionAgentHandler mCarrierActionAgentHandler; 64 65 private String mURL = "http://www.google.com"; 66 67 private static final String CERT = "-----BEGIN CERTIFICATE-----\r\nMIIFjzCCBHegAwIBAgIUPxj3SLif82Ky1RlUy8p2EWJCh8MwDQYJKoZIhvcNAQELBQAwgY0xCzAJBgNVBAYTAk5MMRIwEAYDVQQHEwlBbXN0ZXJkYW0xJTAjBgNVBAoTHFZlcml6b24gRW50ZXJwcmlzZSBTb2x1dGlvbnMxEzARBgNVBAsTCkN5YmVydHJ1c3QxLjAsBgNVBAMTJVZlcml6b24gUHVibGljIFN1cmVTZXJ2ZXIgQ0EgRzE0LVNIQTIwHhcNMTcwODE0MTc0MzM4WhcNMTkwODE0MTc0MzM4WjCBmTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFjAUBgNVBAcTDUJhc2tpbmcgUmlkZ2UxIjAgBgNVBAoTGVZlcml6b24gRGF0YSBTZXJ2aWNlcyBMTEMxHzAdBgNVBAsTFk5ldHdvcmsgU3lzdGVtIFN1cHBvcnQxGDAWBgNVBAMTD3ZpMWx2Lmltc3ZtLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALUQKWTHi4Hjpd1LQwJ87RXa0Rs3rVonvVevliqdUH5BikjhAzvIqwPSXeRQqkaRTFIyp0NKcNqGdjAaHRo43gdHeWSH331sS6CMZDg988gZznskzCqJJo6ii5FuLC8qe2YDsHxT+CefXev2rn6Bj1ei2X74uZsy5KlkBRZfFHtPdK6/EK5TpzrvcXfDyOK1rn8FTno1bQOTAhL39GPcLhdrXV7AN+lu+EBpdCqlTdcoDxsqavi/91MwUIVEzxJmycKloT6OWfU44r7+L5SYYgc88NTaGL/BvCFwHRIa1ZgYSGeAPes45792MGG7tfr/ttAGp9UEwTv2zWTxzWnRP/UCAwEAAaOCAdcwggHTMAwGA1UdEwEB/wQCMAAwTAYDVR0gBEUwQzBBBgkrBgEEAbE+ATIwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly9zZWN1cmUub21uaXJvb3QuY29tL3JlcG9zaXRvcnkwgakGCCsGAQUFBwEBBIGcMIGZMC0GCCsGAQUFBzABhiFodHRwOi8vdnBzc2cxNDIub2NzcC5vbW5pcm9vdC5jb20wMwYIKwYBBQUHMAKGJ2h0dHA6Ly9jYWNlcnQub21uaXJvb3QuY29tL3Zwc3NnMTQyLmNydDAzBggrBgEFBQcwAoYnaHR0cDovL2NhY2VydC5vbW5pcm9vdC5jb20vdnBzc2cxNDIuZGVyMBoGA1UdEQQTMBGCD3ZpMWx2Lmltc3ZtLmNvbTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB8GA1UdIwQYMBaAFOQtu5EBZSYftHo/oxUlpM6MRDM7MD4GA1UdHwQ3MDUwM6AxoC+GLWh0dHA6Ly92cHNzZzE0Mi5jcmwub21uaXJvb3QuY29tL3Zwc3NnMTQyLmNybDAdBgNVHQ4EFgQUv5SaSyNM/yXw1v0N9TNpjsFCaPcwDQYJKoZIhvcNAQELBQADggEBACNJusTULj1KyV4RwiskKfp4wI9Hsz3ESbZS/ijF9D57BQ0UwkELU9r6rEAhsYLUvMq4sDhDbYIdupgP4MBzFnjkKult7VQm5W3nCcuHgXYFAJ9Y1a4OZAo/4hrHj70W9TsQ1ioSMjUT4F8bDUYZI0kcyH8e/+2DaTsLUpHw3L+Keu8PsJVBLnvcKJjWrZD/Bgd6JuaTX2G84i0rY0GJuO9CxLNJa6n61Mz5cqLYIuwKgiVgTA2n71YITyFICOFPFX1vSx35AWvD6aVYblxtC8mpCdF2h4s1iyrpXeji2GCJLwsNVtTtNQ4zWX3Gnq683wzkYZeyOHUyftIgAQZ+HsY=\r\n-----END CERTIFICATE-----"; 68 69 70 private String mJsonStr = "{ \"carrier-keys\": [ { \"certificate\": \"" + CERT + "\", \"key-type\": \"WLAN\", \"key-identifier\": \"key1=value\", \"expiration-date\": 1502577746000 }, { \"certificate\": \"" + CERT + "\", \"key-type\": \"WLAN\", \"key-identifier\": \"key1=value\", \"expiration-date\": 1502577746000 }]}"; 71 72 private String mJsonStr1 = "{ \"carrier-keys\": [ { \"public-key\": \"" + CERT + "\", \"key-type\": \"WLAN\", \"key-identifier\": \"key1=value\", \"expiration-date\": 1502577746000 }, { \"public-key\": \"" + CERT + "\", \"key-type\": \"WLAN\", \"key-identifier\": \"key1=value\", \"expiration-date\": 1502577746000 }]}"; 73 74 private class CarrierActionAgentHandler extends HandlerThread { 75 76 private CarrierActionAgentHandler(String name) { 77 super(name); 78 } 79 80 @Override 81 public void onLooperPrepared() { 82 mCarrierKeyDM = new CarrierKeyDownloadManager(mPhone); 83 setReady(true); 84 } 85 } 86 87 @Before 88 public void setUp() throws Exception { 89 logd("CarrierActionAgentTest +Setup!"); 90 MockitoAnnotations.initMocks(this); 91 super.setUp(getClass().getSimpleName()); 92 mCarrierActionAgentHandler = new CarrierActionAgentHandler(getClass().getSimpleName()); 93 mCarrierActionAgentHandler.start(); 94 waitUntilReady(); 95 logd("CarrierActionAgentTest -Setup!"); 96 } 97 98 @After 99 public void tearDown() throws Exception { 100 mCarrierActionAgentHandler.quit(); 101 super.tearDown(); 102 } 103 104 /* Checks if the expiration date is calculated correctly 105 * In this case the expiration date should be the next day. 106 */ 107 @Test 108 @SmallTest 109 public void testExpirationDate1Day() { 110 java.security.PublicKey publicKey = null; 111 mCarrierKeyDM.mKeyAvailability = 3; 112 SimpleDateFormat dt = new SimpleDateFormat("yyyy-mm-dd"); 113 Calendar cal = new GregorianCalendar(); 114 cal.add(Calendar.DATE, 6); 115 Date date = cal.getTime(); 116 Calendar expectedCal = new GregorianCalendar(); 117 expectedCal.add(Calendar.DATE, 1); 118 String dateExpected = dt.format(expectedCal.getTime()); 119 ImsiEncryptionInfo imsiEncryptionInfo = new ImsiEncryptionInfo("mcc", "mnc", 1, 120 "keyIdentifier", publicKey, date); 121 when(mPhone.getCarrierInfoForImsiEncryption(anyInt())).thenReturn(imsiEncryptionInfo); 122 Date expirationDate = new Date(mCarrierKeyDM.getExpirationDate()); 123 assertTrue(dt.format(expirationDate).equals(dateExpected)); 124 } 125 126 /** 127 * Checks if the expiration date is calculated correctly 128 * In this case the expiration date should be within the window (7 to 21 days). 129 **/ 130 @Test 131 @SmallTest 132 public void testExpirationDate7Day() { 133 java.security.PublicKey publicKey = null; 134 mCarrierKeyDM.mKeyAvailability = 3; 135 SimpleDateFormat dt = new SimpleDateFormat("yyyy-mm-dd"); 136 Calendar cal = new GregorianCalendar(); 137 cal.add(Calendar.DATE, 30); 138 Date date = cal.getTime(); 139 Calendar minExpirationCal = new GregorianCalendar(); 140 Calendar maxExpirationCal = new GregorianCalendar(); 141 minExpirationCal.add(Calendar.DATE, 23); 142 maxExpirationCal.add(Calendar.DATE, 9); 143 Date minExpirationDate = minExpirationCal.getTime(); 144 Date maxExpirationDate = maxExpirationCal.getTime(); 145 ImsiEncryptionInfo imsiEncryptionInfo = new ImsiEncryptionInfo("mcc", "mnc", 1, 146 "keyIdentifier", publicKey, date); 147 when(mPhone.getCarrierInfoForImsiEncryption(anyInt())).thenReturn(imsiEncryptionInfo); 148 Date expirationDate = new Date(mCarrierKeyDM.getExpirationDate()); 149 assertTrue(expirationDate.before(minExpirationDate)); 150 assertTrue(expirationDate.after(maxExpirationDate)); 151 } 152 153 /** 154 * Checks if the json is parse correctly. 155 * Verify that setCarrierInfoForImsiEncryption is called with the right params 156 **/ 157 @Test 158 @SmallTest 159 public void testParseJson() { 160 ByteArrayInputStream certBytes = new ByteArrayInputStream(CERT.getBytes()); 161 Reader fRd = new BufferedReader(new InputStreamReader(certBytes)); 162 PemReader reader = new PemReader(fRd); 163 Pair<PublicKey, Long> keyInfo = null; 164 try { 165 keyInfo = mCarrierKeyDM.getKeyInformation(reader.readPemObject().getContent()); 166 } catch (Exception e) { 167 fail(LOG_TAG + "exception creating public key"); 168 } 169 ImsiEncryptionInfo imsiEncryptionInfo = new ImsiEncryptionInfo("310", "270", 2, 170 "key1=value", keyInfo.first, new Date(keyInfo.second)); 171 String mccMnc = "310:270"; 172 mCarrierKeyDM.parseJsonAndPersistKey(mJsonStr, mccMnc); 173 verify(mPhone, times(2)).setCarrierInfoForImsiEncryption( 174 (Matchers.refEq(imsiEncryptionInfo))); 175 } 176 177 /** 178 * Checks if the json is parse correctly. 179 * Same as testParseJason, except that the test looks for the "public-key" field. 180 **/ 181 @Test 182 @SmallTest 183 public void testParseJsonPublicKey() { 184 ByteArrayInputStream certBytes = new ByteArrayInputStream(CERT.getBytes()); 185 Reader fRd = new BufferedReader(new InputStreamReader(certBytes)); 186 PemReader reader = new PemReader(fRd); 187 Pair<PublicKey, Long> keyInfo = null; 188 try { 189 keyInfo = mCarrierKeyDM.getKeyInformation(reader.readPemObject().getContent()); 190 } catch (Exception e) { 191 fail(LOG_TAG + "exception creating public key"); 192 } 193 ImsiEncryptionInfo imsiEncryptionInfo = new ImsiEncryptionInfo("310", "270", 2, 194 "key1=value", keyInfo.first, new Date(keyInfo.second)); 195 String mccMnc = "310:270"; 196 mCarrierKeyDM.parseJsonAndPersistKey(mJsonStr1, mccMnc); 197 verify(mPhone, times(2)).setCarrierInfoForImsiEncryption( 198 (Matchers.refEq(imsiEncryptionInfo))); 199 } 200 201 /** 202 * Checks if the json is parse correctly. 203 * Since the json is bad, we want to verify that savePublicKey is not called. 204 **/ 205 @Test 206 @SmallTest 207 public void testParseBadJsonFail() { 208 String mccMnc = "310:290"; 209 String badJsonStr = "{badJsonString}"; 210 mCarrierKeyDM.parseJsonAndPersistKey(badJsonStr, mccMnc); 211 verify(mPhone, times(0)).setCarrierInfoForImsiEncryption(any()); 212 } 213 214 /** 215 * Checks if the download is valid. 216 * returns true since the mnc/mcc is valid. 217 **/ 218 @Test 219 @SmallTest 220 public void testIsValidDownload() { 221 String mccMnc = "310:260"; 222 when(mTelephonyManager.getSimOperator(anyInt())).thenReturn("310260"); 223 assertTrue(mCarrierKeyDM.isValidDownload(mccMnc)); 224 } 225 226 /** 227 * Checks if the download is valid. 228 * returns false since the mnc/mcc is in-valid. 229 **/ 230 @Test 231 @SmallTest 232 public void testIsValidDownloadFail() { 233 String mccMnc = "310:290"; 234 when(mTelephonyManager.getSimOperator(anyInt())).thenReturn("310260"); 235 assertFalse(mCarrierKeyDM.isValidDownload(mccMnc)); 236 } 237 238 /** 239 * Tests if the key is enabled. 240 * tests for all bit-mask value. 241 **/ 242 @Test 243 @SmallTest 244 public void testIsKeyEnabled() { 245 mCarrierKeyDM.mKeyAvailability = 3; 246 assertTrue(mCarrierKeyDM.isKeyEnabled(1)); 247 assertTrue(mCarrierKeyDM.isKeyEnabled(2)); 248 mCarrierKeyDM.mKeyAvailability = 2; 249 assertFalse(mCarrierKeyDM.isKeyEnabled(1)); 250 assertTrue(mCarrierKeyDM.isKeyEnabled(2)); 251 mCarrierKeyDM.mKeyAvailability = 1; 252 assertTrue(mCarrierKeyDM.isKeyEnabled(1)); 253 assertFalse(mCarrierKeyDM.isKeyEnabled(2)); 254 } 255 256 /** 257 * Tests sending the ACTION_DOWNLOAD_COMPLETE intent. 258 * Verify that the alarm will kick-off the next day. 259 **/ 260 @Test 261 @SmallTest 262 public void testDownloadComplete() { 263 SharedPreferences.Editor editor = getDefaultSharedPreferences(mContext).edit(); 264 String mccMnc = "310:260"; 265 int slotId = mPhone.getPhoneId(); 266 editor.putString("CARRIER_KEY_DM_MCC_MNC" + slotId, mccMnc); 267 editor.commit(); 268 269 SimpleDateFormat dt = new SimpleDateFormat("yyyy-mm-dd"); 270 Calendar expectedCal = new GregorianCalendar(); 271 expectedCal.add(Calendar.DATE, 1); 272 String dateExpected = dt.format(expectedCal.getTime()); 273 274 when(mTelephonyManager.getSimOperator(anyInt())).thenReturn("310260"); 275 Intent mIntent = new Intent(DownloadManager.ACTION_DOWNLOAD_COMPLETE); 276 mContext.sendBroadcast(mIntent); 277 Date expirationDate = new Date(mCarrierKeyDM.getExpirationDate()); 278 assertTrue(dt.format(expirationDate).equals(dateExpected)); 279 } 280 281 /** 282 * Test sending the ACTION_CARRIER_CONFIG_CHANGED intent. 283 * Verify that the right mnc/mcc gets stored in the preferences. 284 **/ 285 @Test 286 @SmallTest 287 public void testCarrierConfigChanged() { 288 CarrierConfigManager carrierConfigManager = (CarrierConfigManager) 289 mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); 290 int slotId = mPhone.getPhoneId(); 291 PersistableBundle bundle = carrierConfigManager.getConfigForSubId(slotId); 292 bundle.putInt(CarrierConfigManager.IMSI_KEY_AVAILABILITY_INT, 3); 293 bundle.putString(CarrierConfigManager.IMSI_KEY_DOWNLOAD_URL_STRING, mURL); 294 295 when(mTelephonyManager.getSimOperator(anyInt())).thenReturn("310260"); 296 Intent mIntent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); 297 mIntent.putExtra(PhoneConstants.PHONE_KEY, 0); 298 mContext.sendBroadcast(mIntent); 299 SharedPreferences preferences = getDefaultSharedPreferences(mContext); 300 String mccMnc = preferences.getString("CARRIER_KEY_DM_MCC_MNC" + slotId, null); 301 assertTrue(mccMnc.equals("310:260")); 302 } 303 304 /** 305 * Tests sending the INTENT_KEY_RENEWAL_ALARM_PREFIX intent. 306 * Verify that the right mnc/mcc gets stored in the preferences. 307 **/ 308 @Test 309 @SmallTest 310 public void testAlarmRenewal() { 311 CarrierConfigManager carrierConfigManager = (CarrierConfigManager) 312 mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); 313 int slotId = mPhone.getPhoneId(); 314 PersistableBundle bundle = carrierConfigManager.getConfigForSubId(slotId); 315 bundle.putInt(CarrierConfigManager.IMSI_KEY_AVAILABILITY_INT, 3); 316 bundle.putString(CarrierConfigManager.IMSI_KEY_DOWNLOAD_URL_STRING, mURL); 317 318 when(mTelephonyManager.getSimOperator(anyInt())).thenReturn("310260"); 319 Intent mIntent = new Intent("com.android.internal.telephony.carrier_key_download_alarm" 320 + slotId); 321 mContext.sendBroadcast(mIntent); 322 SharedPreferences preferences = getDefaultSharedPreferences(mContext); 323 String mccMnc = preferences.getString("CARRIER_KEY_DM_MCC_MNC" + slotId, null); 324 assertTrue(mccMnc.equals("310:260")); 325 } 326 } 327