From 1eb1daf12acadffcc45b56b9eeca7e9905d0e40b Mon Sep 17 00:00:00 2001 From: Sawan Garg Date: Sun, 17 Nov 2024 06:02:24 +0530 Subject: [PATCH] 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 --- .../main/java/brut/androlib/ApkBuilder.java | 6 -- .../brut/androlib/res/xml/ResXmlPatcher.java | 67 +++++++++++++------ .../androlib/aapt2/NetworkConfigTest.java | 43 ++++++++---- 3 files changed, 78 insertions(+), 38 deletions(-) diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkBuilder.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkBuilder.java index e4376045..8ebd6b04 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkBuilder.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkBuilder.java @@ -343,12 +343,6 @@ public class ApkBuilder { } 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.setNetworkSecurityConfig(manifest); LOGGER.info("Added permissive network security config in manifest"); diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/xml/ResXmlPatcher.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/xml/ResXmlPatcher.java index cc7951b2..1914dde2 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/xml/ResXmlPatcher.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/xml/ResXmlPatcher.java @@ -146,30 +146,59 @@ public final class ResXmlPatcher { */ public static void modNetworkSecurityConfig(File file) throws ParserConfigurationException, TransformerException, IOException, SAXException { - DocumentBuilderFactory documentFactory = DocumentBuilderFactory.newInstance(); 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"); - document.appendChild(root); - Element baseConfig = document.createElement("base-config"); - root.appendChild(baseConfig); - Element trustAnchors = document.createElement("trust-anchors"); - baseConfig.appendChild(trustAnchors); + Element trustAnchors = (Element) document.getElementsByTagName("trust-anchors").item(0); + if (trustAnchors == null) { + trustAnchors = document.createElement("trust-anchors"); + baseConfig.appendChild(trustAnchors); + } - Element certSystem = document.createElement("certificates"); - Attr attrSystem = document.createAttribute("src"); - attrSystem.setValue("system"); - certSystem.setAttributeNode(attrSystem); - trustAnchors.appendChild(certSystem); - - Element certUser = document.createElement("certificates"); - Attr attrUser = document.createAttribute("src"); - attrUser.setValue("user"); - certUser.setAttributeNode(attrUser); - trustAnchors.appendChild(certUser); + NodeList certificates = document.getElementsByTagName("certificates"); + boolean hasSystemCert = false; + boolean hasUserCert = false; + for (int i = 0; i < certificates.getLength(); i++) { + Element cert = (Element) certificates.item(i); + String src = cert.getAttribute("src"); + if ("system".equals(src)) { + hasSystemCert = true; + } else if ("user".equals(src)) { + hasUserCert = true; + } + } + 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); } diff --git a/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt2/NetworkConfigTest.java b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt2/NetworkConfigTest.java index f9789bc1..0c4a25ed 100644 --- a/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt2/NetworkConfigTest.java +++ b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt2/NetworkConfigTest.java @@ -17,25 +17,31 @@ package brut.androlib.aapt2; import brut.androlib.*; -import brut.androlib.Config; import brut.common.BrutException; import brut.directory.ExtFile; import brut.util.OS; -import org.custommonkey.xmlunit.XMLUnit; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; +import org.w3c.dom.NodeList; import org.xml.sax.SAXException; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; 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.nio.file.Files; import java.nio.file.Paths; -import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; import static org.junit.Assert.*; public class NetworkConfigTest extends BaseTest { @@ -72,20 +78,31 @@ public class NetworkConfigTest extends BaseTest { } @Test - public void netSecConfGeneric() throws IOException, SAXException { - LOGGER.info("Comparing network security configuration file..."); - String expected = TestUtils.replaceNewlines("" + - ""); + public void netSecConfGeneric() throws IOException, SAXException, ParserConfigurationException, XPathExpressionException { + LOGGER.info("Verifying network security configuration file contains user and system certificates..."); 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); - XMLUnit.setIgnoreAttributeOrder(true); - XMLUnit.setCompareUnmatched(false); + // Load the XML document + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + 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