1 /* 2 * Copyright (C) 2020 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.google.android.sample.rcsclient; 18 19 import android.net.Uri; 20 import android.os.Bundle; 21 import android.os.Handler; 22 import android.os.Message; 23 import android.os.PersistableBundle; 24 import android.telephony.CarrierConfigManager; 25 import android.telephony.SmsManager; 26 import android.telephony.SubscriptionManager; 27 import android.telephony.TelephonyManager; 28 import android.telephony.TelephonyManager.BootstrapAuthenticationCallback; 29 import android.telephony.gba.UaSecurityProtocolIdentifier; 30 import android.text.method.ScrollingMovementMethod; 31 import android.util.Log; 32 import android.view.MenuItem; 33 import android.view.View; 34 import android.widget.AdapterView; 35 import android.widget.AdapterView.OnItemSelectedListener; 36 import android.widget.ArrayAdapter; 37 import android.widget.Button; 38 import android.widget.EditText; 39 import android.widget.Spinner; 40 import android.widget.TextView; 41 42 import androidx.annotation.Nullable; 43 import androidx.appcompat.app.AppCompatActivity; 44 45 import java.util.Locale; 46 import java.util.concurrent.ExecutorService; 47 import java.util.concurrent.Executors; 48 49 /** An activity to verify GBA authentication. */ 50 public class GbaActivity extends AppCompatActivity { 51 52 private static final String TAG = "TestRcsApp.GbaActivity"; 53 private static final String NAF_PREFIX = "https://3GPP-bootstrapping@"; 54 55 private static final int MSG_RESULT = 1; 56 private final ExecutorService mExecutorService = Executors.newSingleThreadExecutor(); 57 private Button mGbaButton; 58 private TextView mCallbackResult; 59 private Spinner mOrganizationSpinner, mProtocolSpinner, mUiccSpinner; 60 private EditText mTlsCs; 61 private EditText mNaf; 62 private Handler mHandler; 63 private int mOrganization; 64 private int mProtocol; 65 private int mUiccType; 66 bytesToHex(byte[] bytes)67 private static String bytesToHex(byte[] bytes) { 68 StringBuilder result = new StringBuilder(); 69 for (byte aByte : bytes) { 70 result.append(String.format(Locale.US, "%02X", aByte)); 71 } 72 return result.toString(); 73 } 74 75 @Override onCreate(@ullable Bundle savedInstanceState)76 protected void onCreate(@Nullable Bundle savedInstanceState) { 77 super.onCreate(savedInstanceState); 78 setContentView(R.layout.gba_layout); 79 80 getSupportActionBar().setDisplayHomeAsUpEnabled(true); 81 getSupportActionBar().setDisplayShowHomeEnabled(true); 82 initLayout(); 83 mHandler = new Handler() { 84 public void handleMessage(Message message) { 85 switch (message.what) { 86 case MSG_RESULT: 87 mCallbackResult.setText(message.obj.toString()); 88 break; 89 } 90 } 91 }; 92 } 93 initLayout()94 private void initLayout() { 95 mGbaButton = findViewById(R.id.gba_btn); 96 mCallbackResult = findViewById(R.id.gba_result); 97 mCallbackResult.setMovementMethod(new ScrollingMovementMethod()); 98 mTlsCs = findViewById(R.id.tls_id); 99 mNaf = findViewById(R.id.naf_url); 100 101 initOrganization(); 102 initProtocol(); 103 initUicctype(); 104 105 int defaultSmsSubId = SmsManager.getDefaultSmsSubscriptionId(); 106 if (!SubscriptionManager.isValidSubscriptionId(defaultSmsSubId)) { 107 Log.i(TAG, "invalid subId:" + defaultSmsSubId); 108 return; 109 } 110 TelephonyManager telephonyManager = getSystemService( 111 TelephonyManager.class).createForSubscriptionId(defaultSmsSubId); 112 PersistableBundle carrierConfig = telephonyManager.getCarrierConfig(); 113 String uploadUrl = carrierConfig.getString( 114 CarrierConfigManager.KEY_CALL_COMPOSER_PICTURE_SERVER_URL_STRING); 115 mNaf.setText(NAF_PREFIX + uploadUrl); 116 117 mGbaButton.setOnClickListener(view -> { 118 Log.i(TAG, "trigger bootstrapAuthenticationRequest"); 119 UaSecurityProtocolIdentifier.Builder builder = 120 new UaSecurityProtocolIdentifier.Builder(); 121 try { 122 builder.setOrg(mOrganization) 123 .setProtocol(mProtocol) 124 .setTlsCipherSuite(Integer.parseInt(mTlsCs.getText().toString())); 125 } catch (IllegalArgumentException e) { 126 Log.e(TAG, e.getMessage()); 127 return; 128 } 129 UaSecurityProtocolIdentifier spId = builder.build(); 130 telephonyManager.bootstrapAuthenticationRequest(mUiccType, 131 Uri.parse(mNaf.getText().toString()), 132 spId, 133 true, 134 mExecutorService, 135 new BootstrapAuthenticationCallback() { 136 @Override 137 public void onKeysAvailable(byte[] gbaKey, String btId) { 138 String result = "OnKeysAvailable key:" + bytesToHex(gbaKey) 139 + "\r\n btId:" + btId; 140 Log.i(TAG, result); 141 mHandler.sendMessage(mHandler.obtainMessage(MSG_RESULT, result)); 142 } 143 144 @Override 145 public void onAuthenticationFailure(int reason) { 146 String result = "OnAuthenticationFailure reason: " + reason; 147 Log.i(TAG, result); 148 mHandler.sendMessage(mHandler.obtainMessage(MSG_RESULT, result)); 149 } 150 }); 151 }); 152 } 153 initOrganization()154 private void initOrganization() { 155 mOrganizationSpinner = findViewById(R.id.organization_list); 156 ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, 157 R.array.organization, android.R.layout.simple_spinner_item); 158 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 159 mOrganizationSpinner.setAdapter(adapter); 160 mOrganizationSpinner.setOnItemSelectedListener(new OnItemSelectedListener() { 161 @Override 162 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { 163 Log.i(TAG, "Organization position:" + position); 164 switch (position) { 165 case 0: 166 mOrganization = UaSecurityProtocolIdentifier.ORG_NONE; 167 break; 168 case 1: 169 mOrganization = UaSecurityProtocolIdentifier.ORG_3GPP; 170 break; 171 case 2: 172 mOrganization = UaSecurityProtocolIdentifier.ORG_3GPP2; 173 break; 174 case 3: 175 mOrganization = UaSecurityProtocolIdentifier.ORG_GSMA; 176 break; 177 case 4: 178 mOrganization = UaSecurityProtocolIdentifier.ORG_LOCAL; 179 break; 180 default: 181 Log.e(TAG, "invalid position:" + position); 182 } 183 } 184 185 @Override 186 public void onNothingSelected(AdapterView<?> parent) { 187 // TODO Auto-generated method stub 188 } 189 }); 190 mOrganizationSpinner.setSelection(1); 191 } 192 initProtocol()193 private void initProtocol() { 194 mProtocolSpinner = findViewById(R.id.protocol_list); 195 ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, 196 R.array.protocol, android.R.layout.simple_spinner_item); 197 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 198 mProtocolSpinner.setAdapter(adapter); 199 mProtocolSpinner.setOnItemSelectedListener(new OnItemSelectedListener() { 200 @Override 201 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { 202 Log.i(TAG, "Protocol position:" + position); 203 switch (position) { 204 case 0: 205 mProtocol = UaSecurityProtocolIdentifier 206 .UA_SECURITY_PROTOCOL_3GPP_SUBSCRIBER_CERTIFICATE; 207 break; 208 case 1: 209 mProtocol = UaSecurityProtocolIdentifier 210 .UA_SECURITY_PROTOCOL_3GPP_MBMS; 211 break; 212 case 2: 213 mProtocol = UaSecurityProtocolIdentifier 214 .UA_SECURITY_PROTOCOL_3GPP_HTTP_DIGEST_AUTHENTICATION; 215 break; 216 case 3: 217 mProtocol = UaSecurityProtocolIdentifier 218 .UA_SECURITY_PROTOCOL_3GPP_HTTP_BASED_MBMS; 219 break; 220 case 4: 221 mProtocol = UaSecurityProtocolIdentifier 222 .UA_SECURITY_PROTOCOL_3GPP_SIP_BASED_MBMS; 223 break; 224 case 5: 225 mProtocol = UaSecurityProtocolIdentifier 226 .UA_SECURITY_PROTOCOL_3GPP_GENERIC_PUSH_LAYER; 227 break; 228 case 6: 229 mProtocol = UaSecurityProtocolIdentifier 230 .UA_SECURITY_PROTOCOL_3GPP_IMS_MEDIA_PLANE; 231 break; 232 case 7: 233 mProtocol = UaSecurityProtocolIdentifier 234 .UA_SECURITY_PROTOCOL_3GPP_GENERATION_TMPI; 235 break; 236 case 8: 237 mProtocol = UaSecurityProtocolIdentifier 238 .UA_SECURITY_PROTOCOL_3GPP_TLS_DEFAULT; 239 break; 240 case 9: 241 mProtocol = UaSecurityProtocolIdentifier 242 .UA_SECURITY_PROTOCOL_3GPP_TLS_BROWSER; 243 break; 244 default: 245 Log.e(TAG, "invalid position:" + position); 246 } 247 } 248 249 @Override 250 public void onNothingSelected(AdapterView<?> parent) { 251 // TODO Auto-generated method stub 252 } 253 }); 254 mProtocolSpinner.setSelection(8); 255 } 256 initUicctype()257 private void initUicctype() { 258 mUiccSpinner = findViewById(R.id.uicc_list); 259 ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, 260 R.array.uicc_type, android.R.layout.simple_spinner_item); 261 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 262 mUiccSpinner.setAdapter(adapter); 263 mUiccSpinner.setOnItemSelectedListener(new OnItemSelectedListener() { 264 @Override 265 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { 266 Log.i(TAG, "uicc position:" + position); 267 switch (position) { 268 case 0: 269 mUiccType = TelephonyManager.APPTYPE_UNKNOWN; 270 break; 271 case 1: 272 mUiccType = TelephonyManager.APPTYPE_SIM; 273 break; 274 case 2: 275 mUiccType = TelephonyManager.APPTYPE_USIM; 276 break; 277 case 3: 278 mUiccType = TelephonyManager.APPTYPE_RUIM; 279 break; 280 case 4: 281 mUiccType = TelephonyManager.APPTYPE_CSIM; 282 break; 283 case 5: 284 mUiccType = TelephonyManager.APPTYPE_ISIM; 285 break; 286 default: 287 Log.e(TAG, "invalid position:" + position); 288 } 289 } 290 291 @Override 292 public void onNothingSelected(AdapterView<?> parent) { 293 // TODO Auto-generated method stub 294 } 295 }); 296 mUiccSpinner.setSelection(5); 297 } 298 299 @Override onOptionsItemSelected(MenuItem item)300 public boolean onOptionsItemSelected(MenuItem item) { 301 if (item.getItemId() == android.R.id.home) { 302 finish(); 303 } 304 return super.onOptionsItemSelected(item); 305 } 306 } 307