diff options
author | Seth Moore <sethmo@google.com> | 2022-04-20 15:51:43 -0700 |
---|---|---|
committer | Seth Moore <sethmo@google.com> | 2022-04-20 17:17:45 -0700 |
commit | b476b7a6e248b9207ab08a11b88b60ea17031b42 (patch) | |
tree | c5adf6ca04fef69b057b311f72cf58868fa6dd62 | |
parent | 7497fdaee137addab5dec77912189eb325fc1336 (diff) | |
download | RemoteProvisioner-b476b7a6e248b9207ab08a11b88b60ea17031b42.tar.gz |
Add test to verify "device not registered" RKP behavior
This additional test finishes up coverage of the API changes around
retry on rkp-only devices by ensuring unregistered devices correctly
recognize the response from the RKP backend and do not retry.
Bug: 227306369
Test: RemoteProvisionerUnitTests
Change-Id: I6097c9c96a7aa9b4c5ef2ce5c2655aad42d7137d
-rw-r--r-- | tests/unittests/Android.bp | 1 | ||||
-rw-r--r-- | tests/unittests/src/com/android/remoteprovisioner/unittest/ServerToSystemTest.java | 88 |
2 files changed, 89 insertions, 0 deletions
diff --git a/tests/unittests/Android.bp b/tests/unittests/Android.bp index 2aafdc7..9364cea 100644 --- a/tests/unittests/Android.bp +++ b/tests/unittests/Android.bp @@ -22,6 +22,7 @@ android_test { "androidx.test.core", "androidx.test.rules", "android.security.remoteprovisioning-java", + "libnanohttpd", "platform-test-annotations", "ub-uiautomator", "cbor-java", diff --git a/tests/unittests/src/com/android/remoteprovisioner/unittest/ServerToSystemTest.java b/tests/unittests/src/com/android/remoteprovisioner/unittest/ServerToSystemTest.java index 924caff..047d888 100644 --- a/tests/unittests/src/com/android/remoteprovisioner/unittest/ServerToSystemTest.java +++ b/tests/unittests/src/com/android/remoteprovisioner/unittest/ServerToSystemTest.java @@ -31,11 +31,13 @@ import android.os.ParcelFileDescriptor; import android.os.ServiceManager; import android.os.SystemProperties; import android.security.KeyStoreException; +import android.security.NetworkSecurityPolicy; import android.security.keystore.KeyGenParameterSpec; import android.security.remoteprovisioning.AttestationPoolStatus; import android.security.remoteprovisioning.IRemoteProvisioning; import android.security.remoteprovisioning.ImplInfo; import android.system.keystore2.ResponseCode; +import android.util.Base64; import androidx.test.core.app.ApplicationProvider; import androidx.test.platform.app.InstrumentationRegistry; @@ -54,6 +56,7 @@ import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.security.KeyPairGenerator; import java.security.KeyStore; @@ -62,6 +65,8 @@ import java.security.cert.Certificate; import java.time.Duration; import java.util.Arrays; +import fi.iki.elonen.NanoHTTPD; + @RunWith(AndroidJUnit4.class) public class ServerToSystemTest { @@ -69,6 +74,26 @@ public class ServerToSystemTest { private static final String SERVICE = "android.security.remoteprovisioning"; private static final String RKP_ONLY_PROP = "remote_provisioning.tee.rkp_only"; + private static final byte[] GEEK_RESPONSE = Base64.decode( + "g4KCAYOEQ6EBJqBYTaUBAgMmIAEhWCD3FIrbl/TMU+/SZBHE43UfZh+kcQxsz/oJRoB0h1TyrSJY" + + "IF5/W/bs5PYZzP8TN/0PociT2xgGdsRd5tdqd4bDLa+PWEAvl45C+74HLZVHhUeTQLAf1JtHpMRE" + + "qfKhB4cQx5/LEfS/n+g74Oc0TBX8e8N+MwX00TQ87QIEYHoV4HnTiv8khEOhASagWE2lAQIDJiAB" + + "IVggUYCsz4+WjOwPUOGpG7eQhjSL48OsZQJNtPYxDghGMjkiWCBU65Sd/ra05HM6JU4vH52dvfpm" + + "wRGL6ZaMQ+Qw9tp2q1hAmDj7NDpl23OYsSeiFXTyvgbnjSJO3fC/wgF0xLcpayQctdjSZvpE7/Uw" + + "LAR07ejGYNrOn1ZXJ3Qh096Tj+O4zYRDoQEmoFhxpgECAlggg5/4/RAcEp+SQcdbjeRO9BkTmscb" + + "bacOlfJkU12nHcEDOBggASFYIBakUhJjs4ZWUNjf8qCofbzZbqdoYOqMXPGT5ZcZDazeIlggib7M" + + "bD9esDk0r5e6ONEWHaHMHWTTjEhO+HKBGzs+Me5YQPrazy2rpTAMc8Xlq0mSWWBE+sTyM+UEsmwZ" + + "ZOkc42Q7NIYAZS313a+qAcmvg8lO+FqU6GWTUeMYHjmAp2lLM82CAoOEQ6EBJ6BYKqQBAQMnIAYh" + + "WCCZue7dXuRS9oXGTGLcPmGrV0h9dTcprXaAMtKzy2NY2VhAHiIIS6S3pMjXTgMO/rivFEynO2+l" + + "zdzaecYrZP6ZOa9254D6ZgCFDQeYKqyRXKclFEkGNHXKiid62eNaSesCA4RDoQEnoFgqpAEBAycg" + + "BiFYIOovhQ6eagxc973Z+igyv9pV6SCiUQPJA5MYzqAVKezRWECCa8ddpjZXt8dxEq0cwmqzLCMq" + + "3RQwy4IUtonF0x4xu7hQIUpJTbqRDG8zTYO8WCsuhNvFWQ+YYeLB6ony0K4EhEOhASegWE6lAQEC" + + "WCBvktEEbXHYp46I2NFWgV+W0XiD5jAbh+2/INFKO/5qLgM4GCAEIVggtl0cS5qDOp21FVk3oSb7" + + "D9/nnKwB1aTsyDopAIhYJTlYQICyn9Aynp1K/rAl8sLSImhGxiCwqugWrGShRYObzElUJX+rFgVT" + + "8L01k/PGu1lOXvneIQcUo7ako4uPgpaWugNYHQAAAYBINcxrASC0rWP9VTSO7LdABvcdkv7W2vh+" + + "onV0aW1lX3RvX3JlZnJlc2hfaG91cnMYSHgabnVtX2V4dHJhX2F0dGVzdGF0aW9uX2tleXMU", + Base64.DEFAULT); + private static Context sContext; private static IRemoteProvisioning sBinder; private static int sCurve = 0; @@ -257,4 +282,67 @@ public class ServerToSystemTest { setAirplaneMode(false); } } + + @Test + public void testRetryNeverWhenDeviceNotRegistered() throws Exception { + final NanoHTTPD server = new NanoHTTPD("localhost", 0) { + @Override + public Response serve(IHTTPSession session) { + // We must consume all bytes in the request, else they get interpreted as a + // sepearate (bad) request by the HTTP server. + consumeRequestBody((HTTPSession) session); + if (session.getUri().contains(":fetchEekChain")) { + return newFixedLengthResponse(Response.Status.OK, "application/cbor", + new ByteArrayInputStream(GEEK_RESPONSE), GEEK_RESPONSE.length); + } else if (session.getUri().contains(":signCertificates")) { + Response.IStatus status = new Response.IStatus() { + @Override + public String getDescription() { + return "444 Device Not Registered"; + } + + @Override + public int getRequestStatus() { + return 444; + } + }; + return newFixedLengthResponse(status, NanoHTTPD.MIME_PLAINTEXT, + "device not registered"); + } + Assert.fail("Unexpected HTTP request: " + session.getUri()); + return null; + } + + void consumeRequestBody(HTTPSession session) { + try { + session.getInputStream().readNBytes((int) session.getBodySize()); + } catch (IOException e) { + Assert.fail("Error reading request bytes: " + e.toString()); + } + } + }; + server.start(NanoHTTPD.SOCKET_READ_TIMEOUT, false); + + final boolean cleartextPolicy = + NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted(); + NetworkSecurityPolicy.getInstance().setCleartextTrafficPermitted(true); + SettingsManager.setDeviceConfig(sContext, 1 /* extraKeys */, mDuration /* expiringBy */, + "http://localhost:" + server.getListeningPort() + "/"); + + try (ForceRkpOnlyContext c = new ForceRkpOnlyContext()) { + assertPoolStatus(0, 0, 0, 0, mDuration); + generateKeyStoreKey("should-never-succeed"); + Assert.fail("Expected a keystore exception"); + } catch (ProviderException e) { + Assert.assertTrue(e.getCause() instanceof KeyStoreException); + KeyStoreException keyStoreException = (KeyStoreException) e.getCause(); + Assert.assertEquals(ResponseCode.OUT_OF_KEYS, keyStoreException.getErrorCode()); + Assert.assertFalse(keyStoreException.isTransientFailure()); + Assert.assertEquals(KeyStoreException.RETRY_NEVER, keyStoreException.getRetryPolicy()); + } finally { + NetworkSecurityPolicy.getInstance().setCleartextTrafficPermitted(cleartextPolicy); + SettingsManager.clearPreferences(sContext); + server.stop(); + } + } } |