blob: 9f710b4a8b8ba47dd055748e8ae30e3ec2ffae1a [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.remoteprovisioner.unittest;
import static android.hardware.security.keymint.SecurityLevel.STRONGBOX;
import static android.hardware.security.keymint.SecurityLevel.TRUSTED_ENVIRONMENT;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.security.keymint.DeviceInfo;
import android.hardware.security.keymint.ProtectedData;
import android.os.Build;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.security.IGenerateRkpKeyService.Status;
import android.security.remoteprovisioning.IRemoteProvisioning;
import android.security.remoteprovisioning.ImplInfo;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.runner.AndroidJUnit4;
import com.android.remoteprovisioner.CborUtils;
import com.android.remoteprovisioner.GeekResponse;
import com.android.remoteprovisioner.ProvisionerMetrics;
import com.android.remoteprovisioner.RemoteProvisioningException;
import com.android.remoteprovisioner.ServerInterface;
import com.android.remoteprovisioner.SettingsManager;
import com.android.remoteprovisioner.SystemInterface;
import org.junit.After;
import org.junit.Assume;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.List;
import co.nstant.in.cbor.model.Map;
import co.nstant.in.cbor.model.UnicodeString;
@RunWith(AndroidJUnit4.class)
public class KeyRegisteredTest {
private static final String SERVICE = "android.security.remoteprovisioning";
private static Context sContext;
private static IRemoteProvisioning sBinder;
private static int sCurve;
private static int sCurveStrongbox;
@BeforeClass
public static void init() throws Exception {
sContext = ApplicationProvider.getApplicationContext();
sBinder = IRemoteProvisioning.Stub.asInterface(ServiceManager.getService(SERVICE));
assertNotNull(sBinder);
ImplInfo[] info = sBinder.getImplementationInfo();
for (int i = 0; i < info.length; i++) {
if (info[i].secLevel == TRUSTED_ENVIRONMENT) {
sCurve = info[i].supportedCurve;
break;
}
}
if (isStrongBoxSupported()) {
for (int i = 0; i < info.length; i++) {
if (info[i].secLevel == STRONGBOX) {
sCurveStrongbox = info[i].supportedCurve;
break;
}
}
}
}
@Before
public void setUp() throws Exception {
Assume.assumeFalse(SystemProperties.getBoolean(
"persist.device_config.remote_key_provisioning_native.enable_rkpd", false));
sBinder.deleteAllKeys();
}
@After
public void tearDown() throws Exception {
sBinder.deleteAllKeys();
}
private void requestCerts(int numKeys, int secLevel, byte[] geekChain, byte[] challenge,
IRemoteProvisioning binder, Context context,
ProvisionerMetrics metrics) throws Exception {
DeviceInfo deviceInfo = new DeviceInfo();
ProtectedData protectedData = new ProtectedData();
byte[] macedKeysToSign = SystemInterface.generateCsr(SettingsManager.isTestMode(), numKeys,
secLevel, geekChain, challenge, protectedData, deviceInfo, binder, metrics);
String fingerprint = Build.FINGERPRINT;
// The backend should provision test certs if the build isn't a user build.
// Registration status only factors into user builds, so set a debug property that
// will instruct the underlying provisioning code to appear as a user build to the
// backend if it isn't.
if (!Build.TYPE.equals("user")) {
fingerprint = fingerprint.replace("userdebug", "user");
fingerprint = fingerprint.replace("eng", "user");
}
Map unverifiedDeviceInfo = new Map();
unverifiedDeviceInfo.put(new UnicodeString("fingerprint"),
new UnicodeString(fingerprint));
byte[] certificateRequest =
CborUtils.buildCertificateRequest(deviceInfo.deviceInfo,
challenge,
protectedData.protectedData,
macedKeysToSign,
unverifiedDeviceInfo);
List<byte[]> certChains = ServerInterface.requestSignedCertificates(context,
certificateRequest, challenge, metrics);
}
@Test
public void testKeyRegisteredTee() throws Exception {
try {
ProvisionerMetrics metrics = ProvisionerMetrics.createScheduledAttemptMetrics(sContext);
int numTestKeys = 1;
sBinder.generateKeyPair(SettingsManager.isTestMode(), TRUSTED_ENVIRONMENT);
GeekResponse geek = ServerInterface.fetchGeek(sContext, metrics);
assertNotNull(geek);
requestCerts(numTestKeys, TRUSTED_ENVIRONMENT, geek.getGeekChain(sCurve),
geek.getChallenge(), sBinder, sContext, metrics);
} catch (RemoteProvisioningException e) {
// Any exception will be a failure here, but specifically call out DEVICE_NOT_REGISTERED
// as a registration failure before throwing whatever other problem may have occurred.
assertNotEquals("Device isn't registered.",
Status.DEVICE_NOT_REGISTERED, e.getErrorCode());
throw e;
}
}
@Test
public void testKeyRegisteredStrongbox() throws Exception {
if (!isStrongBoxSupported()) {
return;
}
try {
ProvisionerMetrics metrics = ProvisionerMetrics.createScheduledAttemptMetrics(sContext);
int numTestKeys = 1;
sBinder.generateKeyPair(SettingsManager.isTestMode(), STRONGBOX);
GeekResponse geek = ServerInterface.fetchGeek(sContext, metrics);
assertNotNull(geek);
requestCerts(numTestKeys, STRONGBOX, geek.getGeekChain(sCurveStrongbox),
geek.getChallenge(), sBinder, sContext, metrics);
} catch (RemoteProvisioningException e) {
// Any exception will be a failure here, but specifically call out DEVICE_NOT_REGISTERED
// as a registration failure before throwing whatever other problem may have occurred.
assertNotEquals("Device isn't registered.",
Status.DEVICE_NOT_REGISTERED, e.getErrorCode());
throw e;
}
}
private static boolean isStrongBoxSupported() {
return sContext.getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_STRONGBOX_KEYSTORE);
}
}