Loading services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java +28 −4 Original line number Diff line number Diff line Loading @@ -16,6 +16,10 @@ package com.android.server.integrity.serializer; import static com.android.server.integrity.serializer.RuleIndexingDetails.APP_CERTIFICATE_INDEXED; import static com.android.server.integrity.serializer.RuleIndexingDetails.NOT_INDEXED; import static com.android.server.integrity.serializer.RuleIndexingDetails.PACKAGE_NAME_INDEXED; import android.content.integrity.AtomicFormula; import android.content.integrity.CompoundFormula; import android.content.integrity.Formula; Loading @@ -29,6 +33,7 @@ import java.io.OutputStream; import java.io.StringWriter; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; import java.util.Optional; /** A helper class to serialize rules from the {@link Rule} model to Xml representation. */ Loading Loading @@ -75,13 +80,32 @@ public class RuleXmlSerializer implements RuleSerializer { } } private void serializeRules(List<Rule> rules, XmlSerializer xmlSerializer) throws IOException { private void serializeRules(List<Rule> rules, XmlSerializer xmlSerializer) throws RuleSerializeException { try { // Determine the indexing groups and the order of the rules within each indexed group. Map<Integer, List<Rule>> indexedRules = RuleIndexingDetailsIdentifier.splitRulesIntoIndexBuckets(rules); // Write the XML formatted rules in order. xmlSerializer.startTag(NAMESPACE, RULE_LIST_TAG); serializeRuleList(indexedRules.get(PACKAGE_NAME_INDEXED), xmlSerializer); serializeRuleList(indexedRules.get(APP_CERTIFICATE_INDEXED), xmlSerializer); serializeRuleList(indexedRules.get(NOT_INDEXED), xmlSerializer); xmlSerializer.endTag(NAMESPACE, RULE_LIST_TAG); xmlSerializer.endDocument(); } catch (Exception e) { throw new RuleSerializeException(e.getMessage(), e); } } private void serializeRuleList(List<Rule> rules, XmlSerializer xmlSerializer) throws IOException { for (Rule rule : rules) { serializeRule(rule, xmlSerializer); } xmlSerializer.endTag(NAMESPACE, RULE_LIST_TAG); xmlSerializer.endDocument(); } private void serializeRule(Rule rule, XmlSerializer xmlSerializer) throws IOException { Loading services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java +163 −27 Original line number Diff line number Diff line Loading @@ -44,48 +44,66 @@ import java.util.Optional; @RunWith(JUnit4.class) public class RuleXmlSerializerTest { private static final String SAMPLE_INSTALLER_NAME = "com.test.installer"; private static final String SAMPLE_INSTALLER_CERT = "installer_cert"; @Test public void testXmlString_serializeEmptyRule() throws Exception { Rule rule = null; public void testXmlString_serializeEmptyRuleList() throws Exception { RuleSerializer xmlSerializer = new RuleXmlSerializer(); String expectedRules = "<RL />"; byte[] actualRules = xmlSerializer.serialize( Collections.singletonList(rule), /* formatVersion= */ Optional.empty()); Collections.emptyList(), /* formatVersion= */ Optional.empty()); assertEquals(expectedRules, new String(actualRules, StandardCharsets.UTF_8)); } @Test public void testXmlString_serializeMultipleRules_oneEmpty() throws Exception { Rule rule1 = null; Rule rule2 = public void testXmlString_serializeMultipleRules_indexingOrderPreserved() throws Exception { String packageNameA = "aaa"; String packageNameB = "bbb"; String packageNameC = "ccc"; String appCert1 = "cert1"; String appCert2 = "cert2"; String appCert3 = "cert3"; Rule installerRule = new Rule( new CompoundFormula( CompoundFormula.AND, Arrays.asList( new AtomicFormula.StringAtomicFormula( AtomicFormula.PACKAGE_NAME, "com.app.test", AtomicFormula.INSTALLER_NAME, SAMPLE_INSTALLER_NAME, /* isHashedValue= */ false), new AtomicFormula.StringAtomicFormula( AtomicFormula.INSTALLER_CERTIFICATE, SAMPLE_INSTALLER_CERT, /* isHashedValue= */ false))), Rule.DENY); RuleSerializer xmlSerializer = new RuleXmlSerializer(); Map<String, String> packageNameAttrs = new LinkedHashMap<>(); packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME)); packageNameAttrs.put("V", "com.app.test"); packageNameAttrs.put("H", "false"); String expectedRules = "<RL>" + generateTagWithAttribute( /* tag= */ "R", Collections.singletonMap("E", String.valueOf(Rule.DENY)), /* closed= */ false) + generateTagWithAttribute( /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</R>" + "</RL>"; RuleSerializer xmlSerializer = new RuleXmlSerializer(); byte[] actualRules = xmlSerializer.serialize( Arrays.asList(rule1, rule2), /* formatVersion= */ Optional.empty()); Arrays.asList( installerRule, getRuleWithAppCertificateAndSampleInstallerName(appCert1), getRuleWithPackageNameAndSampleInstallerName(packageNameB), getRuleWithAppCertificateAndSampleInstallerName(appCert3), getRuleWithPackageNameAndSampleInstallerName(packageNameC), getRuleWithAppCertificateAndSampleInstallerName(appCert2), getRuleWithPackageNameAndSampleInstallerName(packageNameA)), /* formatVersion= */ Optional.empty()); String expectedRules = "<RL>" + getSerializedCompoundRuleWithPackageNameAndSampleInstallerName(packageNameA) + getSerializedCompoundRuleWithPackageNameAndSampleInstallerName(packageNameB) + getSerializedCompoundRuleWithPackageNameAndSampleInstallerName(packageNameC) + getSerializedCompoundRuleWithAppCertificateAndSampleInstallerName(appCert1) + getSerializedCompoundRuleWithAppCertificateAndSampleInstallerName(appCert2) + getSerializedCompoundRuleWithAppCertificateAndSampleInstallerName(appCert3) + getSerializedCompoundRuleWithSampleInstallerNameAndCert() + "</RL>"; assertEquals(expectedRules, new String(actualRules, StandardCharsets.UTF_8)); } Loading Loading @@ -371,7 +389,7 @@ public class RuleXmlSerializerTest { assertExpectException( RuleSerializeException.class, /* expectedExceptionMessageRegex */ "Invalid formula type", /* expectedExceptionMessageRegex */ "Malformed rule identified.", () -> xmlSerializer.serialize( Collections.singletonList(rule), Loading @@ -393,6 +411,124 @@ public class RuleXmlSerializerTest { return res.toString(); } private Rule getRuleWithPackageNameAndSampleInstallerName(String packageName) { return new Rule( new CompoundFormula( CompoundFormula.AND, Arrays.asList( new AtomicFormula.StringAtomicFormula( AtomicFormula.PACKAGE_NAME, packageName, /* isHashedValue= */ false), new AtomicFormula.StringAtomicFormula( AtomicFormula.INSTALLER_NAME, SAMPLE_INSTALLER_NAME, /* isHashedValue= */ false))), Rule.DENY); } private String getSerializedCompoundRuleWithPackageNameAndSampleInstallerName( String packageName) { Map<String, String> packageNameAttrs = new LinkedHashMap<>(); packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME)); packageNameAttrs.put("V", packageName); packageNameAttrs.put("H", "false"); Map<String, String> installerNameAttrs = new LinkedHashMap<>(); installerNameAttrs.put("K", String.valueOf(AtomicFormula.INSTALLER_NAME)); installerNameAttrs.put("V", SAMPLE_INSTALLER_NAME); installerNameAttrs.put("H", "false"); return generateTagWithAttribute( /* tag= */ "R", Collections.singletonMap("E", String.valueOf(Rule.DENY)), /* closed= */ false) + generateTagWithAttribute( /* tag= */ "OF", Collections.singletonMap("C", String.valueOf(CompoundFormula.AND)), /* closed= */ false) + generateTagWithAttribute( /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + generateTagWithAttribute( /* tag= */ "AF", installerNameAttrs, /* closed= */ true) + "</OF>" + "</R>"; } private Rule getRuleWithAppCertificateAndSampleInstallerName(String certificate) { return new Rule( new CompoundFormula( CompoundFormula.AND, Arrays.asList( new AtomicFormula.StringAtomicFormula( AtomicFormula.APP_CERTIFICATE, certificate, /* isHashedValue= */ false), new AtomicFormula.StringAtomicFormula( AtomicFormula.INSTALLER_NAME, SAMPLE_INSTALLER_NAME, /* isHashedValue= */ false))), Rule.DENY); } private String getSerializedCompoundRuleWithAppCertificateAndSampleInstallerName( String appCert) { Map<String, String> packageNameAttrs = new LinkedHashMap<>(); packageNameAttrs.put("K", String.valueOf(AtomicFormula.APP_CERTIFICATE)); packageNameAttrs.put("V", appCert); packageNameAttrs.put("H", "false"); Map<String, String> installerNameAttrs = new LinkedHashMap<>(); installerNameAttrs.put("K", String.valueOf(AtomicFormula.INSTALLER_NAME)); installerNameAttrs.put("V", SAMPLE_INSTALLER_NAME); installerNameAttrs.put("H", "false"); return generateTagWithAttribute( /* tag= */ "R", Collections.singletonMap("E", String.valueOf(Rule.DENY)), /* closed= */ false) + generateTagWithAttribute( /* tag= */ "OF", Collections.singletonMap("C", String.valueOf(CompoundFormula.AND)), /* closed= */ false) + generateTagWithAttribute( /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + generateTagWithAttribute( /* tag= */ "AF", installerNameAttrs, /* closed= */ true) + "</OF>" + "</R>"; } private String getSerializedCompoundRuleWithSampleInstallerNameAndCert() { Map<String, String> installerNameAttrs = new LinkedHashMap<>(); installerNameAttrs.put("K", String.valueOf(AtomicFormula.INSTALLER_NAME)); installerNameAttrs.put("V", SAMPLE_INSTALLER_NAME); installerNameAttrs.put("H", "false"); Map<String, String> installerCertAttrs = new LinkedHashMap<>(); installerCertAttrs.put("K", String.valueOf(AtomicFormula.INSTALLER_CERTIFICATE)); installerCertAttrs.put("V", SAMPLE_INSTALLER_CERT); installerCertAttrs.put("H", "false"); return generateTagWithAttribute( /* tag= */ "R", Collections.singletonMap("E", String.valueOf(Rule.DENY)), /* closed= */ false) + generateTagWithAttribute( /* tag= */ "OF", Collections.singletonMap("C", String.valueOf(CompoundFormula.AND)), /* closed= */ false) + generateTagWithAttribute( /* tag= */ "AF", installerNameAttrs, /* closed= */ true) + generateTagWithAttribute( /* tag= */ "AF", installerCertAttrs, /* closed= */ true) + "</OF>" + "</R>"; } private Formula getInvalidFormula() { return new Formula() { @Override Loading Loading
services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java +28 −4 Original line number Diff line number Diff line Loading @@ -16,6 +16,10 @@ package com.android.server.integrity.serializer; import static com.android.server.integrity.serializer.RuleIndexingDetails.APP_CERTIFICATE_INDEXED; import static com.android.server.integrity.serializer.RuleIndexingDetails.NOT_INDEXED; import static com.android.server.integrity.serializer.RuleIndexingDetails.PACKAGE_NAME_INDEXED; import android.content.integrity.AtomicFormula; import android.content.integrity.CompoundFormula; import android.content.integrity.Formula; Loading @@ -29,6 +33,7 @@ import java.io.OutputStream; import java.io.StringWriter; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; import java.util.Optional; /** A helper class to serialize rules from the {@link Rule} model to Xml representation. */ Loading Loading @@ -75,13 +80,32 @@ public class RuleXmlSerializer implements RuleSerializer { } } private void serializeRules(List<Rule> rules, XmlSerializer xmlSerializer) throws IOException { private void serializeRules(List<Rule> rules, XmlSerializer xmlSerializer) throws RuleSerializeException { try { // Determine the indexing groups and the order of the rules within each indexed group. Map<Integer, List<Rule>> indexedRules = RuleIndexingDetailsIdentifier.splitRulesIntoIndexBuckets(rules); // Write the XML formatted rules in order. xmlSerializer.startTag(NAMESPACE, RULE_LIST_TAG); serializeRuleList(indexedRules.get(PACKAGE_NAME_INDEXED), xmlSerializer); serializeRuleList(indexedRules.get(APP_CERTIFICATE_INDEXED), xmlSerializer); serializeRuleList(indexedRules.get(NOT_INDEXED), xmlSerializer); xmlSerializer.endTag(NAMESPACE, RULE_LIST_TAG); xmlSerializer.endDocument(); } catch (Exception e) { throw new RuleSerializeException(e.getMessage(), e); } } private void serializeRuleList(List<Rule> rules, XmlSerializer xmlSerializer) throws IOException { for (Rule rule : rules) { serializeRule(rule, xmlSerializer); } xmlSerializer.endTag(NAMESPACE, RULE_LIST_TAG); xmlSerializer.endDocument(); } private void serializeRule(Rule rule, XmlSerializer xmlSerializer) throws IOException { Loading
services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java +163 −27 Original line number Diff line number Diff line Loading @@ -44,48 +44,66 @@ import java.util.Optional; @RunWith(JUnit4.class) public class RuleXmlSerializerTest { private static final String SAMPLE_INSTALLER_NAME = "com.test.installer"; private static final String SAMPLE_INSTALLER_CERT = "installer_cert"; @Test public void testXmlString_serializeEmptyRule() throws Exception { Rule rule = null; public void testXmlString_serializeEmptyRuleList() throws Exception { RuleSerializer xmlSerializer = new RuleXmlSerializer(); String expectedRules = "<RL />"; byte[] actualRules = xmlSerializer.serialize( Collections.singletonList(rule), /* formatVersion= */ Optional.empty()); Collections.emptyList(), /* formatVersion= */ Optional.empty()); assertEquals(expectedRules, new String(actualRules, StandardCharsets.UTF_8)); } @Test public void testXmlString_serializeMultipleRules_oneEmpty() throws Exception { Rule rule1 = null; Rule rule2 = public void testXmlString_serializeMultipleRules_indexingOrderPreserved() throws Exception { String packageNameA = "aaa"; String packageNameB = "bbb"; String packageNameC = "ccc"; String appCert1 = "cert1"; String appCert2 = "cert2"; String appCert3 = "cert3"; Rule installerRule = new Rule( new CompoundFormula( CompoundFormula.AND, Arrays.asList( new AtomicFormula.StringAtomicFormula( AtomicFormula.PACKAGE_NAME, "com.app.test", AtomicFormula.INSTALLER_NAME, SAMPLE_INSTALLER_NAME, /* isHashedValue= */ false), new AtomicFormula.StringAtomicFormula( AtomicFormula.INSTALLER_CERTIFICATE, SAMPLE_INSTALLER_CERT, /* isHashedValue= */ false))), Rule.DENY); RuleSerializer xmlSerializer = new RuleXmlSerializer(); Map<String, String> packageNameAttrs = new LinkedHashMap<>(); packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME)); packageNameAttrs.put("V", "com.app.test"); packageNameAttrs.put("H", "false"); String expectedRules = "<RL>" + generateTagWithAttribute( /* tag= */ "R", Collections.singletonMap("E", String.valueOf(Rule.DENY)), /* closed= */ false) + generateTagWithAttribute( /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</R>" + "</RL>"; RuleSerializer xmlSerializer = new RuleXmlSerializer(); byte[] actualRules = xmlSerializer.serialize( Arrays.asList(rule1, rule2), /* formatVersion= */ Optional.empty()); Arrays.asList( installerRule, getRuleWithAppCertificateAndSampleInstallerName(appCert1), getRuleWithPackageNameAndSampleInstallerName(packageNameB), getRuleWithAppCertificateAndSampleInstallerName(appCert3), getRuleWithPackageNameAndSampleInstallerName(packageNameC), getRuleWithAppCertificateAndSampleInstallerName(appCert2), getRuleWithPackageNameAndSampleInstallerName(packageNameA)), /* formatVersion= */ Optional.empty()); String expectedRules = "<RL>" + getSerializedCompoundRuleWithPackageNameAndSampleInstallerName(packageNameA) + getSerializedCompoundRuleWithPackageNameAndSampleInstallerName(packageNameB) + getSerializedCompoundRuleWithPackageNameAndSampleInstallerName(packageNameC) + getSerializedCompoundRuleWithAppCertificateAndSampleInstallerName(appCert1) + getSerializedCompoundRuleWithAppCertificateAndSampleInstallerName(appCert2) + getSerializedCompoundRuleWithAppCertificateAndSampleInstallerName(appCert3) + getSerializedCompoundRuleWithSampleInstallerNameAndCert() + "</RL>"; assertEquals(expectedRules, new String(actualRules, StandardCharsets.UTF_8)); } Loading Loading @@ -371,7 +389,7 @@ public class RuleXmlSerializerTest { assertExpectException( RuleSerializeException.class, /* expectedExceptionMessageRegex */ "Invalid formula type", /* expectedExceptionMessageRegex */ "Malformed rule identified.", () -> xmlSerializer.serialize( Collections.singletonList(rule), Loading @@ -393,6 +411,124 @@ public class RuleXmlSerializerTest { return res.toString(); } private Rule getRuleWithPackageNameAndSampleInstallerName(String packageName) { return new Rule( new CompoundFormula( CompoundFormula.AND, Arrays.asList( new AtomicFormula.StringAtomicFormula( AtomicFormula.PACKAGE_NAME, packageName, /* isHashedValue= */ false), new AtomicFormula.StringAtomicFormula( AtomicFormula.INSTALLER_NAME, SAMPLE_INSTALLER_NAME, /* isHashedValue= */ false))), Rule.DENY); } private String getSerializedCompoundRuleWithPackageNameAndSampleInstallerName( String packageName) { Map<String, String> packageNameAttrs = new LinkedHashMap<>(); packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME)); packageNameAttrs.put("V", packageName); packageNameAttrs.put("H", "false"); Map<String, String> installerNameAttrs = new LinkedHashMap<>(); installerNameAttrs.put("K", String.valueOf(AtomicFormula.INSTALLER_NAME)); installerNameAttrs.put("V", SAMPLE_INSTALLER_NAME); installerNameAttrs.put("H", "false"); return generateTagWithAttribute( /* tag= */ "R", Collections.singletonMap("E", String.valueOf(Rule.DENY)), /* closed= */ false) + generateTagWithAttribute( /* tag= */ "OF", Collections.singletonMap("C", String.valueOf(CompoundFormula.AND)), /* closed= */ false) + generateTagWithAttribute( /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + generateTagWithAttribute( /* tag= */ "AF", installerNameAttrs, /* closed= */ true) + "</OF>" + "</R>"; } private Rule getRuleWithAppCertificateAndSampleInstallerName(String certificate) { return new Rule( new CompoundFormula( CompoundFormula.AND, Arrays.asList( new AtomicFormula.StringAtomicFormula( AtomicFormula.APP_CERTIFICATE, certificate, /* isHashedValue= */ false), new AtomicFormula.StringAtomicFormula( AtomicFormula.INSTALLER_NAME, SAMPLE_INSTALLER_NAME, /* isHashedValue= */ false))), Rule.DENY); } private String getSerializedCompoundRuleWithAppCertificateAndSampleInstallerName( String appCert) { Map<String, String> packageNameAttrs = new LinkedHashMap<>(); packageNameAttrs.put("K", String.valueOf(AtomicFormula.APP_CERTIFICATE)); packageNameAttrs.put("V", appCert); packageNameAttrs.put("H", "false"); Map<String, String> installerNameAttrs = new LinkedHashMap<>(); installerNameAttrs.put("K", String.valueOf(AtomicFormula.INSTALLER_NAME)); installerNameAttrs.put("V", SAMPLE_INSTALLER_NAME); installerNameAttrs.put("H", "false"); return generateTagWithAttribute( /* tag= */ "R", Collections.singletonMap("E", String.valueOf(Rule.DENY)), /* closed= */ false) + generateTagWithAttribute( /* tag= */ "OF", Collections.singletonMap("C", String.valueOf(CompoundFormula.AND)), /* closed= */ false) + generateTagWithAttribute( /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + generateTagWithAttribute( /* tag= */ "AF", installerNameAttrs, /* closed= */ true) + "</OF>" + "</R>"; } private String getSerializedCompoundRuleWithSampleInstallerNameAndCert() { Map<String, String> installerNameAttrs = new LinkedHashMap<>(); installerNameAttrs.put("K", String.valueOf(AtomicFormula.INSTALLER_NAME)); installerNameAttrs.put("V", SAMPLE_INSTALLER_NAME); installerNameAttrs.put("H", "false"); Map<String, String> installerCertAttrs = new LinkedHashMap<>(); installerCertAttrs.put("K", String.valueOf(AtomicFormula.INSTALLER_CERTIFICATE)); installerCertAttrs.put("V", SAMPLE_INSTALLER_CERT); installerCertAttrs.put("H", "false"); return generateTagWithAttribute( /* tag= */ "R", Collections.singletonMap("E", String.valueOf(Rule.DENY)), /* closed= */ false) + generateTagWithAttribute( /* tag= */ "OF", Collections.singletonMap("C", String.valueOf(CompoundFormula.AND)), /* closed= */ false) + generateTagWithAttribute( /* tag= */ "AF", installerNameAttrs, /* closed= */ true) + generateTagWithAttribute( /* tag= */ "AF", installerCertAttrs, /* closed= */ true) + "</OF>" + "</R>"; } private Formula getInvalidFormula() { return new Formula() { @Override Loading