feat: add user, system certificate in existing network security config (#3724)

* add user, system certificate in existing network security config rather than creating a fresh config

* prevent deleting existing network security config to modify the existing one

* modified test case for certificate check.

Rather than comparing exact string, parse and check if user and system certificate exist
This commit is contained in:
Sawan Garg 2024-11-17 06:02:24 +05:30 committed by GitHub
parent c2eab3101c
commit 1eb1daf12a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 78 additions and 38 deletions

View File

@ -343,12 +343,6 @@ public class ApkBuilder {
} }
File netSecConfOrig = new File(mApkDir, "res/xml/network_security_config.xml"); File netSecConfOrig = new File(mApkDir, "res/xml/network_security_config.xml");
if (netSecConfOrig.exists()) {
LOGGER.info("Replacing existing network_security_config.xml!");
//noinspection ResultOfMethodCallIgnored
netSecConfOrig.delete();
}
ResXmlPatcher.modNetworkSecurityConfig(netSecConfOrig); ResXmlPatcher.modNetworkSecurityConfig(netSecConfOrig);
ResXmlPatcher.setNetworkSecurityConfig(manifest); ResXmlPatcher.setNetworkSecurityConfig(manifest);
LOGGER.info("Added permissive network security config in manifest"); LOGGER.info("Added permissive network security config in manifest");

View File

@ -146,30 +146,59 @@ public final class ResXmlPatcher {
*/ */
public static void modNetworkSecurityConfig(File file) public static void modNetworkSecurityConfig(File file)
throws ParserConfigurationException, TransformerException, IOException, SAXException { throws ParserConfigurationException, TransformerException, IOException, SAXException {
DocumentBuilderFactory documentFactory = DocumentBuilderFactory.newInstance(); DocumentBuilderFactory documentFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentFactory.newDocumentBuilder(); DocumentBuilder documentBuilder = documentFactory.newDocumentBuilder();
Document document = documentBuilder.newDocument(); Document document;
if (file.exists()) {
document = documentBuilder.parse(file);
document.getDocumentElement().normalize();
} else {
document = documentBuilder.newDocument();
}
Element root = (Element) document.getElementsByTagName("network-security-config").item(0);
if (root == null) {
root = document.createElement("network-security-config");
document.appendChild(root);
}
Element baseConfig = (Element) document.getElementsByTagName("base-config").item(0);
if (baseConfig == null) {
baseConfig = document.createElement("base-config");
root.appendChild(baseConfig);
}
Element root = document.createElement("network-security-config"); Element trustAnchors = (Element) document.getElementsByTagName("trust-anchors").item(0);
document.appendChild(root); if (trustAnchors == null) {
Element baseConfig = document.createElement("base-config"); trustAnchors = document.createElement("trust-anchors");
root.appendChild(baseConfig); baseConfig.appendChild(trustAnchors);
Element trustAnchors = document.createElement("trust-anchors"); }
baseConfig.appendChild(trustAnchors);
Element certSystem = document.createElement("certificates"); NodeList certificates = document.getElementsByTagName("certificates");
Attr attrSystem = document.createAttribute("src"); boolean hasSystemCert = false;
attrSystem.setValue("system"); boolean hasUserCert = false;
certSystem.setAttributeNode(attrSystem); for (int i = 0; i < certificates.getLength(); i++) {
trustAnchors.appendChild(certSystem); Element cert = (Element) certificates.item(i);
String src = cert.getAttribute("src");
Element certUser = document.createElement("certificates"); if ("system".equals(src)) {
Attr attrUser = document.createAttribute("src"); hasSystemCert = true;
attrUser.setValue("user"); } else if ("user".equals(src)) {
certUser.setAttributeNode(attrUser); hasUserCert = true;
trustAnchors.appendChild(certUser); }
}
if (!hasSystemCert) {
Element certSystem = document.createElement("certificates");
certSystem.setAttribute("src", "system");
trustAnchors.appendChild(certSystem);
}
if (!hasUserCert) {
Element certUser = document.createElement("certificates");
certUser.setAttribute("src", "user");
trustAnchors.appendChild(certUser);
}
saveDocument(file, document); saveDocument(file, document);
} }

View File

@ -17,25 +17,31 @@
package brut.androlib.aapt2; package brut.androlib.aapt2;
import brut.androlib.*; import brut.androlib.*;
import brut.androlib.Config;
import brut.common.BrutException; import brut.common.BrutException;
import brut.directory.ExtFile; import brut.directory.ExtFile;
import brut.util.OS; import brut.util.OS;
import org.custommonkey.xmlunit.XMLUnit;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap; import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import java.io.*; import java.io.*;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Paths; import java.nio.file.Paths;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
import static org.junit.Assert.*; import static org.junit.Assert.*;
public class NetworkConfigTest extends BaseTest { public class NetworkConfigTest extends BaseTest {
@ -72,20 +78,31 @@ public class NetworkConfigTest extends BaseTest {
} }
@Test @Test
public void netSecConfGeneric() throws IOException, SAXException { public void netSecConfGeneric() throws IOException, SAXException, ParserConfigurationException, XPathExpressionException {
LOGGER.info("Comparing network security configuration file..."); LOGGER.info("Verifying network security configuration file contains user and system certificates...");
String expected = TestUtils.replaceNewlines("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>" +
"<network-security-config><base-config><trust-anchors><certificates src=\"system\"/><certificates src=\"us" +
"er\"/></trust-anchors></base-config></network-security-config>");
byte[] encoded = Files.readAllBytes(Paths.get(String.valueOf(sTestNewDir), "res/xml/network_security_config.xml")); byte[] encoded = Files.readAllBytes(Paths.get(String.valueOf(sTestNewDir), "res/xml/network_security_config.xml"));
String obtained = TestUtils.replaceNewlines(new String(encoded)); String obtained = new String(encoded);
XMLUnit.setIgnoreWhitespace(true); // Load the XML document
XMLUnit.setIgnoreAttributeOrder(true); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
XMLUnit.setCompareUnmatched(false); factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new ByteArrayInputStream(obtained.getBytes()));
assertXMLEqual(expected, obtained); // XPath expression to check for user and system certificates
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xpath = xPathFactory.newXPath();
// Check if 'system' certificate exists
XPathExpression systemCertExpr = xpath.compile("//certificates[@src='system']");
NodeList systemCertNodes = (NodeList) systemCertExpr.evaluate(document, XPathConstants.NODESET);
assertTrue(systemCertNodes.getLength() > 0);
// Check if 'user' certificate exists
XPathExpression userCertExpr = xpath.compile("//certificates[@src='user']");
NodeList userCertNodes = (NodeList) userCertExpr.evaluate(document, XPathConstants.NODESET);
assertTrue(userCertNodes.getLength() > 0);
} }
@Test @Test