Loading services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertUtils.java +53 −46 Original line number Diff line number Diff line Loading @@ -16,13 +16,17 @@ package com.android.server.locksettings.recoverablekeystore.certificate; import static javax.xml.xpath.XPathConstants.NODESET; import android.annotation.IntDef; import android.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; Loading @@ -40,7 +44,6 @@ import java.security.cert.CertPathBuilderException; import java.security.cert.CertPathValidator; import java.security.cert.CertPathValidatorException; import java.security.cert.CertStore; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.CollectionCertStoreParameters; Loading @@ -58,15 +61,6 @@ import java.util.Set; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; /** Utility functions related to parsing and validating public-key certificates. */ public final class CertUtils { Loading Loading @@ -167,50 +161,63 @@ public final class CertUtils { static List<String> getXmlNodeContents(@MustExist int mustExist, Element rootNode, String... nodeTags) throws CertParsingException { String expression = String.join("/", nodeTags); XPath xPath = XPathFactory.newInstance().newXPath(); NodeList nodeList; try { nodeList = (NodeList) xPath.compile(expression).evaluate(rootNode, NODESET); } catch (XPathExpressionException e) { throw new CertParsingException(e); if (nodeTags.length == 0) { throw new CertParsingException("The tag list must not be empty"); } // Go down through all the intermediate node tags (except the last tag for the leaf nodes). // Note that this implementation requires that at most one path exists for the given // intermediate node tags. Element parent = rootNode; for (int i = 0; i < nodeTags.length - 1; i++) { String tag = nodeTags[i]; List<Element> children = getXmlDirectChildren(parent, tag); if ((children.size() == 0 && mustExist != MUST_EXIST_UNENFORCED) || children.size() > 1) { throw new CertParsingException( "The XML file must contain exactly one path with the tag " + tag); } if (children.size() == 0) { return new ArrayList<>(); } parent = children.get(0); } switch (mustExist) { case MUST_EXIST_UNENFORCED: break; case MUST_EXIST_EXACTLY_ONE: if (nodeList.getLength() != 1) { // Then collect the contents of the leaf nodes. List<Element> leafs = getXmlDirectChildren(parent, nodeTags[nodeTags.length - 1]); if (mustExist == MUST_EXIST_EXACTLY_ONE && leafs.size() != 1) { throw new CertParsingException( "The XML file must contain exactly one node with the path " + expression); + String.join("/", nodeTags)); } break; case MUST_EXIST_AT_LEAST_ONE: if (nodeList.getLength() == 0) { if (mustExist == MUST_EXIST_AT_LEAST_ONE && leafs.size() == 0) { throw new CertParsingException( "The XML file must contain at least one node with the path " + expression); + String.join("/", nodeTags)); } break; default: throw new UnsupportedOperationException( "This value of MustExist is not supported: " + mustExist); } List<String> result = new ArrayList<>(); for (int i = 0; i < nodeList.getLength(); i++) { Node node = nodeList.item(i); for (Element leaf : leafs) { // Remove whitespaces and newlines. result.add(node.getTextContent().replaceAll("\\s", "")); result.add(leaf.getTextContent().replaceAll("\\s", "")); } return result; } /** Get the direct child nodes with a given tag. */ private static List<Element> getXmlDirectChildren(Element parent, String tag) { // Cannot use Element.getElementsByTagName because it will return all descendant elements // with the tag name, i.e. not only the direct child nodes. List<Element> children = new ArrayList<>(); NodeList childNodes = parent.getChildNodes(); for (int i = 0; i < childNodes.getLength(); i++) { Node node = childNodes.item(i); if (node.getNodeType() == Node.ELEMENT_NODE && node.getNodeName().equals(tag)) { children.add((Element) node); } } return children; } /** * Decodes a base64-encoded string. * Loading Loading
services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertUtils.java +53 −46 Original line number Diff line number Diff line Loading @@ -16,13 +16,17 @@ package com.android.server.locksettings.recoverablekeystore.certificate; import static javax.xml.xpath.XPathConstants.NODESET; import android.annotation.IntDef; import android.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; Loading @@ -40,7 +44,6 @@ import java.security.cert.CertPathBuilderException; import java.security.cert.CertPathValidator; import java.security.cert.CertPathValidatorException; import java.security.cert.CertStore; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.CollectionCertStoreParameters; Loading @@ -58,15 +61,6 @@ import java.util.Set; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; /** Utility functions related to parsing and validating public-key certificates. */ public final class CertUtils { Loading Loading @@ -167,50 +161,63 @@ public final class CertUtils { static List<String> getXmlNodeContents(@MustExist int mustExist, Element rootNode, String... nodeTags) throws CertParsingException { String expression = String.join("/", nodeTags); XPath xPath = XPathFactory.newInstance().newXPath(); NodeList nodeList; try { nodeList = (NodeList) xPath.compile(expression).evaluate(rootNode, NODESET); } catch (XPathExpressionException e) { throw new CertParsingException(e); if (nodeTags.length == 0) { throw new CertParsingException("The tag list must not be empty"); } // Go down through all the intermediate node tags (except the last tag for the leaf nodes). // Note that this implementation requires that at most one path exists for the given // intermediate node tags. Element parent = rootNode; for (int i = 0; i < nodeTags.length - 1; i++) { String tag = nodeTags[i]; List<Element> children = getXmlDirectChildren(parent, tag); if ((children.size() == 0 && mustExist != MUST_EXIST_UNENFORCED) || children.size() > 1) { throw new CertParsingException( "The XML file must contain exactly one path with the tag " + tag); } if (children.size() == 0) { return new ArrayList<>(); } parent = children.get(0); } switch (mustExist) { case MUST_EXIST_UNENFORCED: break; case MUST_EXIST_EXACTLY_ONE: if (nodeList.getLength() != 1) { // Then collect the contents of the leaf nodes. List<Element> leafs = getXmlDirectChildren(parent, nodeTags[nodeTags.length - 1]); if (mustExist == MUST_EXIST_EXACTLY_ONE && leafs.size() != 1) { throw new CertParsingException( "The XML file must contain exactly one node with the path " + expression); + String.join("/", nodeTags)); } break; case MUST_EXIST_AT_LEAST_ONE: if (nodeList.getLength() == 0) { if (mustExist == MUST_EXIST_AT_LEAST_ONE && leafs.size() == 0) { throw new CertParsingException( "The XML file must contain at least one node with the path " + expression); + String.join("/", nodeTags)); } break; default: throw new UnsupportedOperationException( "This value of MustExist is not supported: " + mustExist); } List<String> result = new ArrayList<>(); for (int i = 0; i < nodeList.getLength(); i++) { Node node = nodeList.item(i); for (Element leaf : leafs) { // Remove whitespaces and newlines. result.add(node.getTextContent().replaceAll("\\s", "")); result.add(leaf.getTextContent().replaceAll("\\s", "")); } return result; } /** Get the direct child nodes with a given tag. */ private static List<Element> getXmlDirectChildren(Element parent, String tag) { // Cannot use Element.getElementsByTagName because it will return all descendant elements // with the tag name, i.e. not only the direct child nodes. List<Element> children = new ArrayList<>(); NodeList childNodes = parent.getChildNodes(); for (int i = 0; i < childNodes.getLength(); i++) { Node node = childNodes.item(i); if (node.getNodeType() == Node.ELEMENT_NODE && node.getNodeName().equals(tag)) { children.add((Element) node); } } return children; } /** * Decodes a base64-encoded string. * Loading