diff options
27 files changed, 2654 insertions, 0 deletions
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertParsingException.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertParsingException.java new file mode 100644 index 000000000000..57a3d992f0a9 --- /dev/null +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertParsingException.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.locksettings.recoverablekeystore.certificate; + +/** Exception thrown when parsing errors occur. */ +public class CertParsingException extends Exception { + + public CertParsingException(String message) { + super(message); + } + + public CertParsingException(Exception cause) { + super(cause); + } + + public CertParsingException(String message, Exception cause) { + super(message, cause); + } +} diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertUtils.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertUtils.java new file mode 100644 index 000000000000..985f5b61dc31 --- /dev/null +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertUtils.java @@ -0,0 +1,351 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.locksettings.recoverablekeystore.certificate; + +import static javax.xml.xpath.XPathConstants.NODESET; + +import android.annotation.Nullable; + +import com.android.internal.annotations.VisibleForTesting; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.cert.CertPath; +import java.security.cert.CertPathBuilder; +import java.security.cert.CertPathBuilderException; +import java.security.cert.CertPathValidator; +import java.security.cert.CertPathValidatorException; +import java.security.cert.CertStore; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.CollectionCertStoreParameters; +import java.security.cert.PKIXBuilderParameters; +import java.security.cert.PKIXParameters; +import java.security.cert.TrustAnchor; +import java.security.cert.X509CertSelector; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Base64; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +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. */ +final class CertUtils { + + private static final String CERT_FORMAT = "X.509"; + private static final String CERT_PATH_ALG = "PKIX"; + private static final String CERT_STORE_ALG = "Collection"; + private static final String SIGNATURE_ALG = "SHA256withRSA"; + + private CertUtils() {} + + enum MustExist { + FALSE, + EXACTLY_ONE, + AT_LEAST_ONE, + } + + /** + * Decodes a byte array containing an encoded X509 certificate. + * + * @param certBytes the byte array containing the encoded X509 certificate + * @return the decoded X509 certificate + * @throws CertParsingException if any parsing error occurs + */ + static X509Certificate decodeCert(byte[] certBytes) throws CertParsingException { + return decodeCert(new ByteArrayInputStream(certBytes)); + } + + /** + * Decodes an X509 certificate from an {@code InputStream}. + * + * @param inStream the input stream containing the encoded X509 certificate + * @return the decoded X509 certificate + * @throws CertParsingException if any parsing error occurs + */ + static X509Certificate decodeCert(InputStream inStream) throws CertParsingException { + CertificateFactory certFactory; + try { + certFactory = CertificateFactory.getInstance(CERT_FORMAT); + } catch (CertificateException e) { + // Should not happen, as X.509 is mandatory for all providers. + throw new RuntimeException(e); + } + try { + return (X509Certificate) certFactory.generateCertificate(inStream); + } catch (CertificateException e) { + throw new CertParsingException(e); + } + } + + /** + * Parses a byte array as the content of an XML file, and returns the root node of the XML file. + * + * @param xmlBytes the byte array that is the XML file content + * @return the root node of the XML file + * @throws CertParsingException if any parsing error occurs + */ + static Element getXmlRootNode(byte[] xmlBytes) throws CertParsingException { + try { + Document document = + DocumentBuilderFactory.newInstance() + .newDocumentBuilder() + .parse(new ByteArrayInputStream(xmlBytes)); + document.getDocumentElement().normalize(); + return document.getDocumentElement(); + } catch (SAXException | ParserConfigurationException | IOException e) { + throw new CertParsingException(e); + } + } + + /** + * Gets the text contents of certain XML child nodes, given a XML root node and a list of tags + * representing the path to locate the child nodes. The whitespaces and newlines in the text + * contents are stripped away. + * + * <p>For example, the list of tags [tag1, tag2, tag3] represents the XML tree like the + * following: + * + * <pre> + * <root> + * <tag1> + * <tag2> + * <tag3>abc</tag3> + * <tag3>def</tag3> + * </tag2> + * </tag1> + * <root> + * </pre> + * + * @param mustExist whether and how many nodes must exist. If the number of child nodes does not + * satisfy the requirement, CertParsingException will be thrown. + * @param rootNode the root node that serves as the starting point to locate the child nodes + * @param nodeTags the list of tags representing the relative path from the root node + * @return a list of strings that are the text contents of the child nodes + * @throws CertParsingException if any parsing error occurs + */ + static List<String> getXmlNodeContents(MustExist 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); + } + + switch (mustExist) { + case FALSE: + break; + + case EXACTLY_ONE: + if (nodeList.getLength() != 1) { + throw new CertParsingException( + "The XML file must contain exactly one node with the path " + + expression); + } + break; + + case AT_LEAST_ONE: + if (nodeList.getLength() == 0) { + throw new CertParsingException( + "The XML file must contain at least one node with the path " + + expression); + } + break; + + default: + throw new UnsupportedOperationException( + "This enum 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); + // Remove whitespaces and newlines. + result.add(node.getTextContent().replaceAll("\\s", "")); + } + return result; + } + + /** + * Decodes a base64-encoded string. + * + * @param str the base64-encoded string + * @return the decoding decoding result + * @throws CertParsingException if the input string is not a properly base64-encoded string + */ + static byte[] decodeBase64(String str) throws CertParsingException { + try { + return Base64.getDecoder().decode(str); + } catch (IllegalArgumentException e) { + throw new CertParsingException(e); + } + } + + /** + * Verifies a public-key signature that is computed by RSA with SHA256. + * + * @param signerPublicKey the public key of the original signer + * @param signature the public-key signature + * @param signedBytes the bytes that have been signed + * @throws CertValidationException if the signature verification fails + */ + static void verifyRsaSha256Signature( + PublicKey signerPublicKey, byte[] signature, byte[] signedBytes) + throws CertValidationException { + Signature verifier; + try { + verifier = Signature.getInstance(SIGNATURE_ALG); + } catch (NoSuchAlgorithmException e) { + // Should not happen, as SHA256withRSA is mandatory for all providers. + throw new RuntimeException(e); + } + try { + verifier.initVerify(signerPublicKey); + verifier.update(signedBytes); + if (!verifier.verify(signature)) { + throw new CertValidationException("The signature is invalid"); + } + } catch (InvalidKeyException | SignatureException e) { + throw new CertValidationException(e); + } + } + + /** + * Validates a leaf certificate, and returns the certificate path if the certificate is valid. + * If the given validation date is null, the current date will be used. + * + * @param validationDate the date for which the validity of the certificate should be + * determined + * @param trustedRoot the certificate of the trusted root CA + * @param intermediateCerts the list of certificates of possible intermediate CAs + * @param leafCert the leaf certificate that is to be validated + * @return the certificate path if the leaf cert is valid + * @throws CertValidationException if {@code leafCert} is invalid (e.g., is expired, or has + * invalid signature) + */ + static CertPath validateCert( + @Nullable Date validationDate, + X509Certificate trustedRoot, + List<X509Certificate> intermediateCerts, + X509Certificate leafCert) + throws CertValidationException { + PKIXParameters pkixParams = + buildPkixParams(validationDate, trustedRoot, intermediateCerts, leafCert); + CertPath certPath = buildCertPath(pkixParams); + + CertPathValidator certPathValidator; + try { + certPathValidator = CertPathValidator.getInstance(CERT_PATH_ALG); + } catch (NoSuchAlgorithmException e) { + // Should not happen, as PKIX is mandatory for all providers. + throw new RuntimeException(e); + } + try { + certPathValidator.validate(certPath, pkixParams); + } catch (CertPathValidatorException | InvalidAlgorithmParameterException e) { + throw new CertValidationException(e); + } + return certPath; + } + + @VisibleForTesting + static CertPath buildCertPath(PKIXParameters pkixParams) throws CertValidationException { + CertPathBuilder certPathBuilder; + try { + certPathBuilder = CertPathBuilder.getInstance(CERT_PATH_ALG); + } catch (NoSuchAlgorithmException e) { + // Should not happen, as PKIX is mandatory for all providers. + throw new RuntimeException(e); + } + try { + return certPathBuilder.build(pkixParams).getCertPath(); + } catch (CertPathBuilderException | InvalidAlgorithmParameterException e) { + throw new CertValidationException(e); + } + } + + @VisibleForTesting + static PKIXParameters buildPkixParams( + @Nullable Date validationDate, + X509Certificate trustedRoot, + List<X509Certificate> intermediateCerts, + X509Certificate leafCert) + throws CertValidationException { + // Create a TrustAnchor from the trusted root certificate. + Set<TrustAnchor> trustedAnchors = new HashSet<>(); + trustedAnchors.add(new TrustAnchor(trustedRoot, null)); + + // Create a CertStore from the list of intermediate certificates. + List<X509Certificate> certs = new ArrayList<>(intermediateCerts); + certs.add(leafCert); + CertStore certStore; + try { + certStore = + CertStore.getInstance(CERT_STORE_ALG, new CollectionCertStoreParameters(certs)); + } catch (NoSuchAlgorithmException e) { + // Should not happen, as Collection is mandatory for all providers. + throw new RuntimeException(e); + } catch (InvalidAlgorithmParameterException e) { + throw new CertValidationException(e); + } + + // Create a CertSelector from the leaf certificate. + X509CertSelector certSelector = new X509CertSelector(); + certSelector.setCertificate(leafCert); + + // Build a PKIXParameters from TrustAnchor, CertStore, and CertSelector. + PKIXBuilderParameters pkixParams; + try { + pkixParams = new PKIXBuilderParameters(trustedAnchors, certSelector); + } catch (InvalidAlgorithmParameterException e) { + throw new CertValidationException(e); + } + pkixParams.addCertStore(certStore); + + // If validationDate is null, the current time will be used. + pkixParams.setDate(validationDate); + pkixParams.setRevocationEnabled(false); + + return pkixParams; + } +} diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertValidationException.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertValidationException.java new file mode 100644 index 000000000000..99a9ff7e537a --- /dev/null +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertValidationException.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.locksettings.recoverablekeystore.certificate; + +/** Exception thrown when validation or verification fails. */ +public class CertValidationException extends Exception { + + public CertValidationException(String message) { + super(message); + } + + public CertValidationException(Exception cause) { + super(cause); + } + + public CertValidationException(String message, Exception cause) { + super(message, cause); + } +} diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertXml.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertXml.java new file mode 100644 index 000000000000..2c04a861abb6 --- /dev/null +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertXml.java @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.locksettings.recoverablekeystore.certificate; + +import android.annotation.Nullable; + +import com.android.internal.annotations.VisibleForTesting; + +import java.security.SecureRandom; +import java.security.cert.CertPath; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +import org.w3c.dom.Element; + +/** + * Parses and holds the XML file containing the list of THM public-key certificates and related + * metadata. + */ +public final class CertXml { + + private static final String METADATA_NODE_TAG = "metadata"; + private static final String METADATA_SERIAL_NODE_TAG = "serial"; + private static final String METADATA_REFRESH_INTERVAL_NODE_TAG = "refresh-interval"; + private static final String ENDPOINT_CERT_LIST_TAG = "endpoints"; + private static final String ENDPOINT_CERT_ITEM_TAG = "cert"; + private static final String INTERMEDIATE_CERT_LIST_TAG = "intermediates"; + private static final String INTERMEDIATE_CERT_ITEM_TAG = "cert"; + + private final long serial; + private final long refreshInterval; + private final List<X509Certificate> intermediateCerts; + private final List<X509Certificate> endpointCerts; + + private CertXml( + long serial, + long refreshInterval, + List<X509Certificate> intermediateCerts, + List<X509Certificate> endpointCerts) { + this.serial = serial; + this.refreshInterval = refreshInterval; + this.intermediateCerts = intermediateCerts; + this.endpointCerts = endpointCerts; + } + + /** Gets the serial number of the XML file containing public-key certificates. */ + public long getSerial() { + return serial; + } + + /** + * Gets the refresh interval in the XML file containing public-key certificates. The refresh + * interval denotes the number of seconds that the client should follow to contact the server to + * refresh the XML file. + */ + public long getRefreshInterval() { + return refreshInterval; + } + + @VisibleForTesting + List<X509Certificate> getAllIntermediateCerts() { + return intermediateCerts; + } + + @VisibleForTesting + List<X509Certificate> getAllEndpointCerts() { + return endpointCerts; + } + + /** + * Chooses a random endpoint certificate from the XML file, validates the chosen certificate, + * and returns the certificate path including the chosen certificate if it is valid. + * + * @param trustedRoot the trusted root certificate + * @return the certificate path including the chosen certificate if the certificate is valid + * @throws CertValidationException if the chosen certificate cannot be validated based on the + * trusted root certificate + */ + public CertPath getRandomEndpointCert(X509Certificate trustedRoot) + throws CertValidationException { + return getEndpointCert( + new SecureRandom().nextInt(this.endpointCerts.size()), + /*validationDate=*/ null, + trustedRoot); + } + + @VisibleForTesting + CertPath getEndpointCert( + int index, @Nullable Date validationDate, X509Certificate trustedRoot) + throws CertValidationException { + X509Certificate chosenCert = endpointCerts.get(index); + return CertUtils.validateCert(validationDate, trustedRoot, intermediateCerts, chosenCert); + } + + /** + * Parses a byte array as the content of the XML file containing a list of endpoint + * certificates. + * + * @param bytes the bytes of the XML file + * @return a {@code CertXml} instance that contains the parsing result + * @throws CertParsingException if any parsing error occurs + */ + public static CertXml parse(byte[] bytes) throws CertParsingException { + Element rootNode = CertUtils.getXmlRootNode(bytes); + return new CertXml( + parseSerial(rootNode), + parseRefreshInterval(rootNode), + parseIntermediateCerts(rootNode), + parseEndpointCerts(rootNode)); + } + + private static long parseSerial(Element rootNode) throws CertParsingException { + List<String> contents = + CertUtils.getXmlNodeContents( + CertUtils.MustExist.EXACTLY_ONE, + rootNode, + METADATA_NODE_TAG, + METADATA_SERIAL_NODE_TAG); + return Long.parseLong(contents.get(0)); + } + + private static long parseRefreshInterval(Element rootNode) throws CertParsingException { + List<String> contents = + CertUtils.getXmlNodeContents( + CertUtils.MustExist.EXACTLY_ONE, + rootNode, + METADATA_NODE_TAG, + METADATA_REFRESH_INTERVAL_NODE_TAG); + return Long.parseLong(contents.get(0)); + } + + private static List<X509Certificate> parseIntermediateCerts(Element rootNode) + throws CertParsingException { + List<String> contents = + CertUtils.getXmlNodeContents( + CertUtils.MustExist.FALSE, + rootNode, + INTERMEDIATE_CERT_LIST_TAG, + INTERMEDIATE_CERT_ITEM_TAG); + List<X509Certificate> res = new ArrayList<>(); + for (String content : contents) { + res.add(CertUtils.decodeCert(CertUtils.decodeBase64(content))); + } + return Collections.unmodifiableList(res); + } + + private static List<X509Certificate> parseEndpointCerts(Element rootNode) + throws CertParsingException { + List<String> contents = + CertUtils.getXmlNodeContents( + CertUtils.MustExist.AT_LEAST_ONE, + rootNode, + ENDPOINT_CERT_LIST_TAG, + ENDPOINT_CERT_ITEM_TAG); + List<X509Certificate> res = new ArrayList<>(); + for (String content : contents) { + res.add(CertUtils.decodeCert(CertUtils.decodeBase64(content))); + } + return Collections.unmodifiableList(res); + } +} diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/SigXml.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/SigXml.java new file mode 100644 index 000000000000..878fc6edf77c --- /dev/null +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/SigXml.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.locksettings.recoverablekeystore.certificate; + +import android.annotation.Nullable; + +import com.android.internal.annotations.VisibleForTesting; + +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +import org.w3c.dom.Element; + +/** + * Parses and holds the XML file containing the signature of the XML file containing the list of THM + * public-key certificates. + */ +public final class SigXml { + + private static final String INTERMEDIATE_CERT_LIST_TAG = "intermediates"; + private static final String INTERMEDIATE_CERT_ITEM_TAG = "cert"; + private static final String SIGNER_CERT_NODE_TAG = "certificate"; + private static final String SIGNATURE_NODE_TAG = "value"; + + private final List<X509Certificate> intermediateCerts; + private final X509Certificate signerCert; + private final byte[] signature; + + private SigXml( + List<X509Certificate> intermediateCerts, X509Certificate signerCert, byte[] signature) { + this.intermediateCerts = intermediateCerts; + this.signerCert = signerCert; + this.signature = signature; + } + + /** + * Verifies the signature contained in this XML file against a trusted root certificate and the + * binary content of another file. The signer's public-key certificate and possible intermediate + * CA certificates are included in this XML file, and will be validated against the trusted root + * certificate. + * + * @param trustedRoot the trusted root certificate + * @param signedFileBytes the original file content that has been signed + * @throws CertValidationException if the signature verification fails, or the signer's + * certificate contained in this XML file cannot be validated + * based on the trusted root certificate + */ + public void verifyFileSignature(X509Certificate trustedRoot, byte[] signedFileBytes) + throws CertValidationException { + verifyFileSignature(trustedRoot, signedFileBytes, /*validationDate=*/ null); + } + + @VisibleForTesting + void verifyFileSignature( + X509Certificate trustedRoot, byte[] signedFileBytes, @Nullable Date validationDate) + throws CertValidationException { + CertUtils.validateCert(validationDate, trustedRoot, intermediateCerts, signerCert); + CertUtils.verifyRsaSha256Signature(signerCert.getPublicKey(), signature, signedFileBytes); + } + + /** + * Parses a byte array as the content of the XML file containing the signature and related + * certificates. + * + * @param bytes the bytes of the XML file + * @return a {@code SigXml} instance that contains the parsing result + * @throws CertParsingException if any parsing error occurs + */ + public static SigXml parse(byte[] bytes) throws CertParsingException { + Element rootNode = CertUtils.getXmlRootNode(bytes); + return new SigXml( + parseIntermediateCerts(rootNode), parseSignerCert(rootNode), + parseFileSignature(rootNode)); + } + + private static List<X509Certificate> parseIntermediateCerts(Element rootNode) + throws CertParsingException { + List<String> contents = + CertUtils.getXmlNodeContents( + CertUtils.MustExist.FALSE, + rootNode, + INTERMEDIATE_CERT_LIST_TAG, + INTERMEDIATE_CERT_ITEM_TAG); + List<X509Certificate> res = new ArrayList<>(); + for (String content : contents) { + res.add(CertUtils.decodeCert(CertUtils.decodeBase64(content))); + } + return Collections.unmodifiableList(res); + } + + private static X509Certificate parseSignerCert(Element rootNode) throws CertParsingException { + List<String> contents = + CertUtils.getXmlNodeContents( + CertUtils.MustExist.EXACTLY_ONE, rootNode, SIGNER_CERT_NODE_TAG); + return CertUtils.decodeCert(CertUtils.decodeBase64(contents.get(0))); + } + + private static byte[] parseFileSignature(Element rootNode) throws CertParsingException { + List<String> contents = + CertUtils.getXmlNodeContents( + CertUtils.MustExist.EXACTLY_ONE, rootNode, SIGNATURE_NODE_TAG); + return CertUtils.decodeBase64(contents.get(0)); + } +} diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/invalid-cert-1-no-begin-end.pem b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/invalid-cert-1-no-begin-end.pem new file mode 100644 index 000000000000..b5d513c1652c --- /dev/null +++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/invalid-cert-1-no-begin-end.pem @@ -0,0 +1,49 @@ +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 diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/invalid-cert-2-empty-block.pem b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/invalid-cert-2-empty-block.pem new file mode 100644 index 000000000000..c412709aa8e2 --- /dev/null +++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/invalid-cert-2-empty-block.pem @@ -0,0 +1,2 @@ +-----BEGIN CERTIFICATE----- +-----END CERTIFICATE----- diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/invalid-cert-3-invalid-key.pem b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/invalid-cert-3-invalid-key.pem new file mode 100644 index 000000000000..9137b160223f --- /dev/null +++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/invalid-cert-3-invalid-key.pem @@ -0,0 +1,50 @@ +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/valid-cert-multiple-blocks.pem b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/valid-cert-multiple-blocks.pem new file mode 100644 index 000000000000..e3abeaa177d4 --- /dev/null +++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/valid-cert-multiple-blocks.pem @@ -0,0 +1,70 @@ +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDCDCB8aADAgECAgYBYOlweDswDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwi +R29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTEwODE1 +NTBaFw0yMDAxMTIwODE1NTBaMCkxJzAlBgNVBAMTHkdvb2dsZSBDcnlwdEF1dGhW +YXVsdCBJbnN0YW5jZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgAERiYHfBu +tJT+htocB40BtDr2jdxh0EZJlQ8QhpMkZuA/0t/zeSAdkVWw5b16izJ9JVOi/KVl +4b0hRH54UvowDQYJKoZIhvcNAQELBQADggIBABZALhC9j3hpZ0AgN0tsqAP2Ix21 +tNOcvo/aFJuSFanOM4DZbycZEYAo5rorvuFu7eXETBKDGnI5xreNAoQsaj/dyCHu +HKIn5P7yCmKvG2sV2TQ5go+0xV2x8BhTrtUWLeHvUbM3fXipa3NrordbA8MgzXwr +GR1Y1FuMOn5n4kiuHJ2sQTbDdzSQSK5VpH+6rjARlfOCyLUX0u8UKRRH81qhIQWb +UFMp9q1CVfiLP2O3CdDdpZXCysdflIb62TWnma+I8jqMryyxrMVs9kpfa8zkX9qe +33Vxp+QaQTqQ07/7KYVw869MeFn+bXeHnjUhqGY6S8M71vrTMG3M5p8Sq9LmV8Y5 +7YB5uqKap2Inf0FOuJS7h7nVVzU/kOFkepaQVHyScwTPuuXNgpQg8XZnN/AWfRwJ +hf5zE6vXXTHMzQA1mY2eEhxGfpryv7LH8pvfcyTakdBlw8aMJjKdre8xLLGZeVCa +79plkfYD0rMrxtRHCGyTKGzUcx/B9kYJK5qBgJiDJLKF3XwGbAs/F8CyEPihjvj4 +M2EoeyhmHWKLYsps6+uTksJ+PxZU14M7672K2y8BdulyfkZIhili118XnRykKkMf +JLQJKMqZx5O0B9bF8yQdcGKEGEwMQt5ENdH8HeiwLm4QS3VzFXYetgUPCM5lPDIp +BuwwuQxvQDF4pmQd +-----END CERTIFICATE----- diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/valid-cert.pem b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/valid-cert.pem new file mode 100644 index 000000000000..5c16a1f179e8 --- /dev/null +++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/valid-cert.pem @@ -0,0 +1,204 @@ +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + ce:df:04:67:90:d7:00:64 + Signature Algorithm: sha512WithRSAEncryption + Issuer: CN = Google CryptAuthVault + Validity + Not Before: Jan 11 06:49:33 2018 GMT + Not After : Jan 6 06:49:33 2038 GMT + Subject: CN = Google CryptAuthVault + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (8196 bit) + Modulus: + 09:c1:6f:d3:93:35:b1:e2:cf:60:85:bb:a0:58:af: + 87:bb:b9:a2:d0:ad:32:6e:eb:ca:ad:14:8e:96:d3: + 40:f7:10:c4:94:1b:63:37:14:40:5e:c2:6c:f6:13: + 75:60:e2:77:81:2e:3b:c6:5e:73:4d:e8:c2:7b:1d: + b8:58:4a:b9:de:87:df:22:10:e2:e7:86:8a:a0:81: + a0:6d:43:eb:e3:7c:7c:5f:51:f1:ac:13:98:0b:1b: + 36:0e:b7:54:89:f1:e8:8c:1c:05:99:e3:16:5b:08: + 21:fb:4e:17:1a:88:24:16:21:88:a8:4d:26:13:ed: + 17:58:bd:76:7f:8d:e4:78:c4:2a:69:09:3b:7a:57: + 85:88:51:5c:ca:7b:3b:02:ff:7a:9c:73:84:15:c5: + 61:3e:da:0e:0f:69:9d:a3:3a:0b:ee:21:9a:14:3f: + d2:ad:a8:cb:36:2d:02:a1:66:ac:47:a7:6e:d2:3a: + 1b:8e:d2:cc:c7:3e:b2:13:53:b9:82:ed:ab:6d:63: + fd:9d:ee:03:74:70:07:d4:b3:7e:ef:7d:17:ae:ad: + 96:04:d7:bf:b2:bb:61:2e:7b:de:13:77:4d:06:3f: + fa:79:0b:7c:5c:bf:a0:5d:8b:41:16:2f:28:71:7e: + 36:fd:01:1f:34:0b:ce:a0:c4:60:16:88:2d:c3:1f: + de:2d:82:7b:f6:fb:c1:98:e2:b4:ba:85:00:8d:6c: + c2:a1:b3:80:7f:d0:a4:1d:ce:ad:7e:75:33:f0:7b: + 50:21:76:9c:1e:cf:6b:c9:27:bb:89:01:0c:69:33: + d9:0e:35:8c:02:f4:5b:fa:ad:8f:8d:d5:c0:90:d6: + d1:8f:7c:3a:ea:90:88:2a:89:ad:3a:c6:76:fe:db: + fe:98:67:55:50:6f:16:bb:48:8d:83:1f:c8:ad:f8: + 8f:2e:55:2d:77:2d:57:90:92:91:68:f9:de:e9:77: + 9a:f1:85:1c:90:fe:ea:79:de:0d:1e:0f:52:49:98: + 37:49:21:4f:8b:7f:46:a9:d0:97:06:04:d1:ae:84: + ae:ad:7e:46:87:fa:fc:3a:16:4b:37:81:2c:16:15: + 25:a1:e1:47:2f:66:ae:e7:51:fd:57:10:ca:72:ca: + b7:2e:99:b2:de:0b:ca:1e:9a:3c:c1:dc:a5:3c:06: + 65:b1:be:e2:65:e7:59:e4:da:2c:49:c6:be:2b:e5: + 76:4b:13:5c:ec:62:a5:c3:bf:7d:72:5f:0e:cb:38: + 6f:48:25:1b:33:f7:18:3d:3e:1f:91:19:07:d7:28: + 63:33:53:e3:b4:19:77:d7:6b:c4:77:6b:2f:1b:4f: + a2:2f:8c:7a:a9:06:80:27:72:17:20:59:3b:c1:b6: + 93:f2:6e:cb:38:93:ea:1c:be:e7:45:57:26:79:7a: + 52:3c:63:ec:c5:54:60:0b:08:48:7b:07:82:a1:13: + 0e:cb:a4:41:b6:ca:bd:32:a0:de:0c:4f:54:d3:7f: + bc:a5:b0:ca:1e:ca:2d:c1:48:68:e1:28:3c:e8:12: + b6:49:95:b2:aa:d7:9b:b6:0b:13:a0:6f:ce:6f:27: + bb:8a:f0:25:e0:05:f5:8b:1e:83:d0:44:63:ce:93: + 45:19:80:23:b7:d6:e1:e0:c4:3e:7c:60:09:45:2f: + 71:84:80:87:99:9c:6b:22:32:22:bd:0a:4e:e5:e4: + 7a:fc:18:6d:54:47:31:59:b2:f4:36:aa:ce:c3:fc: + 60:55:c8:a8:5b:c3:5d:10:85:4b:2f:e0:32:4a:0d: + 6f:d6:68:a9:d9:26:8d:9f:95:06:c8:c0:28:8f:ae: + fc:76:9f:ea:98:1d:a4:66:5b:54:62:84:16:66:95: + 1c:29:2b:b4:fa:7f:83:2e:24:13:8a:a6:77:f4:88: + 69:c7:06:f2:8e:84:6f:d5:fd:7d:ba:93:4c:36:6f: + df:89:1c:1a:0c:4e:bc:12:55:21:a3:47:a6:b4:e3: + 82:f6:04:9d:16:83:29:39:66:66:80:94:98:19:47: + ce:f6:df:eb:c6:16:06:62:33:d0:af:2f:60:f7:71: + f6:bf:7c:2e:25:20:a5:b4:c7:b4:a6:48:62:b2:67: + 6e:03:e7:6c:2f:62:70:fd:b8:da:4b:01:e3:26:93: + c7:54:16:73:5e:2f:4c:db:f5:95:4b:6f:e3:32:44: + 99:a6:a8:ca:73:65:11:32:45:7f:f4:f3:d1:02:89: + c6:d4:fe:97:f0:48:03:3f:24:10:93:00:70:ab:1f: + a1:3c:7d:39:3b:5f:b8:bf:39:a5:76:c2:83:16:ca: + 2a:62:a7:e9:1c:f1:50:2c:d2:ce:03:1b:a0:2d:33: + e9:6f:19:c7:2d:a0:2c:88:6a:32:6f:00:5c:01:7b: + b1:a9:70:ad:18:ab:57:89:56:b0:cf:4c:3a:15:44: + 81:f8:dc:bf:fa:a6:41:26:2b:d4:04:6b:c3:07:a0: + 1d:1a:b1:3c:0d:ea:87:5d:64:7e:ae:58:48:55:3b: + 5b:bf:9f:26:b5:87:e9:5b:8b:67:40:75:7e:3d:be: + 96:ca:0c:35:e9:05:03:55:0b:0f:c0:ca:ed:a0:05: + 22:1f:58:d7:2e:09:b7:ff:f1:32:e3:8f:70:3e:4f: + 58:d1:85:99:49:3b:a0:f7:b0:88:85:0c:2e:35:d2: + 59:c8:2b:41:56:1b:64:40:d6:fe:fa:28:30:9a:28: + e3:b5:60:d5:f4:0f:7a:17:a3:6c:e3:44:d6:70:48: + 69:e4:55:84:97 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + D7:7B:A1:87:92:8B:B8:52:1A:29:91:A5:36:5A:1C:B4:32:EB:EC:D1 + X509v3 Authority Key Identifier: + keyid:D7:7B:A1:87:92:8B:B8:52:1A:29:91:A5:36:5A:1C:B4:32:EB:EC:D1 + + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + Signature Algorithm: sha512WithRSAEncryption + 01:9f:2d:35:d6:f7:ae:3e:99:53:70:d7:b2:2d:e2:a1:59:19: + ff:cb:d5:4c:40:4c:a1:68:b9:6c:0b:50:e2:df:95:8d:f2:8c: + 23:8f:8f:a0:ba:02:e5:0d:db:44:73:fa:6f:ce:09:3e:66:40: + 2e:a6:54:24:ae:c5:3d:d3:b7:6f:c2:40:cf:6f:8a:d6:64:1e: + 61:8d:ba:fd:c9:5c:84:1c:ad:5b:1e:1e:d1:49:49:09:ac:1d: + cd:47:0a:87:d6:5c:96:cf:f2:df:69:57:db:57:80:ad:69:a1: + 11:85:38:73:64:2a:7f:33:07:8e:4e:2b:e0:d9:7a:52:96:ec: + b9:b3:c9:44:11:b3:02:fd:d1:ae:22:c0:4c:8a:d5:f7:5c:b9: + 5b:61:ad:8d:0f:76:87:64:ba:3a:5f:dc:90:30:57:d3:0a:38: + 30:60:6d:a7:78:36:2e:a6:7b:dc:2c:83:65:ae:52:58:72:b6: + 12:ac:8b:e8:42:7f:57:7e:c9:e3:53:70:17:cf:e8:dc:eb:12: + eb:3b:71:2d:5c:38:62:f5:ef:90:4d:f7:27:bd:1b:20:97:f1: + e3:f5:26:6b:d7:0d:4b:d4:f3:c9:a3:e2:a3:b1:16:af:56:fc: + da:1d:79:41:02:fb:d4:b4:4a:23:26:b9:11:de:3f:9b:e7:3b: + d0:07:a7:60:56:b3:34:cd:48:4c:43:dc:d1:a7:94:7f:c6:a1: + de:67:fd:13:4d:07:bd:90:46:bc:42:e4:73:b9:12:24:2b:95: + 9b:87:be:84:8b:1d:d2:fb:6b:93:b1:b8:f8:eb:69:e4:e0:4d: + 28:3d:1f:29:89:8a:29:4b:86:44:14:47:eb:29:6d:78:1c:ea: + 61:f5:9b:1c:23:89:7f:1d:f0:e6:4c:d7:e0:a7:21:65:eb:65: + 2b:bf:35:41:9e:8c:fe:b1:b8:53:81:b3:c7:3d:c0:97:39:4a: + e1:9a:9c:fd:23:9a:01:93:21:00:65:8b:a7:4a:fc:d8:ff:d4: + 97:52:cc:fa:a6:c5:c7:26:65:73:2d:07:27:7b:f6:10:4e:da: + 56:cd:5f:f0:18:3e:dc:8e:30:e5:6d:fc:ec:98:60:9f:67:c8: + ea:3c:1a:22:72:5e:48:51:57:72:66:c2:60:b9:f1:19:1d:7c: + 4a:65:0e:f0:2f:b4:7a:8c:aa:e3:fc:6b:42:0d:ec:b5:5a:bd: + 90:4f:c5:57:e4:94:e4:f5:c2:50:16:38:23:0d:66:80:c8:20: + 69:18:46:90:bd:82:5c:68:ec:64:d8:3f:96:6a:9e:5a:c7:c9: + d4:7d:6f:fd:f6:f5:45:03:41:09:2a:c4:95:57:3c:3b:75:a4: + 6d:cb:45:29:7d:9b:31:d9:27:f3:a6:0d:26:ca:69:a0:07:cf: + 8d:63:ab:7a:f1:d2:f9:0b:fc:71:02:fe:66:11:0f:30:18:99: + 8f:e3:98:90:a6:8e:53:e8:b5:55:32:b9:2d:2d:fe:5e:23:3c: + 65:00:b4:08:5b:f0:20:a5:21:fd:24:a0:aa:a4:8b:5d:c5:f8: + ac:00:82:2c:f5:ef:17:1d:b5:49:24:0d:09:75:ee:eb:b4:08: + fe:4d:46:34:87:4d:31:4a:ac:9f:49:26:e9:70:32:7d:94:8a: + 12:64:e2:6f:15:07:56:3b:10:7c:73:7b:d9:64:61:a1:32:e4: + 45:9b:4e:ac:50:7b:dc:1e:3a:3c:2b:09:db:ab:23:b1:0c:68: + de:aa:de:98:5a:dc:ba:59:c3:62:9f:45:9c:89:1d:f7:bc:61: + c8:cf:05:4d:c4:d9:e6:b9:8d:f4:f1:b3:6c:32:f6:3d:8e:c9: + 9d:df:b8:5d:9a:6c:27:99:08:1e:ec:02:1a:ed:33:0f:8d:a2: + a6:d2:f5:7f:d7:3b:45:48:e0:d6:08:8d:8a:ee:49:66:2f:63: + 2d:38:93:06:7e:a5:1e:39:f8:cf:00:d6:d2:de:53:09:04:01: + fd:ab:12:cc:ec:a9:e0:fa:77:ea:56:db:7e:34:6f:4c:c5:c4: + db:3f:cd:05:90:16:bf:e8:9c:46:82:38:ec:8b:00:e6:86:bd: + 8c:4c:26:0e:2b:f7:83:f9:66:62:90:c3:a2:7b:2b:c7:9b:6b: + e0:c5:80:9d:5a:b8:5a:19:f7:37:b7:aa:10:d9:83:be:99:72: + 3b:7b:a7:77:17:76:bd:d1:45:18:90:12:20:8d:ef:73:bb:44: + 4b:c6:70:41:86:ea:11:c8:6c:2f:b9:00:25:aa:03:03:05:92: + 33:4c:ed:15:9f:07:b0:ec:a4:4b:77:32:e1:59:b8:a2:92:18: + bc:d6:ae:8b:83:ad:9a:5a:36:dd:17:a5:1e:e8:05:57:72:1f: + 9d:aa:6a:fe:f5:a5:6d:d1:8e:84:4d:34:bb:ee:7a:d0:ca:09: + 72:2c:a2:1e:37:1e:9c:10:70:e3:11:35:e5:3d:81:9b:08:09: + 6b:74:a0:1d:4c:0e:27:82:70:59:9f:31:90:ff:cc:e0:b4:ff: + 73:bc:82:55:03:a7:2e:38:09:fc:18:51:2c:ad:be:c6:37:6d: + 10:48:3c:32:25:6a:d8:8b:a7:fe:9b:ae:03:f6:b3:8a:e0:9c: + f8:b7:e9:44:7e:37:1f:25:e3:3f:51:c3:65:86:60:13:70:c1: + d7:58:f0:a8:2a:43:9f:96:5e:0f:05:cf:d6:8a:0b:f5:c5:8c: + 3b:d1:16:78:a5:a8:b4:ec:bc:c9:c4:d1:d8:86:fa:44:dd
\ No newline at end of file diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-no-endpoint-cert.xml b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-no-endpoint-cert.xml new file mode 100644 index 000000000000..6519f49287c6 --- /dev/null +++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-no-endpoint-cert.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<certificates> + <metadata> + <serial> + 1000 + </serial> + <creation-time> + 1515697631 + </creation-time> + <refresh-interval> + 2592000 + </refresh-interval> + <previous> + <serial> + 0 + </serial> + <hash> + 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= + </hash> + </previous> + </metadata> + <endpoints> + </endpoints> +</certificates> diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-no-refresh-interval.xml b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-no-refresh-interval.xml new file mode 100644 index 000000000000..3da012257d8f --- /dev/null +++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-no-refresh-interval.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8"?> +<certificates> + <metadata> + <serial> + 1000 + </serial> + <creation-time> + 1515697631 + </creation-time> + <previous> + <serial> + 0 + </serial> + <hash> + 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= + </hash> + </previous> + </metadata> + <endpoints> + <cert> + MIIDCDCB8aADAgECAgYBYOlweDswDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwi + R29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTEwODE1 + NTBaFw0yMDAxMTIwODE1NTBaMCkxJzAlBgNVBAMTHkdvb2dsZSBDcnlwdEF1dGhW + YXVsdCBJbnN0YW5jZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgAERiYHfBu + tJT+htocB40BtDr2jdxh0EZJlQ8QhpMkZuA/0t/zeSAdkVWw5b16izJ9JVOi/KVl + 4b0hRH54UvowDQYJKoZIhvcNAQELBQADggIBABZALhC9j3hpZ0AgN0tsqAP2Ix21 + tNOcvo/aFJuSFanOM4DZbycZEYAo5rorvuFu7eXETBKDGnI5xreNAoQsaj/dyCHu + HKIn5P7yCmKvG2sV2TQ5go+0xV2x8BhTrtUWLeHvUbM3fXipa3NrordbA8MgzXwr + GR1Y1FuMOn5n4kiuHJ2sQTbDdzSQSK5VpH+6rjARlfOCyLUX0u8UKRRH81qhIQWb + UFMp9q1CVfiLP2O3CdDdpZXCysdflIb62TWnma+I8jqMryyxrMVs9kpfa8zkX9qe + 33Vxp+QaQTqQ07/7KYVw869MeFn+bXeHnjUhqGY6S8M71vrTMG3M5p8Sq9LmV8Y5 + 7YB5uqKap2Inf0FOuJS7h7nVVzU/kOFkepaQVHyScwTPuuXNgpQg8XZnN/AWfRwJ + hf5zE6vXXTHMzQA1mY2eEhxGfpryv7LH8pvfcyTakdBlw8aMJjKdre8xLLGZeVCa + 79plkfYD0rMrxtRHCGyTKGzUcx/B9kYJK5qBgJiDJLKF3XwGbAs/F8CyEPihjvj4 + M2EoeyhmHWKLYsps6+uTksJ+PxZU14M7672K2y8BdulyfkZIhili118XnRykKkMf + JLQJKMqZx5O0B9bF8yQdcGKEGEwMQt5ENdH8HeiwLm4QS3VzFXYetgUPCM5lPDIp + BuwwuQxvQDF4pmQd + </cert> + </endpoints> +</certificates> diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-no-serial.xml b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-no-serial.xml new file mode 100644 index 000000000000..4370ff08dfda --- /dev/null +++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-no-serial.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8"?> +<certificates> + <metadata> + <creation-time> + 1515697631 + </creation-time> + <refresh-interval> + 2592000 + </refresh-interval> + <previous> + <serial> + 0 + </serial> + <hash> + 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= + </hash> + </previous> + </metadata> + <endpoints> + <cert> + MIIDCDCB8aADAgECAgYBYOlweDswDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwi + R29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTEwODE1 + NTBaFw0yMDAxMTIwODE1NTBaMCkxJzAlBgNVBAMTHkdvb2dsZSBDcnlwdEF1dGhW + YXVsdCBJbnN0YW5jZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgAERiYHfBu + tJT+htocB40BtDr2jdxh0EZJlQ8QhpMkZuA/0t/zeSAdkVWw5b16izJ9JVOi/KVl + 4b0hRH54UvowDQYJKoZIhvcNAQELBQADggIBABZALhC9j3hpZ0AgN0tsqAP2Ix21 + tNOcvo/aFJuSFanOM4DZbycZEYAo5rorvuFu7eXETBKDGnI5xreNAoQsaj/dyCHu + HKIn5P7yCmKvG2sV2TQ5go+0xV2x8BhTrtUWLeHvUbM3fXipa3NrordbA8MgzXwr + GR1Y1FuMOn5n4kiuHJ2sQTbDdzSQSK5VpH+6rjARlfOCyLUX0u8UKRRH81qhIQWb + UFMp9q1CVfiLP2O3CdDdpZXCysdflIb62TWnma+I8jqMryyxrMVs9kpfa8zkX9qe + 33Vxp+QaQTqQ07/7KYVw869MeFn+bXeHnjUhqGY6S8M71vrTMG3M5p8Sq9LmV8Y5 + 7YB5uqKap2Inf0FOuJS7h7nVVzU/kOFkepaQVHyScwTPuuXNgpQg8XZnN/AWfRwJ + hf5zE6vXXTHMzQA1mY2eEhxGfpryv7LH8pvfcyTakdBlw8aMJjKdre8xLLGZeVCa + 79plkfYD0rMrxtRHCGyTKGzUcx/B9kYJK5qBgJiDJLKF3XwGbAs/F8CyEPihjvj4 + M2EoeyhmHWKLYsps6+uTksJ+PxZU14M7672K2y8BdulyfkZIhili118XnRykKkMf + JLQJKMqZx5O0B9bF8yQdcGKEGEwMQt5ENdH8HeiwLm4QS3VzFXYetgUPCM5lPDIp + BuwwuQxvQDF4pmQd + </cert> + </endpoints> +</certificates> diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-two-refresh-intervals.xml b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-two-refresh-intervals.xml new file mode 100644 index 000000000000..0f4e8a3ca0c6 --- /dev/null +++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-two-refresh-intervals.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<certificates> + <metadata> + <serial> + 1000 + </serial> + <creation-time> + 1515697631 + </creation-time> + <refresh-interval> + 2592000 + </refresh-interval> + <refresh-interval> + 2592000 + </refresh-interval> + <previous> + <serial> + 0 + </serial> + <hash> + 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= + </hash> + </previous> + </metadata> + <endpoints> + <cert> + MIIDCDCB8aADAgECAgYBYOlweDswDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwi + R29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTEwODE1 + NTBaFw0yMDAxMTIwODE1NTBaMCkxJzAlBgNVBAMTHkdvb2dsZSBDcnlwdEF1dGhW + YXVsdCBJbnN0YW5jZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgAERiYHfBu + tJT+htocB40BtDr2jdxh0EZJlQ8QhpMkZuA/0t/zeSAdkVWw5b16izJ9JVOi/KVl + 4b0hRH54UvowDQYJKoZIhvcNAQELBQADggIBABZALhC9j3hpZ0AgN0tsqAP2Ix21 + tNOcvo/aFJuSFanOM4DZbycZEYAo5rorvuFu7eXETBKDGnI5xreNAoQsaj/dyCHu + HKIn5P7yCmKvG2sV2TQ5go+0xV2x8BhTrtUWLeHvUbM3fXipa3NrordbA8MgzXwr + GR1Y1FuMOn5n4kiuHJ2sQTbDdzSQSK5VpH+6rjARlfOCyLUX0u8UKRRH81qhIQWb + UFMp9q1CVfiLP2O3CdDdpZXCysdflIb62TWnma+I8jqMryyxrMVs9kpfa8zkX9qe + 33Vxp+QaQTqQ07/7KYVw869MeFn+bXeHnjUhqGY6S8M71vrTMG3M5p8Sq9LmV8Y5 + 7YB5uqKap2Inf0FOuJS7h7nVVzU/kOFkepaQVHyScwTPuuXNgpQg8XZnN/AWfRwJ + hf5zE6vXXTHMzQA1mY2eEhxGfpryv7LH8pvfcyTakdBlw8aMJjKdre8xLLGZeVCa + 79plkfYD0rMrxtRHCGyTKGzUcx/B9kYJK5qBgJiDJLKF3XwGbAs/F8CyEPihjvj4 + M2EoeyhmHWKLYsps6+uTksJ+PxZU14M7672K2y8BdulyfkZIhili118XnRykKkMf + JLQJKMqZx5O0B9bF8yQdcGKEGEwMQt5ENdH8HeiwLm4QS3VzFXYetgUPCM5lPDIp + BuwwuQxvQDF4pmQd + </cert> + </endpoints> +</certificates> diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-two-serials.xml b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-two-serials.xml new file mode 100644 index 000000000000..a2685aa3402d --- /dev/null +++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-two-serials.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<certificates> + <metadata> + <serial> + 1000 + </serial> + <serial> + 1000 + </serial> + <creation-time> + 1515697631 + </creation-time> + <refresh-interval> + 2592000 + </refresh-interval> + <previous> + <serial> + 0 + </serial> + <hash> + 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= + </hash> + </previous> + </metadata> + <endpoints> + <cert> + MIIDCDCB8aADAgECAgYBYOlweDswDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwi + R29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTEwODE1 + NTBaFw0yMDAxMTIwODE1NTBaMCkxJzAlBgNVBAMTHkdvb2dsZSBDcnlwdEF1dGhW + YXVsdCBJbnN0YW5jZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgAERiYHfBu + tJT+htocB40BtDr2jdxh0EZJlQ8QhpMkZuA/0t/zeSAdkVWw5b16izJ9JVOi/KVl + 4b0hRH54UvowDQYJKoZIhvcNAQELBQADggIBABZALhC9j3hpZ0AgN0tsqAP2Ix21 + tNOcvo/aFJuSFanOM4DZbycZEYAo5rorvuFu7eXETBKDGnI5xreNAoQsaj/dyCHu + HKIn5P7yCmKvG2sV2TQ5go+0xV2x8BhTrtUWLeHvUbM3fXipa3NrordbA8MgzXwr + GR1Y1FuMOn5n4kiuHJ2sQTbDdzSQSK5VpH+6rjARlfOCyLUX0u8UKRRH81qhIQWb + UFMp9q1CVfiLP2O3CdDdpZXCysdflIb62TWnma+I8jqMryyxrMVs9kpfa8zkX9qe + 33Vxp+QaQTqQ07/7KYVw869MeFn+bXeHnjUhqGY6S8M71vrTMG3M5p8Sq9LmV8Y5 + 7YB5uqKap2Inf0FOuJS7h7nVVzU/kOFkepaQVHyScwTPuuXNgpQg8XZnN/AWfRwJ + hf5zE6vXXTHMzQA1mY2eEhxGfpryv7LH8pvfcyTakdBlw8aMJjKdre8xLLGZeVCa + 79plkfYD0rMrxtRHCGyTKGzUcx/B9kYJK5qBgJiDJLKF3XwGbAs/F8CyEPihjvj4 + M2EoeyhmHWKLYsps6+uTksJ+PxZU14M7672K2y8BdulyfkZIhili118XnRykKkMf + JLQJKMqZx5O0B9bF8yQdcGKEGEwMQt5ENdH8HeiwLm4QS3VzFXYetgUPCM5lPDIp + BuwwuQxvQDF4pmQd + </cert> + </endpoints> +</certificates> diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-sig-file-no-signature.sig.xml b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-sig-file-no-signature.sig.xml new file mode 100644 index 000000000000..5dc8ffa29625 --- /dev/null +++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-sig-file-no-signature.sig.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<signature> + <certificate> + MIIDCDCB8aADAgECAgYBYOlweDswDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwi + R29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTEwODE1 + NTBaFw0yMDAxMTIwODE1NTBaMCkxJzAlBgNVBAMTHkdvb2dsZSBDcnlwdEF1dGhW + YXVsdCBJbnN0YW5jZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgAERiYHfBu + tJT+htocB40BtDr2jdxh0EZJlQ8QhpMkZuA/0t/zeSAdkVWw5b16izJ9JVOi/KVl + 4b0hRH54UvowDQYJKoZIhvcNAQELBQADggIBABZALhC9j3hpZ0AgN0tsqAP2Ix21 + tNOcvo/aFJuSFanOM4DZbycZEYAo5rorvuFu7eXETBKDGnI5xreNAoQsaj/dyCHu + HKIn5P7yCmKvG2sV2TQ5go+0xV2x8BhTrtUWLeHvUbM3fXipa3NrordbA8MgzXwr + GR1Y1FuMOn5n4kiuHJ2sQTbDdzSQSK5VpH+6rjARlfOCyLUX0u8UKRRH81qhIQWb + UFMp9q1CVfiLP2O3CdDdpZXCysdflIb62TWnma+I8jqMryyxrMVs9kpfa8zkX9qe + 33Vxp+QaQTqQ07/7KYVw869MeFn+bXeHnjUhqGY6S8M71vrTMG3M5p8Sq9LmV8Y5 + 7YB5uqKap2Inf0FOuJS7h7nVVzU/kOFkepaQVHyScwTPuuXNgpQg8XZnN/AWfRwJ + hf5zE6vXXTHMzQA1mY2eEhxGfpryv7LH8pvfcyTakdBlw8aMJjKdre8xLLGZeVCa + 79plkfYD0rMrxtRHCGyTKGzUcx/B9kYJK5qBgJiDJLKF3XwGbAs/F8CyEPihjvj4 + M2EoeyhmHWKLYsps6+uTksJ+PxZU14M7672K2y8BdulyfkZIhili118XnRykKkMf + JLQJKMqZx5O0B9bF8yQdcGKEGEwMQt5ENdH8HeiwLm4QS3VzFXYetgUPCM5lPDIp + BuwwuQxvQDF4pmQd + </certificate> +</signature> diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-sig-file-no-signer-cert.sig.xml b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-sig-file-no-signer-cert.sig.xml new file mode 100644 index 000000000000..aa81295461e6 --- /dev/null +++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-sig-file-no-signer-cert.sig.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<signature> + <value> + VEVTVA== + </value> +</signature> diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-sig-file-two-signatures.sig.xml b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-sig-file-two-signatures.sig.xml new file mode 100644 index 000000000000..09d0f449fe41 --- /dev/null +++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-sig-file-two-signatures.sig.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<signature> + <certificate> + MIIDCDCB8aADAgECAgYBYOlweDswDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwi + R29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTEwODE1 + NTBaFw0yMDAxMTIwODE1NTBaMCkxJzAlBgNVBAMTHkdvb2dsZSBDcnlwdEF1dGhW + YXVsdCBJbnN0YW5jZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgAERiYHfBu + tJT+htocB40BtDr2jdxh0EZJlQ8QhpMkZuA/0t/zeSAdkVWw5b16izJ9JVOi/KVl + 4b0hRH54UvowDQYJKoZIhvcNAQELBQADggIBABZALhC9j3hpZ0AgN0tsqAP2Ix21 + tNOcvo/aFJuSFanOM4DZbycZEYAo5rorvuFu7eXETBKDGnI5xreNAoQsaj/dyCHu + HKIn5P7yCmKvG2sV2TQ5go+0xV2x8BhTrtUWLeHvUbM3fXipa3NrordbA8MgzXwr + GR1Y1FuMOn5n4kiuHJ2sQTbDdzSQSK5VpH+6rjARlfOCyLUX0u8UKRRH81qhIQWb + UFMp9q1CVfiLP2O3CdDdpZXCysdflIb62TWnma+I8jqMryyxrMVs9kpfa8zkX9qe + 33Vxp+QaQTqQ07/7KYVw869MeFn+bXeHnjUhqGY6S8M71vrTMG3M5p8Sq9LmV8Y5 + 7YB5uqKap2Inf0FOuJS7h7nVVzU/kOFkepaQVHyScwTPuuXNgpQg8XZnN/AWfRwJ + hf5zE6vXXTHMzQA1mY2eEhxGfpryv7LH8pvfcyTakdBlw8aMJjKdre8xLLGZeVCa + 79plkfYD0rMrxtRHCGyTKGzUcx/B9kYJK5qBgJiDJLKF3XwGbAs/F8CyEPihjvj4 + M2EoeyhmHWKLYsps6+uTksJ+PxZU14M7672K2y8BdulyfkZIhili118XnRykKkMf + JLQJKMqZx5O0B9bF8yQdcGKEGEwMQt5ENdH8HeiwLm4QS3VzFXYetgUPCM5lPDIp + BuwwuQxvQDF4pmQd + </certificate> + <value> + VEVTVA== + </value> + <value> + VEVTVA== + </value> +</signature> diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-sig-file-two-signer-certs.sig.xml b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-sig-file-two-signer-certs.sig.xml new file mode 100644 index 000000000000..44e8993f1eb4 --- /dev/null +++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-sig-file-two-signer-certs.sig.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<signature> + <certificate> + signer certificate 1 + </certificate> + <certificate> + signer certificate 2 + </certificate> + <value> + VEVTVA== + </value> +</signature> diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/valid-cert-file-no-intermediates.xml b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/valid-cert-file-no-intermediates.xml new file mode 100644 index 000000000000..e59bf362db8b --- /dev/null +++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/valid-cert-file-no-intermediates.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8"?> +<certificates> + <metadata> + <serial> + 1000 + </serial> + <creation-time> + 1515697631 + </creation-time> + <refresh-interval> + 2592000 + </refresh-interval> + <previous> + <serial> + 0 + </serial> + <hash> + 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= + </hash> + </previous> + </metadata> + <endpoints> + <cert> + MIIDCDCB8aADAgECAgYBYOlweDswDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwi + R29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTEwODE1 + NTBaFw0yMDAxMTIwODE1NTBaMCkxJzAlBgNVBAMTHkdvb2dsZSBDcnlwdEF1dGhW + YXVsdCBJbnN0YW5jZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgAERiYHfBu + tJT+htocB40BtDr2jdxh0EZJlQ8QhpMkZuA/0t/zeSAdkVWw5b16izJ9JVOi/KVl + 4b0hRH54UvowDQYJKoZIhvcNAQELBQADggIBABZALhC9j3hpZ0AgN0tsqAP2Ix21 + tNOcvo/aFJuSFanOM4DZbycZEYAo5rorvuFu7eXETBKDGnI5xreNAoQsaj/dyCHu + HKIn5P7yCmKvG2sV2TQ5go+0xV2x8BhTrtUWLeHvUbM3fXipa3NrordbA8MgzXwr + GR1Y1FuMOn5n4kiuHJ2sQTbDdzSQSK5VpH+6rjARlfOCyLUX0u8UKRRH81qhIQWb + UFMp9q1CVfiLP2O3CdDdpZXCysdflIb62TWnma+I8jqMryyxrMVs9kpfa8zkX9qe + 33Vxp+QaQTqQ07/7KYVw869MeFn+bXeHnjUhqGY6S8M71vrTMG3M5p8Sq9LmV8Y5 + 7YB5uqKap2Inf0FOuJS7h7nVVzU/kOFkepaQVHyScwTPuuXNgpQg8XZnN/AWfRwJ + hf5zE6vXXTHMzQA1mY2eEhxGfpryv7LH8pvfcyTakdBlw8aMJjKdre8xLLGZeVCa + 79plkfYD0rMrxtRHCGyTKGzUcx/B9kYJK5qBgJiDJLKF3XwGbAs/F8CyEPihjvj4 + M2EoeyhmHWKLYsps6+uTksJ+PxZU14M7672K2y8BdulyfkZIhili118XnRykKkMf + JLQJKMqZx5O0B9bF8yQdcGKEGEwMQt5ENdH8HeiwLm4QS3VzFXYetgUPCM5lPDIp + BuwwuQxvQDF4pmQd + </cert> + </endpoints> +</certificates> diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/valid-cert-file.xml b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/valid-cert-file.xml new file mode 100644 index 000000000000..be4893f6d489 --- /dev/null +++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/valid-cert-file.xml @@ -0,0 +1,150 @@ +<?xml version="1.0" encoding="UTF-8"?> +<certificates> + <metadata> + <serial> + 1000 + </serial> + <creation-time> + 1515697631 + </creation-time> + <refresh-interval> + 2592000 + </refresh-interval> + <previous> + <serial> + 0 + </serial> + <hash> + 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= + </hash> + </previous> + </metadata> + <intermediates> + <cert> + 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 + +a0fa5B3pxc8BN0LsHA0stT/Y2o= + </cert> + <cert> + MIIESTCCAjGgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwiR29v + Z2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTIwMDM4MDNa + Fw0yMzAxMTEwMDM4MDNaMDoxODA2BgNVBAMML0dvb2dsZSBDcnlwdEF1dGhWYXVs + dCBJbnRlcm1lZGlhdGUgSW50ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOC + AQ8AMIIBCgKCAQEA0v3bN3MwKifDAkF1524XzuaxYtk1sQKUlAlNngh+Qv4RjCkX + TECi7po8LeNsY+hWxmW3XZ22RBphe/yP4YcOdbqlIjZYNx3b75hCSJCadOkdW+Z9 + f6+tKsHgeUja6r9r2TThzileImAvjXShe7GZYW8csPv6HaEVRXQlu8fGAZf8skmJ + EMfJx84//WeULdVz94beDhi9YAf4gLfmOayQcdWhDcMYI39knJcRny1ffRGgb1Hf + lE+3/a3aGFeODaxfkPaGRxEhzhZ/JDBiNgUAH/u7C5nxqa2WOu5e0wq3S0TndIOE + hmnwCE2GvxADFQst+rSsOn4EHit70hv4CfrMRQIDAQABo2YwZDAdBgNVHQ4EFgQU + 0dKv4xTaEmdwHyox3tY8H8XVDGIwHwYDVR0jBBgwFoAURPUcR0+1NxD9b3Y0czWD + K1OxLHgwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZI + hvcNAQELBQADggIBAJaArqLlJ2SLQ8JRwanD6LPlqQxucQ+x/LztTQpzPrsFfJds + E/sDZr2rXhDpz/bifIdj/DCbQ6/3w+t5JdFjT8GjXLgz1kCa/4W409FgSTgy1ENn + AMUU6pFIbOq/Qy/71uOTrrFWYTN5Vk+RBGxx5iDfHjDYraudi4VlcNkal4OyM98n + N3qp9cZD0RtWxMhvq6ahgmf9cTbEw6+l8yf/bogGLBYXXYeOoO5Q134AxrrgfthE + tvyKwJkT/l3OFKRcaHrebs+V1z5gPs7zWOyO5n2Z1SAmcOGfTfKMZWwp3Hi3OTr2 + gB3LUYKyQVhC70dka3X+IbnFg5YfzJtX6YGnHlnI1SufOkEpGQDfcc0UQAWg/lgb + RkfMFD9tuJomBhyqv1YaxLN8yL4ZTRU0KCvvC5I5+X/zt9kBjnHlBOdYtknZT5jz + 7+mjqWdpmWoAjeV5+CgIzG2k7JAm6rQuE1ZQNF0wAYxPret4NHPJFqfD5gGhdrYw + pEUxkcwHERA/E1CkpyqUy/Hd3kqHvnEDqzFcxBdUdmOgnbpI2nAZdEpfxmA5+M1n + UoxQ8ZWAZH+Mdlkw/Hx5hVjGjz8snD4QN25pj/wT+V6AR5OmYb8yfsQb2S8a8yDp + HzcIHW+dEWpX2boirOsrdI16kNtxYqtG7c5qWBPJy5Zjkvh9qbnfT/RQx10g + </cert> + </intermediates> + <endpoints> + <cert> + MIIDCDCB8aADAgECAgYBYOlweDswDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwi + R29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTEwODE1 + NTBaFw0yMDAxMTIwODE1NTBaMCkxJzAlBgNVBAMTHkdvb2dsZSBDcnlwdEF1dGhW + YXVsdCBJbnN0YW5jZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgAERiYHfBu + tJT+htocB40BtDr2jdxh0EZJlQ8QhpMkZuA/0t/zeSAdkVWw5b16izJ9JVOi/KVl + 4b0hRH54UvowDQYJKoZIhvcNAQELBQADggIBABZALhC9j3hpZ0AgN0tsqAP2Ix21 + tNOcvo/aFJuSFanOM4DZbycZEYAo5rorvuFu7eXETBKDGnI5xreNAoQsaj/dyCHu + HKIn5P7yCmKvG2sV2TQ5go+0xV2x8BhTrtUWLeHvUbM3fXipa3NrordbA8MgzXwr + GR1Y1FuMOn5n4kiuHJ2sQTbDdzSQSK5VpH+6rjARlfOCyLUX0u8UKRRH81qhIQWb + UFMp9q1CVfiLP2O3CdDdpZXCysdflIb62TWnma+I8jqMryyxrMVs9kpfa8zkX9qe + 33Vxp+QaQTqQ07/7KYVw869MeFn+bXeHnjUhqGY6S8M71vrTMG3M5p8Sq9LmV8Y5 + 7YB5uqKap2Inf0FOuJS7h7nVVzU/kOFkepaQVHyScwTPuuXNgpQg8XZnN/AWfRwJ + hf5zE6vXXTHMzQA1mY2eEhxGfpryv7LH8pvfcyTakdBlw8aMJjKdre8xLLGZeVCa + 79plkfYD0rMrxtRHCGyTKGzUcx/B9kYJK5qBgJiDJLKF3XwGbAs/F8CyEPihjvj4 + M2EoeyhmHWKLYsps6+uTksJ+PxZU14M7672K2y8BdulyfkZIhili118XnRykKkMf + JLQJKMqZx5O0B9bF8yQdcGKEGEwMQt5ENdH8HeiwLm4QS3VzFXYetgUPCM5lPDIp + BuwwuQxvQDF4pmQd + </cert> + <cert> + MIICrDCCAZSgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwOjE4MDYGA1UEAwwvR29v + Z2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZSBJbnRlcm1lZGlhdGUwHhcN + MTgwMTEyMDEwMzA5WhcNMTkwMTEyMDEwMzA5WjArMSkwJwYDVQQDDCBHb29nbGUg + Q3J5cHRBdXRoVmF1bHQgSW5zdGFuY2UgMjBZMBMGByqGSM49AgEGCCqGSM49AwEH + A0IABGhmBQyWdjsXKJRbkW4iIrvt6iqhX5t2XGt/vZS9CoOl0fs+EvJXo4kgrnx8 + /8SGxz3pwRkFhY943QYy6a1gv/2jgZUwgZIwCQYDVR0TBAIwADAdBgNVHQ4EFgQU + xFmLyxUS2JHKURBtewBKRP6kQBgwVgYDVR0jBE8wTYAU0dKv4xTaEmdwHyox3tY8 + H8XVDGKhMaQvMC0xKzApBgNVBAMMIkdvb2dsZSBDcnlwdEF1dGhWYXVsdCBJbnRl + cm1lZGlhdGWCAhAAMA4GA1UdDwEB/wQEAwIDCDANBgkqhkiG9w0BAQsFAAOCAQEA + EJWpl7HU6LxukLqhw2tVZr7IRrKIucRk+RKaaiMx1Hx2jsTTskiJRiZas/xoPSqX + z1K5DVgI486i7HyqnWkGH5xVzCsv+rya5FOSTS3jVtgtoA4HFEqeeAcDowPDqVw3 + yFTA55ukZnzVaPLpDfPqkhzWiuLQ/4fI6YCmOnWB8KtHTMdyGsDSAkpoxpok++NJ + Lu79BoBLe2ucjN383lTlieLxmrmHjF9ryYSQczcm0v6irMOMxEovw5iT4LHiEhbm + DfOPW909fe/s+K3TGZ3Q6U77x8g5k9dVovMgA4pFwtREtknFjeK1wXR3/eXGcP3W + 0bMX1yTWYJQFWCG3DFoC5w== + </cert> + <cert> + MIIDkjCCAXqgAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwiR29v + Z2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTIwMDU2MjNa + Fw0yMDA3MTMwMDU2MjNaMCsxKTAnBgNVBAMMIEdvb2dsZSBDcnlwdEF1dGhWYXVs + dCBJbnN0YW5jZSAxMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEimGC4KEks4JL + 83DNAAGCA5sKqqxqUPgV8gxgsijlMPL0TOtyJhJ2vSFIULEa0coVFbu+fAdxt3CV + DbzD0vWAmaOBiDCBhTAJBgNVHRMEAjAAMB0GA1UdDgQWBBTVeDueShnq1LCqkCFL + MAYtpxkCuDBJBgNVHSMEQjBAgBRE9RxHT7U3EP1vdjRzNYMrU7EseKEkpCIwIDEe + MBwGA1UEAwwVR29vZ2xlIENyeXB0QXV0aFZhdWx0ggIQATAOBgNVHQ8BAf8EBAMC + AwgwDQYJKoZIhvcNAQELBQADggIBADUZCjfBwBL9SSZDkMwE3n08schTBAgZCCrv + XOQVPGrfbFUcMv1mT4e8a5zxE98HsCS6K4HB40RtTXkmt6nuN+NyBrAmZJrBCqvG + IYtGsBLLEnojgWuSpQIBQeQy9it3RFdSR/1FIPssrWUB5KrtRvd+07+Mo7tI91jE + EunOrocu46g6p/OKSIZ7UmwZzczn2CJsrxuNPgqdlza3ytb+TTm536ZHnqaefSZD + rrruNneTXoqjC2OFn/OVLHQ1ee/vrHiX70P8p1V09cccDiwMCIZskNACYgWRdLYU + F5aYGueoFajrb4zmMoy8DK/4lh1EsfWMsrsQK6whmPidzgz37nb3rPpiHTdxu1Fc + 2XM9QV3Jfj2U5FMOZTcDha7W7kb++gSnQEPTM0+Zu6lTJmcZgK4RJ7lmIfK/eVbJ + 6V/wplOzXSxO3jBb2LNhLbhkUzcg68EIEPxaBpXYVOU2tSo2FMgi7/YLwQLorc6Q + h1pUZep8T8SLpvI02GvsB8TroFr2tCvCe5A1VxBQDx9IE7nEd2N30XxqReFk8Y82 + xZMUOA4DL33NI45KWjhcawm0tzAPFfKjta/zYvnf7rwwE4r2PVuOXdet5eN8zBje + yJbEpjCemADujcwtYQ8hScyj/eCT2KNbZ9ibY2yrZEEuRQanq8CLAbpvSZYIHVhg + Clar7+38 + </cert> + </endpoints> +</certificates> diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/valid-sig-file-no-intermediates.sig.xml b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/valid-sig-file-no-intermediates.sig.xml new file mode 100644 index 000000000000..9c0adcdb2fa1 --- /dev/null +++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/valid-sig-file-no-intermediates.sig.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<signature> + <certificate> + MIIDCDCB8aADAgECAgYBYOlweDswDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwi + R29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTEwODE1 + NTBaFw0yMDAxMTIwODE1NTBaMCkxJzAlBgNVBAMTHkdvb2dsZSBDcnlwdEF1dGhW + YXVsdCBJbnN0YW5jZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgAERiYHfBu + tJT+htocB40BtDr2jdxh0EZJlQ8QhpMkZuA/0t/zeSAdkVWw5b16izJ9JVOi/KVl + 4b0hRH54UvowDQYJKoZIhvcNAQELBQADggIBABZALhC9j3hpZ0AgN0tsqAP2Ix21 + tNOcvo/aFJuSFanOM4DZbycZEYAo5rorvuFu7eXETBKDGnI5xreNAoQsaj/dyCHu + HKIn5P7yCmKvG2sV2TQ5go+0xV2x8BhTrtUWLeHvUbM3fXipa3NrordbA8MgzXwr + GR1Y1FuMOn5n4kiuHJ2sQTbDdzSQSK5VpH+6rjARlfOCyLUX0u8UKRRH81qhIQWb + UFMp9q1CVfiLP2O3CdDdpZXCysdflIb62TWnma+I8jqMryyxrMVs9kpfa8zkX9qe + 33Vxp+QaQTqQ07/7KYVw869MeFn+bXeHnjUhqGY6S8M71vrTMG3M5p8Sq9LmV8Y5 + 7YB5uqKap2Inf0FOuJS7h7nVVzU/kOFkepaQVHyScwTPuuXNgpQg8XZnN/AWfRwJ + hf5zE6vXXTHMzQA1mY2eEhxGfpryv7LH8pvfcyTakdBlw8aMJjKdre8xLLGZeVCa + 79plkfYD0rMrxtRHCGyTKGzUcx/B9kYJK5qBgJiDJLKF3XwGbAs/F8CyEPihjvj4 + M2EoeyhmHWKLYsps6+uTksJ+PxZU14M7672K2y8BdulyfkZIhili118XnRykKkMf + JLQJKMqZx5O0B9bF8yQdcGKEGEwMQt5ENdH8HeiwLm4QS3VzFXYetgUPCM5lPDIp + BuwwuQxvQDF4pmQd + </certificate> + <value> + VEVTVA== + </value> +</signature> diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/valid-sig-file.sig.xml b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/valid-sig-file.sig.xml new file mode 100644 index 000000000000..f94b109aded7 --- /dev/null +++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/valid-sig-file.sig.xml @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="UTF-8"?> +<signature> + <intermediates> + <cert> + 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 + +a0fa5B3pxc8BN0LsHA0stT/Y2o= + </cert> + </intermediates> + <certificate> + MIIESTCCAjGgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwiR29v + Z2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTIwMDM4MDNa + Fw0yMzAxMTEwMDM4MDNaMDoxODA2BgNVBAMML0dvb2dsZSBDcnlwdEF1dGhWYXVs + dCBJbnRlcm1lZGlhdGUgSW50ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOC + AQ8AMIIBCgKCAQEA0v3bN3MwKifDAkF1524XzuaxYtk1sQKUlAlNngh+Qv4RjCkX + TECi7po8LeNsY+hWxmW3XZ22RBphe/yP4YcOdbqlIjZYNx3b75hCSJCadOkdW+Z9 + f6+tKsHgeUja6r9r2TThzileImAvjXShe7GZYW8csPv6HaEVRXQlu8fGAZf8skmJ + EMfJx84//WeULdVz94beDhi9YAf4gLfmOayQcdWhDcMYI39knJcRny1ffRGgb1Hf + lE+3/a3aGFeODaxfkPaGRxEhzhZ/JDBiNgUAH/u7C5nxqa2WOu5e0wq3S0TndIOE + hmnwCE2GvxADFQst+rSsOn4EHit70hv4CfrMRQIDAQABo2YwZDAdBgNVHQ4EFgQU + 0dKv4xTaEmdwHyox3tY8H8XVDGIwHwYDVR0jBBgwFoAURPUcR0+1NxD9b3Y0czWD + K1OxLHgwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZI + hvcNAQELBQADggIBAJaArqLlJ2SLQ8JRwanD6LPlqQxucQ+x/LztTQpzPrsFfJds + E/sDZr2rXhDpz/bifIdj/DCbQ6/3w+t5JdFjT8GjXLgz1kCa/4W409FgSTgy1ENn + AMUU6pFIbOq/Qy/71uOTrrFWYTN5Vk+RBGxx5iDfHjDYraudi4VlcNkal4OyM98n + N3qp9cZD0RtWxMhvq6ahgmf9cTbEw6+l8yf/bogGLBYXXYeOoO5Q134AxrrgfthE + tvyKwJkT/l3OFKRcaHrebs+V1z5gPs7zWOyO5n2Z1SAmcOGfTfKMZWwp3Hi3OTr2 + gB3LUYKyQVhC70dka3X+IbnFg5YfzJtX6YGnHlnI1SufOkEpGQDfcc0UQAWg/lgb + RkfMFD9tuJomBhyqv1YaxLN8yL4ZTRU0KCvvC5I5+X/zt9kBjnHlBOdYtknZT5jz + 7+mjqWdpmWoAjeV5+CgIzG2k7JAm6rQuE1ZQNF0wAYxPret4NHPJFqfD5gGhdrYw + pEUxkcwHERA/E1CkpyqUy/Hd3kqHvnEDqzFcxBdUdmOgnbpI2nAZdEpfxmA5+M1n + UoxQ8ZWAZH+Mdlkw/Hx5hVjGjz8snD4QN25pj/wT+V6AR5OmYb8yfsQb2S8a8yDp + HzcIHW+dEWpX2boirOsrdI16kNtxYqtG7c5qWBPJy5Zjkvh9qbnfT/RQx10g + </certificate> + <value> + zELcMKbEb82mjWdhaV62Po4Tn/fEnHg7TMQzlz3cpDP3uzGKXg4fvCa+yDYrEYqm17uywOfFQpJs + pVjoUMINdnYogO44mul+E+m/klzSQN3GbmvYDtKpFsSGqsymyFSg8Bv2LeDLx2Pisc3sLUhxwKN4 + 8B6MwfZ3qUnRa5/ySk0bzEYYiRWsYR5oY7vK0kAI5c4Oi77E0W440FaEhnT7WxucFUnAhZbOSwXA + apE39BXu6ZbAPpTSc4f+uMErF7cRGbIODcAQJko6yjliBmvnCxj0ct7qzwUpgJojy/G5DLaVx3MF + Xnee9peYCrKFWpB+Z/7io0/Fqs/fDF7U25BsXA== + </value> +</signature> diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertUtilsTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertUtilsTest.java new file mode 100644 index 000000000000..ac6d29395a85 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertUtilsTest.java @@ -0,0 +1,356 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.locksettings.recoverablekeystore.certificate; + +import static com.google.common.truth.Truth.assertThat; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import static org.testng.Assert.assertThrows; +import static org.testng.Assert.expectThrows; + +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import java.io.InputStream; +import java.security.KeyPairGenerator; +import java.security.PublicKey; +import java.security.cert.CertPath; +import java.security.cert.X509Certificate; +import java.security.spec.ECGenParameterSpec; +import java.util.Arrays; +import java.util.Base64; +import java.util.Collections; +import java.util.List; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.w3c.dom.Element; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public final class CertUtilsTest { + + private static final String XML_STR = "" + + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + + "<!-- comment 1 -->" + + "<root>\n\n\n\r\r\r" + + " <node1>\r\n\r\n" + + " node1-1</node1>" + + " <!-- comment 2 -->" + + " <node1>node1-2" + + " \n\r\n\r</node1>" + + " <node2>" + + " <node1> node2-node1-1</node1>" + + " <node1>node2-node1-2 </node1>" + + " <!-- comment 3 -->" + + " <node1> node2-node1-3 </node1>" + + " </node2>" + + "</root>"; + + private static final String SIGNED_STR = "abcdefg\n"; + private static final String SIGNATURE_BASE64 = "" + + "KxBt9B3pwL3/59SrjTJTpuhc9JRxLOUNwNr3J4EEdXj5BqkYOUeXIOjyBGp8XaOnmuW8WmBxhko3" + + "yTR3/M9x0/pJuKDgqQSSFG+I56O/IAri7DmMBfY8QqcgiF8RaR86G7mWXUIdu8ixEtpKa//T4bN7" + + "c8Txvt96ApAcW0wJDihfCqDEXyi56pFCp+qEZuL4fS8iZtZTUkvxim1tb2/IsZ9OyDd9BWxp+JTs" + + "zihzH6xqnUCa1aELSUZnU8OzWGeuKpVDQDbDMtQpcxJ9o+6L6wO5vmQutZAulgw5gRPGhYWVs8+0" + + "ATdNEbv8TSomkXkZ3/lMYnmPXKmaHxcP4330DA=="; + private static final PublicKey SIGNER_PUBLIC_KEY = TestData.INTERMEDIATE_CA_2.getPublicKey(); + + @Test + public void decodeCert_readPemFile_succeeds_singleBlock() throws Exception { + InputStream f = TestData.openTestFile("pem/valid-cert.pem"); + X509Certificate cert = CertUtils.decodeCert(f); + assertThat(cert).isEqualTo(TestData.ROOT_CA_TRUSTED); + } + + @Test + public void decodeCert_readPemFile_succeeds_multipleBlocks() throws Exception { + InputStream in = TestData.openTestFile("pem/valid-cert-multiple-blocks.pem"); + X509Certificate cert = CertUtils.decodeCert(in); + assertThat(cert).isEqualTo(TestData.ROOT_CA_TRUSTED); + } + + @Test + public void decodeCert_readPemFile_throwsIfNoBeginEndLines() throws Exception { + InputStream in = TestData.openTestFile("pem/invalid-cert-1-no-begin-end.pem"); + assertThrows(CertParsingException.class, () -> CertUtils.decodeCert(in)); + } + + @Test + public void decodeCert_readPemFile_throwsIfEmptyBlock() throws Exception { + InputStream in = TestData.openTestFile("pem/invalid-cert-2-empty-block.pem"); + assertThrows(CertParsingException.class, () -> CertUtils.decodeCert(in)); + } + + @Test + public void decodeCert_readPemFile_throwsIfInvalidCert() throws Exception { + InputStream in = TestData.openTestFile("pem/invalid-cert-3-invalid-key.pem"); + assertThrows(CertParsingException.class, () -> CertUtils.decodeCert(in)); + } + + @Test + public void decodeCert_readBytes_succeeds() throws Exception { + X509Certificate cert = CertUtils.decodeCert(TestData.INTERMEDIATE_CA_2.getEncoded()); + assertThat(cert.getIssuerX500Principal().getName()) + .isEqualTo("CN=Google CryptAuthVault Intermediate"); + } + + @Test + public void decodeCert_readBytes_throwsIfInvalidCert() throws Exception { + byte[] modifiedCertBytes = TestData.INTERMEDIATE_CA_1.getEncoded(); + modifiedCertBytes[0] ^= (byte) 1; + assertThrows(CertParsingException.class, () -> CertUtils.decodeCert(modifiedCertBytes)); + } + + @Test + public void decodeBase64_succeeds() throws Exception { + assertThat(CertUtils.decodeBase64("VEVTVA==")).isEqualTo("TEST".getBytes(UTF_8)); + } + + @Test + public void decodeBase64_succeedsIfEmptyInput() throws Exception { + assertThat(CertUtils.decodeBase64("")).hasLength(0); + } + + @Test + public void decodeBase64_throwsIfInvalidInput() throws Exception { + assertThrows(CertParsingException.class, () -> CertUtils.decodeBase64("EVTVA==")); + } + + @Test + public void getXmlRootNode_succeeds() throws Exception { + Element root = CertUtils.getXmlRootNode(XML_STR.getBytes(UTF_8)); + assertThat(root.getTagName()).isEqualTo("root"); + } + + @Test + public void getXmlRootNode_throwsIfEmptyInput() throws Exception { + assertThrows(CertParsingException.class, () -> CertUtils.getXmlRootNode(new byte[0])); + } + + @Test + public void getXmlNodeContents_singleLevel_succeeds() throws Exception { + Element root = CertUtils.getXmlRootNode(XML_STR.getBytes(UTF_8)); + assertThat(CertUtils.getXmlNodeContents(CertUtils.MustExist.FALSE, root, "node1")) + .containsExactly("node1-1", "node1-2"); + } + + @Test + public void getXmlNodeContents_multipleLevels_succeeds() throws Exception { + Element root = CertUtils.getXmlRootNode(XML_STR.getBytes(UTF_8)); + assertThat(CertUtils.getXmlNodeContents(CertUtils.MustExist.FALSE, root, "node2", "node1")) + .containsExactly("node2-node1-1", "node2-node1-2", "node2-node1-3"); + } + + @Test + public void getXmlNodeContents_mustExistFalse_succeedsIfNotExist() throws Exception { + Element root = CertUtils.getXmlRootNode(XML_STR.getBytes(UTF_8)); + assertThat( + CertUtils.getXmlNodeContents( + CertUtils.MustExist.FALSE, root, "node2", "node-not-exist")) + .isEmpty(); + } + + @Test + public void getXmlNodeContents_mustExistAtLeastOne_throwsIfNotExist() throws Exception { + Element root = CertUtils.getXmlRootNode(XML_STR.getBytes(UTF_8)); + CertParsingException expected = + expectThrows( + CertParsingException.class, + () -> + CertUtils.getXmlNodeContents( + CertUtils.MustExist.AT_LEAST_ONE, root, "node2", + "node-not-exist")); + assertThat(expected.getMessage()).contains("must contain at least one"); + } + + @Test + public void getXmlNodeContents_mustExistExactlyOne_throwsIfNotExist() throws Exception { + Element root = CertUtils.getXmlRootNode(XML_STR.getBytes(UTF_8)); + CertParsingException expected = + expectThrows( + CertParsingException.class, + () -> + CertUtils.getXmlNodeContents( + CertUtils.MustExist.EXACTLY_ONE, root, "node-not-exist", + "node1")); + assertThat(expected.getMessage()).contains("must contain exactly one"); + } + + @Test + public void getXmlNodeContents_mustExistExactlyOne_throwsIfMultipleExist() throws Exception { + Element root = CertUtils.getXmlRootNode(XML_STR.getBytes(UTF_8)); + CertParsingException expected = + expectThrows( + CertParsingException.class, + () -> + CertUtils.getXmlNodeContents( + CertUtils.MustExist.EXACTLY_ONE, root, "node2", "node1")); + assertThat(expected.getMessage()).contains("must contain exactly one"); + } + + @Test + public void verifyRsaSha256Signature_succeeds() throws Exception { + CertUtils.verifyRsaSha256Signature( + SIGNER_PUBLIC_KEY, + Base64.getDecoder().decode(SIGNATURE_BASE64), + SIGNED_STR.getBytes(UTF_8)); + } + + @Test + public void verifyRsaSha256Signature_throwsIfMismatchSignature() throws Exception { + byte[] modifiedBytes = SIGNED_STR.getBytes(UTF_8); + modifiedBytes[0] ^= (byte) 1; + assertThrows( + CertValidationException.class, + () -> + CertUtils.verifyRsaSha256Signature( + SIGNER_PUBLIC_KEY, Base64.getDecoder().decode(SIGNATURE_BASE64), + modifiedBytes)); + } + + @Test + public void verifyRsaSha256Signature_throwsIfWrongKeyType() throws Exception { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC"); + keyPairGenerator.initialize(new ECGenParameterSpec("secp256r1")); + PublicKey publicKey = keyPairGenerator.generateKeyPair().getPublic(); + assertThrows( + CertValidationException.class, + () -> + CertUtils.verifyRsaSha256Signature( + publicKey, + Base64.getDecoder().decode(SIGNATURE_BASE64), + SIGNED_STR.getBytes(UTF_8))); + } + + @Test + public void buildCertPath_succeedsWithoutIntermediates() throws Exception { + X509Certificate rootCert = TestData.ROOT_CA_TRUSTED; + X509Certificate leafCert = TestData.INTERMEDIATE_CA_1; + CertPath certPath = CertUtils.buildCertPath( + CertUtils.buildPkixParams( + TestData.DATE_ALL_CERTS_VALID, rootCert, Collections.emptyList(), + leafCert)); + assertThat(certPath.getCertificates()).containsExactly( + TestData.INTERMEDIATE_CA_1).inOrder(); + } + + @Test + public void buildCertPath_succeedsWithIntermediates() throws Exception { + X509Certificate rootCert = TestData.ROOT_CA_TRUSTED; + List<X509Certificate> intermediateCerts = + Arrays.asList(TestData.INTERMEDIATE_CA_1, TestData.INTERMEDIATE_CA_2); + X509Certificate leafCert = TestData.LEAF_CERT_2; + CertPath certPath = + CertUtils.buildCertPath( + CertUtils.buildPkixParams( + TestData.DATE_ALL_CERTS_VALID, rootCert, intermediateCerts, + leafCert)); + assertThat(certPath.getCertificates()) + .containsExactly( + TestData.LEAF_CERT_2, TestData.INTERMEDIATE_CA_2, + TestData.INTERMEDIATE_CA_1) + .inOrder(); + } + + @Test + public void buildCertPath_succeedsWithIntermediates_ignoreUnrelatedIntermedateCert() + throws Exception { + X509Certificate rootCert = TestData.ROOT_CA_TRUSTED; + List<X509Certificate> intermediateCerts = + Arrays.asList(TestData.INTERMEDIATE_CA_1, TestData.INTERMEDIATE_CA_2); + X509Certificate leafCert = TestData.LEAF_CERT_1; + CertPath certPath = + CertUtils.buildCertPath( + CertUtils.buildPkixParams( + TestData.DATE_ALL_CERTS_VALID, rootCert, intermediateCerts, + leafCert)); + assertThat(certPath.getCertificates()) + .containsExactly(TestData.LEAF_CERT_1, TestData.INTERMEDIATE_CA_1) + .inOrder(); + } + + @Test + public void buildCertPath_throwsIfWrongRootCommonName() throws Exception { + X509Certificate rootCert = TestData.ROOT_CA_DIFFERENT_COMMON_NAME; + List<X509Certificate> intermediateCerts = + Arrays.asList(TestData.INTERMEDIATE_CA_1, TestData.INTERMEDIATE_CA_2); + X509Certificate leafCert = TestData.LEAF_CERT_1; + + assertThrows( + CertValidationException.class, + () -> + CertUtils.buildCertPath( + CertUtils.buildPkixParams( + TestData.DATE_ALL_CERTS_VALID, rootCert, intermediateCerts, + leafCert))); + } + + @Test + public void buildCertPath_throwsIfMissingIntermediateCert() throws Exception { + X509Certificate rootCert = TestData.ROOT_CA_DIFFERENT_COMMON_NAME; + List<X509Certificate> intermediateCerts = Collections.emptyList(); + X509Certificate leafCert = TestData.LEAF_CERT_1; + + assertThrows( + CertValidationException.class, + () -> + CertUtils.buildCertPath( + CertUtils.buildPkixParams( + TestData.DATE_ALL_CERTS_VALID, rootCert, intermediateCerts, + leafCert))); + } + + @Test + public void validateCert_succeeds() throws Exception { + X509Certificate rootCert = TestData.ROOT_CA_TRUSTED; + List<X509Certificate> intermediateCerts = + Arrays.asList(TestData.INTERMEDIATE_CA_1, TestData.INTERMEDIATE_CA_2); + X509Certificate leafCert = TestData.LEAF_CERT_2; + CertUtils.validateCert(TestData.DATE_ALL_CERTS_VALID, rootCert, intermediateCerts, + leafCert); + } + + @Test + public void validateCert_throwsIfExpired() throws Exception { + X509Certificate rootCert = TestData.ROOT_CA_TRUSTED; + List<X509Certificate> intermediateCerts = + Arrays.asList(TestData.INTERMEDIATE_CA_1, TestData.INTERMEDIATE_CA_2); + X509Certificate leafCert = TestData.LEAF_CERT_2; + assertThrows( + CertValidationException.class, + () -> + CertUtils.validateCert( + TestData.DATE_LEAF_CERT_2_EXPIRED, rootCert, intermediateCerts, + leafCert)); + } + + @Test + public void validateCert_throwsIfWrongRootWithTheSameCommonName() throws Exception { + X509Certificate rootCert = TestData.ROOT_CA_DIFFERENT_KEY; + List<X509Certificate> intermediateCerts = + Arrays.asList(TestData.INTERMEDIATE_CA_1, TestData.INTERMEDIATE_CA_2); + X509Certificate leafCert = TestData.LEAF_CERT_2; + assertThrows( + CertValidationException.class, + () -> + CertUtils.validateCert( + TestData.DATE_ALL_CERTS_VALID, rootCert, intermediateCerts, + leafCert)); + } +} diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertXmlTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertXmlTest.java new file mode 100644 index 000000000000..52269d98da21 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertXmlTest.java @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.locksettings.recoverablekeystore.certificate; + +import static com.google.common.truth.Truth.assertThat; + +import static org.testng.Assert.assertThrows; +import static org.testng.Assert.expectThrows; + +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import java.security.cert.CertPath; +import java.security.cert.X509Certificate; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public final class CertXmlTest { + + private byte[] certXmlBytes; + + @Before + public void setUp() throws Exception { + certXmlBytes = TestData.readTestFile("xml/valid-cert-file.xml"); + } + + @Test + public void parse_succeeds() throws Exception { + CertXml certXml = CertXml.parse(certXmlBytes); + assertThat(certXml.getSerial()).isEqualTo(1000L); + assertThat(certXml.getRefreshInterval()).isEqualTo(2592000L); + } + + @Test + public void parse_succeedsIfNoIntermediateCerts() throws Exception { + CertXml certXml = + CertXml.parse(TestData.readTestFile("xml/valid-cert-file-no-intermediates.xml")); + assertThat(certXml.getAllIntermediateCerts()).isEmpty(); + } + + @Test + public void parse_checkIntermediateCerts() throws Exception { + CertXml certXml = CertXml.parse(certXmlBytes); + List<X509Certificate> intermediateCerts = certXml.getAllIntermediateCerts(); + assertThat(intermediateCerts) + .containsExactly(TestData.INTERMEDIATE_CA_1, TestData.INTERMEDIATE_CA_2) + .inOrder(); + } + + @Test + public void parse_checkEndpointCerts() throws Exception { + CertXml certXml = CertXml.parse(certXmlBytes); + List<X509Certificate> endpointCerts = certXml.getAllEndpointCerts(); + assertThat(endpointCerts).hasSize(3); + assertThat(endpointCerts).containsAllOf(TestData.LEAF_CERT_1, TestData.LEAF_CERT_2); + } + + @Test + public void parse_throwsIfNoEndpointCert() throws Exception { + CertParsingException expected = + expectThrows( + CertParsingException.class, + () -> + CertXml.parse( + TestData.readTestFile( + "xml/invalid-cert-file-no-endpoint-cert.xml"))); + assertThat(expected.getMessage()).contains("at least one"); + } + + @Test + public void parse_throwsIfNoRefreshInterval() throws Exception { + CertParsingException expected = + expectThrows( + CertParsingException.class, + () -> + CertXml.parse( + TestData.readTestFile( + "xml/invalid-cert-file-no-refresh-interval.xml"))); + assertThat(expected.getMessage()).contains("exactly one"); + } + + @Test + public void parse_throwsIfNoSerial() throws Exception { + CertParsingException expected = + expectThrows( + CertParsingException.class, + () -> + CertXml.parse( + TestData.readTestFile( + "xml/invalid-cert-file-no-serial.xml"))); + assertThat(expected.getMessage()).contains("exactly one"); + } + + @Test + public void parse_throwsIfTwoRefreshIntervals() throws Exception { + CertParsingException expected = + expectThrows( + CertParsingException.class, + () -> + CertXml.parse( + TestData.readTestFile( + "xml/invalid-cert-file-two-refresh-intervals" + + ".xml"))); + assertThat(expected.getMessage()).contains("exactly one"); + } + + @Test + public void parse_throwsIfTwoSerials() throws Exception { + CertParsingException expected = + expectThrows( + CertParsingException.class, + () -> + CertXml.parse( + TestData.readTestFile( + "xml/invalid-cert-file-two-serials.xml"))); + assertThat(expected.getMessage()).contains("exactly one node"); + } + + @Test + public void parseAndValidateAllCerts_succeeds() throws Exception { + CertXml certXml = CertXml.parse(certXmlBytes); + for (int index = 0; index < certXml.getAllEndpointCerts().size(); index++) { + assertThat( + certXml.getEndpointCert( + index, TestData.DATE_ALL_CERTS_VALID, TestData.ROOT_CA_TRUSTED)) + .isNotNull(); + } + } + + @Test + public void parseAndValidate_returnsExpectedCertPath() throws Exception { + CertXml certXml = CertXml.parse(certXmlBytes); + CertPath certPath = + certXml.getEndpointCert( + /*index=*/ 1, // TestData.LEAF_CERT_2 + TestData.DATE_ALL_CERTS_VALID, + TestData.ROOT_CA_TRUSTED); + assertThat(certPath.getCertificates()) + .containsExactly( + TestData.LEAF_CERT_2, TestData.INTERMEDIATE_CA_2, + TestData.INTERMEDIATE_CA_1) + .inOrder(); + } + + @Test + public void validateCert_throwsIfRootCertWithDifferentCommonName() throws Exception { + CertXml certXml = CertXml.parse(certXmlBytes); + assertThrows( + CertValidationException.class, + () -> + certXml.getEndpointCert( + /*index=*/ 0, // TestData.LEAF_CERT_1 + TestData.DATE_ALL_CERTS_VALID, + TestData.ROOT_CA_DIFFERENT_COMMON_NAME)); + } + + @Test + public void validateCert_throwsIfRootCertWithDifferentPublicKey() throws Exception { + CertXml certXml = CertXml.parse(certXmlBytes); + assertThrows( + CertValidationException.class, + () -> + certXml.getEndpointCert( + /*index=*/ 0, // TestData.LEAF_CERT_1 + TestData.DATE_ALL_CERTS_VALID, + TestData.ROOT_CA_DIFFERENT_KEY)); + } + + @Test + public void validateCert_throwsIfExpired() throws Exception { + CertXml certXml = CertXml.parse(certXmlBytes); + assertThrows( + CertValidationException.class, + () -> + certXml.getEndpointCert( + /*index=*/ 1, // TestData.LEAF_CERT_2 + TestData.DATE_LEAF_CERT_2_EXPIRED, + TestData.ROOT_CA_TRUSTED)); + } +} diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/SigXmlTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/SigXmlTest.java new file mode 100644 index 000000000000..4d87006d4fe3 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/SigXmlTest.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.locksettings.recoverablekeystore.certificate; + +import static com.google.common.truth.Truth.assertThat; + +import static org.testng.Assert.assertThrows; +import static org.testng.Assert.expectThrows; + +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public final class SigXmlTest { + + private byte[] certXmlBytes; + private byte[] sigXmlBytes; + + @Before + public void setUp() throws Exception { + certXmlBytes = TestData.readTestFile("xml/valid-cert-file.xml"); + sigXmlBytes = TestData.readTestFile("xml/valid-sig-file.sig.xml"); + } + + @Test + public void parseAndVerifyFileSignature_succeeds() throws Exception { + SigXml sigXml = SigXml.parse(sigXmlBytes); + sigXml.verifyFileSignature( + TestData.ROOT_CA_TRUSTED, certXmlBytes, TestData.DATE_ALL_CERTS_VALID); + } + + @Test + public void parseAndVerifyFileSignature_throwsIfExpiredCert() throws Exception { + SigXml sigXml = SigXml.parse(sigXmlBytes); + assertThrows( + CertValidationException.class, + () -> + sigXml.verifyFileSignature( + TestData.ROOT_CA_TRUSTED, certXmlBytes, + TestData.DATE_INTERMEDIATE_CA_2_EXPIRED)); + } + + @Test + public void parseAndVerifyFileSignature_throwsIfInvalidSignature() throws Exception { + SigXml sigXml = SigXml.parse(sigXmlBytes); + byte[] modifiedBytes = sigXmlBytes.clone(); + modifiedBytes[0] ^= (byte) 1; // Flip one bit + CertValidationException expected = + expectThrows( + CertValidationException.class, + () -> + sigXml.verifyFileSignature( + TestData.ROOT_CA_TRUSTED, modifiedBytes, + TestData.DATE_ALL_CERTS_VALID)); + assertThat(expected.getMessage()).contains("signature is invalid"); + } + + @Test + public void parseAndVerifyFileSignature_throwsIfRootCertWithWrongCommonName() throws Exception { + SigXml sigXml = SigXml.parse(sigXmlBytes); + assertThrows( + CertValidationException.class, + () -> + sigXml.verifyFileSignature( + TestData.ROOT_CA_DIFFERENT_COMMON_NAME, + certXmlBytes, + TestData.DATE_ALL_CERTS_VALID)); + } + + @Test + public void parse_succeedsWithoutIntermediateCerts() throws Exception { + SigXml.parse(TestData.readTestFile("xml/valid-sig-file-no-intermediates.sig.xml")); + } + + @Test + public void parse_throwsIfNoSignerCert() throws Exception { + CertParsingException expected = + expectThrows( + CertParsingException.class, + () -> + SigXml.parse( + TestData.readTestFile( + "xml/invalid-sig-file-no-signer-cert.sig.xml"))); + assertThat(expected.getMessage()).contains("exactly one"); + } + + @Test + public void parse_throwsIfTwoSignerCerts() throws Exception { + CertParsingException expected = + expectThrows( + CertParsingException.class, + () -> + SigXml.parse( + TestData.readTestFile( + "xml/invalid-sig-file-two-signer-certs.sig.xml"))); + assertThat(expected.getMessage()).contains("exactly one"); + } + + @Test + public void parse_throwsIfNoSignatureValue() throws Exception { + CertParsingException expected = + expectThrows( + CertParsingException.class, + () -> + SigXml.parse( + TestData.readTestFile( + "xml/invalid-sig-file-no-signature.sig.xml"))); + assertThat(expected.getMessage()).contains("exactly one"); + } + + @Test + public void parse_throwsIfTwoSignatureValues() throws Exception { + CertParsingException expected = + expectThrows( + CertParsingException.class, + () -> + SigXml.parse( + TestData.readTestFile( + "xml/invalid-sig-file-two-signatures.sig.xml"))); + assertThat(expected.getMessage()).contains("exactly one"); + } +} diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/TestData.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/TestData.java new file mode 100644 index 000000000000..5eb416639b5a --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/TestData.java @@ -0,0 +1,307 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.locksettings.recoverablekeystore.certificate; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; + +import com.google.common.io.ByteStreams; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Base64; +import java.util.Date; + +/** Constants used by the tests in the folder. */ +public final class TestData { + + private static final String TEST_FILE_FOLDER_NAME = "KeyStoreRecoveryControllerTest"; + + private TestData() {} + + // Some test data that is generated by using OpenSSL command line tools. + private static final String ROOT_CA_TRUSTED_BASE64 = "" + + "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"; + private static final String ROOT_CA_DIFFERENT_KEY_BASE64 = "" + + "MIIFJjCCAw6gAwIBAgIJANpazyIWdcb/MA0GCSqGSIb3DQEBCwUAMCAxHjAcBgNV" + + "BAMMFUdvb2dsZSBDcnlwdEF1dGhWYXVsdDAeFw0xODAxMjEwMzI0MjVaFw0zODAx" + + "MTYwMzI0MjVaMCAxHjAcBgNVBAMMFUdvb2dsZSBDcnlwdEF1dGhWYXVsdDCCAiIw" + + "DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKkAUqkRxdVy9UpI9BjQnylGVPRW" + + "aQsCwT2iWJ7fuCnQQon1U9nOyw2R5GYKcA8Zy+4Co++6nzRblYYXJG3Fzsj+kxei" + + "pZGmU11djRJDOhHPPe5jSW37Y0czWaj8jx4xvMim18dGYR7fg6SsOOYXA2y5tlvZ" + + "xLjvw5qpL62J5bVoAAxjng/Oc2Osu+vpv6M50pUZr0OEiFi59WlwrCCZpf1/80bT" + + "j2ebCKKAtTYa6+Q+oMGGxb3imSRpmQPtFcvhUPmAaocUjYM/FeIGNRv14oED/aXz" + + "khuPb+QNkXgk9yiokE10IeAk6oNUNDyuiMNIFy67lUrwc45lv9y0s/8fHj9pvKse" + + "n3+UOKAuV9atUXLdFKQwnQPt4SOmHPkXoj+5tv32RSvVeYhb0ZOpQPkRhxv4wgs7" + + "NldNbKhzVDM9K4M5Q2TrPK1yJKrc5/z0bDzmPOcH4AAXPvSt5PZOs0NlXUJ99BcA" + + "KE1sWArUhipz5mx0hxPTNEM9/8bMb//HkbZtx2log1/fc207W/AFd2FICOpRY+Sb" + + "CJs9WjstpisppotONvgXxZbZiypGKxpeZOb4s6y3iXtZ0FWXUZrc65b8S06fDVCa" + + "ZomNFDWhspHFKyueBgU6cR9K97cDo85Juy6RhnouXxi+XpXPdGFwPqVm1glFYos8" + + "5+Scbwwx69RihN1nAgMBAAGjYzBhMB0GA1UdDgQWBBRoosUAVtfHHeMl8/5x1m2m" + + "arEOoTAfBgNVHSMEGDAWgBRoosUAVtfHHeMl8/5x1m2marEOoTAPBgNVHRMBAf8E" + + "BTADAQH/MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAYbLVQlsi" + + "KdzCPsaybSrUtMrmkad8Gy+/QR3J16adxy/2WpxsZ1Su0YA4tFzOSWqt74C0mnUi" + + "i+3prW7nyEOwezs+NH0SreF4B7tO1FSj157LoHxR2WmCCwul8FfsMi0x6MvEf40v" + + "bMeLrRAA4ysRITua1INb05fzJpczoaW/Q1lBPXConvolnIMvYsLbCZX4/OhQQCLa" + + "mJx8mGrt1wcNp7Kvh+3JfuOXw+WGeCuB5sSWBsOUvhfN+8sgyk1Dtq5c7rVKKtqz" + + "gqHfCNZ+lYa6Vkii7plIcWYJXXa7DMmozX07mrDqdJZEocv6XCoZAKDlJorB8pQT" + + "im47RF60X/FCHSCK2cHbG5M+kF84xwj5fTLztLM1+RlJSJiGk6jhxJRQ+hl0Vkhp" + + "+u7UbUDwkUF/CJB3d1Gtfm+QtzFVKe27ClU5YFSKCXRV/K4KnkZqpyG8Py+PUtUf" + + "WRahp4hkWFkIoLeTnJwgAFRvp/KCtSW0/trI/vfInzqBk/qWIVhxYB8Qv9DXtKBX" + + "3AZ36HM2dxmjef/rpYRphuEN0ZwYdynsGy9dF0SihbR8curSg67sbtYfyw0xURhU" + + "Nk99YMy7T0EUYnaki/PIPK/gnJjZTX1FLCyHUR38fDJIWkGB4xr8pSrwmRoPSvNF" + + "dFr3YlFWwHWd1gXlwJtzeMSuVgoKVtZGmmk="; + private static final String ROOT_CA_DIFFERENT_COMMON_NAME_BASE64 = "" + + "MIIJFzCCBP6gAwIBAgIJAMobGgw5LXwqMA0GCSqGSIb3DQEBCwUAMBgxFjAUBgNV" + + "BAMMDVdyb25nIFJvb3QgQ0EwHhcNMTgwMTE2MTgzNDA5WhcNMzgwMTExMTgzNDA5" + + "WjAYMRYwFAYDVQQDDA1Xcm9uZyBSb290IENBMIIEIjANBgkqhkiG9w0BAQEFAAOC" + + "BA8AMIIECgKCBAEJwW/TkzWx4s9ghbugWK+Hu7mi0K0ybuvKrRSOltNA9xDElBtj" + + "NxRAXsJs9hN1YOJ3gS47xl5zTejCex24WEq53offIhDi54aKoIGgbUPr43x8X1Hx" + + "rBOYCxs2DrdUifHojBwFmeMWWwgh+04XGogkFiGIqE0mE+0XWL12f43keMQqaQk7" + + "eleFiFFcyns7Av96nHOEFcVhPtoOD2mdozoL7iGaFD/SrajLNi0CoWasR6du0job" + + "jtLMxz6yE1O5gu2rbWP9ne4DdHAH1LN+730Xrq2WBNe/srthLnveE3dNBj/6eQt8" + + "XL+gXYtBFi8ocX42/QEfNAvOoMRgFogtwx/eLYJ79vvBmOK0uoUAjWzCobOAf9Ck" + + "Hc6tfnUz8HtQIXacHs9rySe7iQEMaTPZDjWMAvRb+q2PjdXAkNbRj3w66pCIKomt" + + "OsZ2/tv+mGdVUG8Wu0iNgx/IrfiPLlUtdy1XkJKRaPne6Xea8YUckP7qed4NHg9S" + + "SZg3SSFPi39GqdCXBgTRroSurX5Gh/r8OhZLN4EsFhUloeFHL2au51H9VxDKcsq3" + + "Lpmy3gvKHpo8wdylPAZlsb7iZedZ5NosSca+K+V2SxNc7GKlw799cl8OyzhvSCUb" + + "M/cYPT4fkRkH1yhjM1PjtBl312vEd2svG0+iL4x6qQaAJ3IXIFk7wbaT8m7LOJPq" + + "HL7nRVcmeXpSPGPsxVRgCwhIeweCoRMOy6RBtsq9MqDeDE9U03+8pbDKHsotwUho" + + "4Sg86BK2SZWyqtebtgsToG/Obye7ivAl4AX1ix6D0ERjzpNFGYAjt9bh4MQ+fGAJ" + + "RS9xhICHmZxrIjIivQpO5eR6/BhtVEcxWbL0NqrOw/xgVcioW8NdEIVLL+AySg1v" + + "1mip2SaNn5UGyMAoj678dp/qmB2kZltUYoQWZpUcKSu0+n+DLiQTiqZ39Ihpxwby" + + "joRv1f19upNMNm/fiRwaDE68ElUho0emtOOC9gSdFoMpOWZmgJSYGUfO9t/rxhYG" + + "YjPQry9g93H2v3wuJSCltMe0pkhismduA+dsL2Jw/bjaSwHjJpPHVBZzXi9M2/WV" + + "S2/jMkSZpqjKc2URMkV/9PPRAonG1P6X8EgDPyQQkwBwqx+hPH05O1+4vzmldsKD" + + "FsoqYqfpHPFQLNLOAxugLTPpbxnHLaAsiGoybwBcAXuxqXCtGKtXiVawz0w6FUSB" + + "+Ny/+qZBJivUBGvDB6AdGrE8DeqHXWR+rlhIVTtbv58mtYfpW4tnQHV+Pb6Wygw1" + + "6QUDVQsPwMrtoAUiH1jXLgm3//Ey449wPk9Y0YWZSTug97CIhQwuNdJZyCtBVhtk" + + "QNb++igwmijjtWDV9A96F6Ns40TWcEhp5FWElwIDAQABo2MwYTAdBgNVHQ4EFgQU" + + "13uhh5KLuFIaKZGlNloctDLr7NEwHwYDVR0jBBgwFoAU13uhh5KLuFIaKZGlNloc" + + "tDLr7NEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcN" + + "AQELBQADggQCAAWZS0RIH4FdQhlUkdJW06cUYYIJ7p8rRI+6XgMkfj7vupjVnfDN" + + "3Z3s0yf+dGaGGJbv68W952j33z94FuubsacCixNSaS4bIwLXvcL9kQtI9Qf09Pd6" + + "GB102Q6nz/daLVF/5urQPbp4UFkyhcP/d2mg9CmxwBL3Djrf/dKf4EoiV5xmQpUB" + + "a6BNBMntnK1VZ3y8YxDF3XnhbjUZAOTLLYe4+isqvXPb9osdmdaZQU3iHQQwGYJN" + + "6rTYvHmsdfU5eLYLdWxOOm/5Sz5rWXxa1XqSfQgOIaFYQ1w69Z+3BfNbaBnYck3l" + + "xtxGHromigt+2iimXFFML7EHiSznVhHl3SOX0RBLeUvP8oNwwSsaHXuXbceYWvb+" + + "ic7FyTN4f3+wRGjN01U3be93dj+qZlvTmCzpOrJeUcym3F94d0tWQvk3kkBp/Egi" + + "Dd85vYWCdEeCfODW6sReVdj/IuT5xv1T8kKaNaEjJjAjeX6xjPskw3I2LuPeEyz+" + + "26LiOs1hPRHC4CL3JS6LNmRmIYKuy7K0DHwxS6wplDYXXH+a0VuLvQrbsw5zTh3f" + + "Xwq0CLGwPPRyMnFk13+PYBa0bmJ1dNu5hUc9biziCJlvcg0c+FzzUYG4poN0R73R" + + "XPyFHmpULAHit05dw3QaPZqX1GCeiVxrCl6N6G4/9PsVOvi/WEUasHDkk+R4/r9b" + + "RwvQw0PVdDvGndouRcSzHvPEdW9y2TxSDhltvtC2xvp3mGaT0j2+cCRDINLFB6rK" + + "v18oLzpzu3HaZ2ptmm4OpeRnCTLa4qheV1rlSWi3mvPoh77glgHEyTHvhiFrlq+6" + + "f6oMpkcbp4KtOT/npvB3yY4RZWn+J1cDcOW34ssSN2PDVSx1IsianxtSCXKReYrv" + + "kjS4sTQWw0LYG6146g2rz1OKzuT+6YSIPlpw/4/DK0Sz/Q1AY0cuOHhgMSW0cSaE" + + "6PQ275hFjJ4zYYEYNOp56nhsvgbLAu1V5rwQpwi2RNo4teFzP/AKyZzNbApfl8Q5" + + "PKHHE8+Uk3/oLZ8h12JzceKL5ivXU4i8r9sw+o7b/UReVsbrFDXTuO3sRFyA5kI0" + + "aBpYrAyb8xVubbi7gCWhDfJsSKc7CR2N+EUtBrT08TD0AtuxpRLr6Sz2RrTabZNV" + + "lQlgWmKalWT/i7gyA/MNxbBK0hyr7Pvl5f7Ud2+muKOfhEXiCzp8yzXU9I8cTz2p" + + "K85LYJfRNIO2kPrNLdomPL+J2S298GvX2j08CZR8qBXLOs6XJOvZ1KC8BrJ9M7kG" + + "2MHGXeL+9/11khM09dbC+Q0NUKTKOpSU7M7RaON1Dp4RyzdIcdwZ/dFvvxcYbtOP" + + "6OAzRvlk6CZWG3obkt3yaB1NhBEw8hiYvX9F"; + private static final String INTERMEDIATE_CA_1_BASE64 = "" + + "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" + + "+a0fa5B3pxc8BN0LsHA0stT/Y2o="; + private static final String INTERMEDIATE_CA_2_BASE64 = "" + + "MIIESTCCAjGgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwiR29v" + + "Z2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTIwMDM4MDNa" + + "Fw0yMzAxMTEwMDM4MDNaMDoxODA2BgNVBAMML0dvb2dsZSBDcnlwdEF1dGhWYXVs" + + "dCBJbnRlcm1lZGlhdGUgSW50ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOC" + + "AQ8AMIIBCgKCAQEA0v3bN3MwKifDAkF1524XzuaxYtk1sQKUlAlNngh+Qv4RjCkX" + + "TECi7po8LeNsY+hWxmW3XZ22RBphe/yP4YcOdbqlIjZYNx3b75hCSJCadOkdW+Z9" + + "f6+tKsHgeUja6r9r2TThzileImAvjXShe7GZYW8csPv6HaEVRXQlu8fGAZf8skmJ" + + "EMfJx84//WeULdVz94beDhi9YAf4gLfmOayQcdWhDcMYI39knJcRny1ffRGgb1Hf" + + "lE+3/a3aGFeODaxfkPaGRxEhzhZ/JDBiNgUAH/u7C5nxqa2WOu5e0wq3S0TndIOE" + + "hmnwCE2GvxADFQst+rSsOn4EHit70hv4CfrMRQIDAQABo2YwZDAdBgNVHQ4EFgQU" + + "0dKv4xTaEmdwHyox3tY8H8XVDGIwHwYDVR0jBBgwFoAURPUcR0+1NxD9b3Y0czWD" + + "K1OxLHgwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZI" + + "hvcNAQELBQADggIBAJaArqLlJ2SLQ8JRwanD6LPlqQxucQ+x/LztTQpzPrsFfJds" + + "E/sDZr2rXhDpz/bifIdj/DCbQ6/3w+t5JdFjT8GjXLgz1kCa/4W409FgSTgy1ENn" + + "AMUU6pFIbOq/Qy/71uOTrrFWYTN5Vk+RBGxx5iDfHjDYraudi4VlcNkal4OyM98n" + + "N3qp9cZD0RtWxMhvq6ahgmf9cTbEw6+l8yf/bogGLBYXXYeOoO5Q134AxrrgfthE" + + "tvyKwJkT/l3OFKRcaHrebs+V1z5gPs7zWOyO5n2Z1SAmcOGfTfKMZWwp3Hi3OTr2" + + "gB3LUYKyQVhC70dka3X+IbnFg5YfzJtX6YGnHlnI1SufOkEpGQDfcc0UQAWg/lgb" + + "RkfMFD9tuJomBhyqv1YaxLN8yL4ZTRU0KCvvC5I5+X/zt9kBjnHlBOdYtknZT5jz" + + "7+mjqWdpmWoAjeV5+CgIzG2k7JAm6rQuE1ZQNF0wAYxPret4NHPJFqfD5gGhdrYw" + + "pEUxkcwHERA/E1CkpyqUy/Hd3kqHvnEDqzFcxBdUdmOgnbpI2nAZdEpfxmA5+M1n" + + "UoxQ8ZWAZH+Mdlkw/Hx5hVjGjz8snD4QN25pj/wT+V6AR5OmYb8yfsQb2S8a8yDp" + + "HzcIHW+dEWpX2boirOsrdI16kNtxYqtG7c5qWBPJy5Zjkvh9qbnfT/RQx10g"; + private static final String LEAF_CERT_1_BASE64 = "" + + "MIIDCDCB8aADAgECAgYBYOlweDswDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwi" + + "R29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTEwODE1" + + "NTBaFw0yMDAxMTIwODE1NTBaMCkxJzAlBgNVBAMTHkdvb2dsZSBDcnlwdEF1dGhW" + + "YXVsdCBJbnN0YW5jZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgAERiYHfBu" + + "tJT+htocB40BtDr2jdxh0EZJlQ8QhpMkZuA/0t/zeSAdkVWw5b16izJ9JVOi/KVl" + + "4b0hRH54UvowDQYJKoZIhvcNAQELBQADggIBABZALhC9j3hpZ0AgN0tsqAP2Ix21" + + "tNOcvo/aFJuSFanOM4DZbycZEYAo5rorvuFu7eXETBKDGnI5xreNAoQsaj/dyCHu" + + "HKIn5P7yCmKvG2sV2TQ5go+0xV2x8BhTrtUWLeHvUbM3fXipa3NrordbA8MgzXwr" + + "GR1Y1FuMOn5n4kiuHJ2sQTbDdzSQSK5VpH+6rjARlfOCyLUX0u8UKRRH81qhIQWb" + + "UFMp9q1CVfiLP2O3CdDdpZXCysdflIb62TWnma+I8jqMryyxrMVs9kpfa8zkX9qe" + + "33Vxp+QaQTqQ07/7KYVw869MeFn+bXeHnjUhqGY6S8M71vrTMG3M5p8Sq9LmV8Y5" + + "7YB5uqKap2Inf0FOuJS7h7nVVzU/kOFkepaQVHyScwTPuuXNgpQg8XZnN/AWfRwJ" + + "hf5zE6vXXTHMzQA1mY2eEhxGfpryv7LH8pvfcyTakdBlw8aMJjKdre8xLLGZeVCa" + + "79plkfYD0rMrxtRHCGyTKGzUcx/B9kYJK5qBgJiDJLKF3XwGbAs/F8CyEPihjvj4" + + "M2EoeyhmHWKLYsps6+uTksJ+PxZU14M7672K2y8BdulyfkZIhili118XnRykKkMf" + + "JLQJKMqZx5O0B9bF8yQdcGKEGEwMQt5ENdH8HeiwLm4QS3VzFXYetgUPCM5lPDIp" + + "BuwwuQxvQDF4pmQd"; + private static final String LEAF_CERT_2_BASE64 = "" + + "MIICrDCCAZSgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwOjE4MDYGA1UEAwwvR29v" + + "Z2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZSBJbnRlcm1lZGlhdGUwHhcN" + + "MTgwMTEyMDEwMzA5WhcNMTkwMTEyMDEwMzA5WjArMSkwJwYDVQQDDCBHb29nbGUg" + + "Q3J5cHRBdXRoVmF1bHQgSW5zdGFuY2UgMjBZMBMGByqGSM49AgEGCCqGSM49AwEH" + + "A0IABGhmBQyWdjsXKJRbkW4iIrvt6iqhX5t2XGt/vZS9CoOl0fs+EvJXo4kgrnx8" + + "/8SGxz3pwRkFhY943QYy6a1gv/2jgZUwgZIwCQYDVR0TBAIwADAdBgNVHQ4EFgQU" + + "xFmLyxUS2JHKURBtewBKRP6kQBgwVgYDVR0jBE8wTYAU0dKv4xTaEmdwHyox3tY8" + + "H8XVDGKhMaQvMC0xKzApBgNVBAMMIkdvb2dsZSBDcnlwdEF1dGhWYXVsdCBJbnRl" + + "cm1lZGlhdGWCAhAAMA4GA1UdDwEB/wQEAwIDCDANBgkqhkiG9w0BAQsFAAOCAQEA" + + "EJWpl7HU6LxukLqhw2tVZr7IRrKIucRk+RKaaiMx1Hx2jsTTskiJRiZas/xoPSqX" + + "z1K5DVgI486i7HyqnWkGH5xVzCsv+rya5FOSTS3jVtgtoA4HFEqeeAcDowPDqVw3" + + "yFTA55ukZnzVaPLpDfPqkhzWiuLQ/4fI6YCmOnWB8KtHTMdyGsDSAkpoxpok++NJ" + + "Lu79BoBLe2ucjN383lTlieLxmrmHjF9ryYSQczcm0v6irMOMxEovw5iT4LHiEhbm" + + "DfOPW909fe/s+K3TGZ3Q6U77x8g5k9dVovMgA4pFwtREtknFjeK1wXR3/eXGcP3W" + + "0bMX1yTWYJQFWCG3DFoC5w=="; + + /** The cert of the root CA. */ + static final X509Certificate ROOT_CA_TRUSTED = decodeBase64Cert(ROOT_CA_TRUSTED_BASE64); + /** This root CA cert has a different Common Name than ROOT_CA_TRUSTED. */ + static final X509Certificate ROOT_CA_DIFFERENT_COMMON_NAME = + decodeBase64Cert(ROOT_CA_DIFFERENT_COMMON_NAME_BASE64); + /** This root CA cert has the same CN as ROOT_CA_TRUSTED, but a different public key. */ + static final X509Certificate ROOT_CA_DIFFERENT_KEY = + decodeBase64Cert(ROOT_CA_DIFFERENT_KEY_BASE64); + /** This intermediate CA cert is signed by the corresponding private key of ROOT_CA_TRUSTED. */ + static final X509Certificate INTERMEDIATE_CA_1 = decodeBase64Cert(INTERMEDIATE_CA_1_BASE64); + /** This intermediate CA cert is signed by the private key of INTERMEDIATE_CA_1. */ + static final X509Certificate INTERMEDIATE_CA_2 = decodeBase64Cert(INTERMEDIATE_CA_2_BASE64); + /** This leaf cert is signed by the corresponding private key of INTERMEDIATE_CA_1. */ + static final X509Certificate LEAF_CERT_1 = decodeBase64Cert(LEAF_CERT_1_BASE64); + /** This leaf cert is signed by the corresponding private key of INTERMEDIATE_CA_2. */ + static final X509Certificate LEAF_CERT_2 = decodeBase64Cert(LEAF_CERT_2_BASE64); + + private static X509Certificate decodeBase64Cert(String str) { + try { + byte[] bytes = Base64.getDecoder().decode(str); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + return (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(bytes)); + } catch (Exception e) { + throw new RuntimeException(e.getMessage()); + } + } + + static final Date DATE_ALL_CERTS_VALID = new Date(1516406400000L); // Jan 20, 2018 + static final Date DATE_LEAF_CERT_2_EXPIRED = new Date(1547254989001L); // Jan 12, 2019 + static final Date DATE_INTERMEDIATE_CA_2_EXPIRED = new Date(1673397483001L); // Jan 11, 2023 + + static InputStream openTestFile(String relativePath) throws Exception { + Context context = InstrumentationRegistry.getContext(); + return context.getResources().getAssets().open(TEST_FILE_FOLDER_NAME + "/" + relativePath); + } + + static byte[] readTestFile(String relativePath) throws Exception { + InputStream in = openTestFile(relativePath); + return ByteStreams.toByteArray(in); + } +} |