diff --git a/server/build.gradle b/server/build.gradle index fff1b6a..948c856 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -27,7 +27,7 @@ repositories { dependencies { // Bouncy Castle Cryptography APIs used for certificate verification compile 'org.bouncycastle:bcpkix-jdk15on:1.61' - compile 'com.google.guava:guava:27.0.1-android' + compile 'com.google.guava:guava:31.1-jre' compile 'com.google.errorprone:error_prone_annotations:2.3.1' // Gson used for decoding certificate status list compile 'com.google.code.gson:gson:2.8.5' diff --git a/server/src/main/java/com/android/example/KeyAttestationExample.java b/server/src/main/java/com/android/example/KeyAttestationExample.java index 01a2ace..fb93a5b 100644 --- a/server/src/main/java/com/android/example/KeyAttestationExample.java +++ b/server/src/main/java/com/android/example/KeyAttestationExample.java @@ -26,7 +26,7 @@ import com.google.android.attestation.ParsedAttestationRecord; import com.google.android.attestation.RootOfTrust; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableList.Builder; + import java.io.ByteArrayInputStream; import java.io.IOException; import java.nio.file.Files; diff --git a/server/src/main/java/com/google/android/attestation/Constants.java b/server/src/main/java/com/google/android/attestation/Constants.java index bc6e7ec..2c21c37 100644 --- a/server/src/main/java/com/google/android/attestation/Constants.java +++ b/server/src/main/java/com/google/android/attestation/Constants.java @@ -102,6 +102,8 @@ public class Constants { static final int KM_VERIFIED_BOOT_STATE_SELF_SIGNED = 1; static final int KM_VERIFIED_BOOT_STATE_UNVERIFIED = 2; static final int KM_VERIFIED_BOOT_STATE_FAILED = 3; + static final int KM_KEY_PURPOSE_SIGN = 2; + static final int KM_KEY_PURPOSE_ATTEST_KEY = 7; // Unsigned max value of 32-bit integer, 2^32 - 1 static final long UINT32_MAX = (((long) Integer.MAX_VALUE) << 1) + 1; } diff --git a/server/src/main/java/com/google/android/attestation/ParsedAttestationRecord.java b/server/src/main/java/com/google/android/attestation/ParsedAttestationRecord.java index f1aa7e8..afc7ac6 100644 --- a/server/src/main/java/com/google/android/attestation/ParsedAttestationRecord.java +++ b/server/src/main/java/com/google/android/attestation/ParsedAttestationRecord.java @@ -21,6 +21,7 @@ import static com.google.android.attestation.Constants.KEYMASTER_SECURITY_LEVEL_INDEX; import static com.google.android.attestation.Constants.KEYMASTER_VERSION_INDEX; import static com.google.android.attestation.Constants.KEY_DESCRIPTION_OID; +import static com.google.android.attestation.Constants.KM_KEY_PURPOSE_ATTEST_KEY; import static com.google.android.attestation.Constants.KM_SECURITY_LEVEL_SOFTWARE; import static com.google.android.attestation.Constants.KM_SECURITY_LEVEL_STRONG_BOX; import static com.google.android.attestation.Constants.KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT; @@ -30,7 +31,10 @@ import java.io.IOException; import java.security.cert.X509Certificate; +import java.util.Collections; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1Enumerated; import org.bouncycastle.asn1.ASN1InputStream; @@ -100,20 +104,51 @@ private ParsedAttestationRecord( public static ParsedAttestationRecord createParsedAttestationRecord(List certs) throws IOException { - // Parse the attestation record that is closest to the root. This prevents an adversary from - // attesting an attestation record of their choice with an otherwise trusted chain using the - // following attack: - // 1) having the TEE attest a key under the adversary's control, - // 2) using that key to sign a new leaf certificate with an attestation extension that has their chosen attestation record, then - // 3) appending that certificate to the original certificate chain. - for (int i = certs.size() - 1; i >= 0; i--) { - byte[] attestationExtensionBytes = certs.get(i).getExtensionValue(KEY_DESCRIPTION_OID); - if (attestationExtensionBytes != null && attestationExtensionBytes.length != 0) { - return new ParsedAttestationRecord(extractAttestationSequence(attestationExtensionBytes)); + if (certs.isEmpty()) { + throw new IllegalArgumentException("Empty certificate list, couldn't get attestation data."); + } + + // Leaf certificate should contain the attestation record we're looking for. + final ParsedAttestationRecord retval = extractParsedAttestationRecord(certs.get(0)); + if (retval == null) { + throw new IllegalArgumentException("Leaf certificate doesn't contain attestation data."); + } + + // Make sure the rest of the chain is correct. After the leaf we can have zero or more + // attestations of ATTEST_KEYs, then the remaining certificates must not be attestations. So if + // we find any attestations after the first non-attestation, or if we find any attestations that + // aren't for ATTEST_KEYs, throw. + boolean foundNonAttestationCert = false; + for (X509Certificate cert : certs.stream().skip(1).collect(Collectors.toList())) { + final ParsedAttestationRecord record = extractParsedAttestationRecord(cert); + if (record == null) { + foundNonAttestationCert = true; + } else { + if (foundNonAttestationCert) { + throw new IllegalArgumentException( + "Found an attestation certificate after non-attestation cert(s). This should be impossible."); + } + if (!isAttestKeyAttestation(record)) { + throw new IllegalArgumentException("Found non-ATTEST_KEY attestation after leaf."); + } } } - throw new IllegalArgumentException("Couldn't find the keystore attestation extension data."); + return retval; + } + + private static ParsedAttestationRecord extractParsedAttestationRecord(X509Certificate cert) + throws IOException { + byte[] attestationExtensionBytes = cert.getExtensionValue(KEY_DESCRIPTION_OID); + if (attestationExtensionBytes == null) { + return null; + } + return new ParsedAttestationRecord(extractAttestationSequence(attestationExtensionBytes)); + } + + private static boolean isAttestKeyAttestation(ParsedAttestationRecord record) { + Set purposes = record.teeEnforced.purpose.orElse(Collections.emptySet()); + return purposes.size() == 1 && purposes.contains(KM_KEY_PURPOSE_ATTEST_KEY); } public static ParsedAttestationRecord create(ASN1Sequence extensionData) { diff --git a/server/src/test/java/com/google/android/attestation/ParsedAttestationRecordTest.java b/server/src/test/java/com/google/android/attestation/ParsedAttestationRecordTest.java index 678d08e..b6b0207 100644 --- a/server/src/test/java/com/google/android/attestation/ParsedAttestationRecordTest.java +++ b/server/src/test/java/com/google/android/attestation/ParsedAttestationRecordTest.java @@ -15,109 +15,68 @@ package com.google.android.attestation; +import static com.google.android.attestation.Constants.KM_KEY_PURPOSE_SIGN; import static com.google.common.truth.Truth.assertThat; import static java.nio.charset.StandardCharsets.UTF_8; import com.google.android.attestation.AuthorizationList.UserAuthType; import com.google.android.attestation.ParsedAttestationRecord.SecurityLevel; -import java.io.ByteArrayInputStream; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; -import java.util.Arrays; - -import com.google.common.collect.ImmutableSet; +import java.util.Collections; +import java.util.Set; import org.bouncycastle.asn1.ASN1Sequence; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** Test for {@link ParsedAttestationRecord}. */ @RunWith(JUnit4.class) public class ParsedAttestationRecordTest { - - // Certificate generated by TestDPC with RSA Algorithm and StrongBox Security Level - private static final String CERT = - "-----BEGIN CERTIFICATE-----\n" - + "MIIGCDCCBHCgAwIBAgIBATANBgkqhkiG9w0BAQsFADApMRkwFwYDVQQFExAyZGM1OGIyZDFhMjQx" - + "MzI2MQwwCgYDVQQMDANURUUwIBcNNzAwMTAxMDAwMDAwWhgPMjEwNjAyMDcwNjI4MTVaMB8xHTAb" - + "BgNVBAMMFEFuZHJvaWQgS2V5c3RvcmUgS2V5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC" - + "AQEApNVcnyN40MANMbbo2nMGNq2NNysDSjfLm0W3i6wPKf0ffCYkhWM4dCmQKKf50uAZTBeTit4c" - + "NwXeZn3qellMlOsIN3Qc384rfN/8cikrRvUAgibz0Jy7STykjwa7x6tKwqITxbO8HqAhKo8/BQXU" - + "xzrOdIg5ciy+UM7Vgh7a7ogen0KL2iGgrsalb1ti7Vlzb6vIJ4WzIC3TGD2sCkoPahghwqFDZZCo" - + "/FzaLoNY0jAUX2mL+kf8aUaoxz7xA9FTvgara+1pLBR1s4c8xPS2HdZipcVXWfey0wujv1VAKs4+" - + "tXjKlHkYBHBBceEjxUtEmrapSQEdpHPv7Xh9Uanq4QIDAQABo4ICwTCCAr0wDgYDVR0PAQH/BAQD" - + "AgeAMIICqQYKKwYBBAHWeQIBEQSCApkwggKVAgEDCgEBAgEECgEBBANhYmMEADCCAc2/hT0IAgYB" - + "ZOYGEYe/hUWCAbsEggG3MIIBszGCAYswDAQHYW5kcm9pZAIBHTAZBBRjb20uYW5kcm9pZC5rZXlj" - + "aGFpbgIBHTAZBBRjb20uYW5kcm9pZC5zZXR0aW5ncwIBHTAZBBRjb20ucXRpLmRpYWdzZXJ2aWNl" - + "cwIBHTAaBBVjb20uYW5kcm9pZC5keW5zeXN0ZW0CAR0wHQQYY29tLmFuZHJvaWQuaW5wdXRkZXZp" - + "Y2VzAgEdMB8EGmNvbS5hbmRyb2lkLmxvY2FsdHJhbnNwb3J0AgEdMB8EGmNvbS5hbmRyb2lkLmxv" - + "Y2F0aW9uLmZ1c2VkAgEdMB8EGmNvbS5hbmRyb2lkLnNlcnZlci50ZWxlY29tAgEdMCAEG2NvbS5h" - + "bmRyb2lkLndhbGxwYXBlcmJhY2t1cAIBHTAhBBxjb20uZ29vZ2xlLlNTUmVzdGFydERldGVjdG9y" - + "AgEdMCIEHWNvbS5nb29nbGUuYW5kcm9pZC5oaWRkZW5tZW51AgEBMCMEHmNvbS5hbmRyb2lkLnBy" - + "b3ZpZGVycy5zZXR0aW5ncwIBHTEiBCAwGqPLCBE0UBxF8UIqvGbCQiT9Xe1f3I8X5pcXb9hmqjCB" - + "rqEIMQYCAQICAQOiAwIBAaMEAgIIAKUFMQMCAQSmCDEGAgEDAgEFv4FIBQIDAQABv4N3AgUAv4U+" - + "AwIBAL+FQEwwSgQgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQAKAQIEIHKNsSdP" - + "HxzxVx3kOAsEilVKxKOA529TVQg1KQhKk3gBv4VBAwIBAL+FQgUCAwMUs7+FTgUCAwMUs7+FTwUC" - + "AwMUszANBgkqhkiG9w0BAQsFAAOCAYEAJMIuzdNUdfrE6sIdmsnMn/scSG2odbphj8FkX9JGdF2S" - + "OT599HuDY9qhvkru2Dza4sLKK3f4ViBhuR9lpfeprKvstxbtBO7jkLYfVn0ZRzHRHVEyiW5IVKh+" - + "qOXVJ9S1lMShOTlsaYJytLKIlcrRAZBEXZiNbzTuVh1CH6X9Ni1dog14snm+lcOeORdL9fht2CHa" - + "u/caRnpWiZbjoAoJp0O89uBrRkXPpln51+3jPY6AFny30grNAvKguauDcPPhNV1yR+ylSsQi2gm3" - + "Rs4pgtlxFLMfZLgT0cbkl+9zk/QUqlpBP8ftUBsOI0ARr8xhFN3cvq9kXGLtJ9hEP9PRaflAFREk" - + "DK3IBIbVcAFZBFoAQOdE9zy0+F5bQrznPGaZg4Dzhcx33qMDUTgHtWoy+k3ePGQMEtmoTTLgQywW" - + "OIkXEoFqqGi9GKJXUT1KYi5NsigaYqu7FoN4Qsvs61pMUEfZSPP2AFwkA8uNFbmb9uxcxaGHCA8i" - + "3i9VM6yOLIrP\n" - + "-----END CERTIFICATE-----"; - private static final String CERT2 = - "-----BEGIN CERTIFICATE-----\n" - + "MIIEFDCCAnygAwIBAgIVAKZFQPAXr5VWrosuqx4C8tai2XbHMA0GCSqGSIb3DQEB\n" - + "CwUAMBgxFjAUBgNVBAMMDVVua25vd25Jc3N1ZXIwHhcNMjMwMjE1MTU0MzIwWhcN\n" - + "MjMwMjE1MTU0ODIwWjAdMRswGQYDVQQDDBJBbmRyb2lkQXR0ZXN0ZWRLZXkwggGi\n" - + "MA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDJAVfP/7F1bUbDqxMnOVXpSjt5\n" - + "NJwYemBJkN7l7TTbAhTfMW91006Si/snd79Y6bsJklVoiEN9LGL7tQrJEf5lSSLX\n" - + "ZeppjsbLqKnogFHhDJy2vaSiypV2wZdX+kO0qqIKjRvgSqHuTz3gemI1rWilrG3C\n" - + "vd3iHGlkw/4X5PpHQKz99/20p85HP6f/jydMHewFDRQCbkbo2pJ5WrJsyPe9me3o\n" - + "QE0O3lgij7jJ/UBHyb9iH0w13yi+1yZ/jgyojL4QNUeWZnxW656zfHCB8weePD+l\n" - + "tX4AAztZTziJQwk3zVClw4xIPTeztQV6ddRQgjSjGvWanpXqhJx8mq11gWaVJoCl\n" - + "q/I0KOguVsKq42M25uhF7/iAQjC+6lOUUfi2+aPwyTUfGHc5Bw/rTSw2LzvZDnUW\n" - + "8/yw4OUTyDravVcQLeoBES4+O5cVL0yTKDY0THG+ymgsFNgFS7PXUnAbXczYzvg8\n" - + "ldXKOXxnF5nWgg55n2iSQ6mqtHDEUsjcxjmuFcMCAwEAAaNQME4wTAYKKwYBBAHW\n" - + "eQIBEQQ+MDwCAQEKAQECAQIKAQEEEkEgcmFuZG9tIGNoYWxsZW5nZQQAMAAwFr+F\n" - + "SQgEBlNFUklBTL+FSgYEBElNRUkwDQYJKoZIhvcNAQELBQADggGBAHSms4IBjkc8\n" - + "1ZLHu5l70Ih2RrNU4XAc2E/oJX8OsBte9ZRwDT3TdcfLeg0rSneS+aB4xN1BGfmL\n" - + "DPZ1epRzMY4RagVhzBEauHpTaM2imRT9RN5TxbFvuMC4ELICYr5qHfqeALIlMET3\n" - + "TbCAo3njpNh5ids6qdlmpZRoYBQNMKfWJn8SUtCmVMk87FA7RZZCqCiRk+PBnciT\n" - + "O3LLbwT4aBlMinQ84gBfVXRqOvGAeGOgojDqGyK3tDMjIS7itpGb23vGogxHiHjA\n" - + "i8hiQhsHA+C89duCdeGyWZGmxwln7QRsosFI7G4ZOufXPLZt/DauNAC2Mb2OPcDw\n" - + "4tSKQvzQiL9UG4X3Cck0JnATxjT5sLttshJl98V6jQHcWSnjg8+oa3B8WgcePX8E\n" - + "QgcLhYaEGo9WDYJQvHfuUE5AquTxdTRbeiDbV7W+FAOQ5zi/wiGit86gF26120OQ\n" - + "KzQHP94/ORuAT/lkv3Fp3HytF4n3scur1nI0WqrfKpbUuPkmndCIbg==\n" - + "-----END CERTIFICATE-----\n"; - - private static final int EXPECTED_ATTESTATION_VERSION = 3; + public static final int EXPECTED_KEY_PURPOSE = KM_KEY_PURPOSE_SIGN; + // The cert chains at the following paths were all generated on a Pixel 7 Pro, with + // remotely-provisioned certificates. + private static final String TEST_NORMAL_CERT_CHAIN_PATH = + "src/test/resources/normal_cert_chain.pem"; + private static final String TEST_ATTEST_KEY_CERT_CHAIN_PATH = + "src/test/resources/cert_chain_with_attest_keys.pem"; + private static final String TEST_FAKE_KEY_CERT_CHAIN_PATH = + "src/test/resources/fake_cert_chain_with_attest_keys.pem"; + // The values specified in these expectation constants must match what's in the cert chains + // mentioned above. + private static final int EXPECTED_ATTESTATION_VERSION = 200; private static final SecurityLevel EXPECTED_ATTESTATION_SECURITY_LEVEL = SecurityLevel.TRUSTED_ENVIRONMENT; - private static final int EXPECTED_KEYMASTER_VERSION = 4; + private static final int EXPECTED_KEYMASTER_VERSION = 200; private static final SecurityLevel EXPECTED_KEYMASTER_SECURITY_LEVEL = SecurityLevel.TRUSTED_ENVIRONMENT; - private static final byte[] EXPECTED_ATTESTATION_CHALLENGE = "abc".getBytes(UTF_8); + private static final byte[] EXPECTED_ATTESTATION_CHALLENGE = "challenge".getBytes(UTF_8); private static final byte[] EXPECTED_UNIQUE_ID = "".getBytes(UTF_8); + @Rule public ExpectedException fakeLeafException = ExpectedException.none(); - private static X509Certificate getAttestationRecord(String certStr) throws CertificateException { - CertificateFactory factory = CertificateFactory.getInstance("X509"); - X509Certificate cert = - (X509Certificate) - factory.generateCertificate(new ByteArrayInputStream(certStr.getBytes(UTF_8))); - return cert; + private ImmutableList loadCertificateChain(String filePath) + throws FileNotFoundException, CertificateException { + return CertificateFactory // + .getInstance("X.509") + .generateCertificates(new FileInputStream(filePath)) + .stream() + .map(c -> (X509Certificate) c) + .collect(ImmutableList.toImmutableList()); } @Test public void testParseAttestationRecord() throws CertificateException, IOException { - X509Certificate x509Certificate = getAttestationRecord(CERT); - X509Certificate x509Certificate2 = getAttestationRecord(CERT2); ParsedAttestationRecord attestationRecord = - ParsedAttestationRecord.createParsedAttestationRecord(Arrays.asList(x509Certificate2, x509Certificate)); + ParsedAttestationRecord.createParsedAttestationRecord( + loadCertificateChain(TEST_NORMAL_CERT_CHAIN_PATH)); assertThat(attestationRecord.attestationVersion).isEqualTo(EXPECTED_ATTESTATION_VERSION); assertThat(attestationRecord.attestationSecurityLevel) @@ -129,13 +88,40 @@ public void testParseAttestationRecord() throws CertificateException, IOExceptio assertThat(attestationRecord.uniqueId).isEqualTo(EXPECTED_UNIQUE_ID); assertThat(attestationRecord.softwareEnforced).isNotNull(); assertThat(attestationRecord.teeEnforced).isNotNull(); + Set actual = attestationRecord.teeEnforced.purpose.orElse(Collections.emptySet()); + assertThat(actual).containsExactly(KM_KEY_PURPOSE_SIGN); + } + + @Test + public void testParseAttestationRecordWithAttestKeys() throws IOException, CertificateException { + ParsedAttestationRecord attestationRecord = + ParsedAttestationRecord.createParsedAttestationRecord( + loadCertificateChain(TEST_ATTEST_KEY_CERT_CHAIN_PATH)); + + assertThat(attestationRecord.attestationVersion).isEqualTo(EXPECTED_ATTESTATION_VERSION); + assertThat(attestationRecord.attestationSecurityLevel) + .isEqualTo(EXPECTED_ATTESTATION_SECURITY_LEVEL); + assertThat(attestationRecord.keymasterVersion).isEqualTo(EXPECTED_KEYMASTER_VERSION); + assertThat(attestationRecord.keymasterSecurityLevel) + .isEqualTo(EXPECTED_KEYMASTER_SECURITY_LEVEL); + assertThat(attestationRecord.attestationChallenge).isEqualTo(EXPECTED_ATTESTATION_CHALLENGE); + assertThat(attestationRecord.uniqueId).isEqualTo(EXPECTED_UNIQUE_ID); + assertThat(attestationRecord.softwareEnforced).isNotNull(); + assertThat(attestationRecord.teeEnforced).isNotNull(); + Set actual = attestationRecord.teeEnforced.purpose.orElse(Collections.emptySet()); + assertThat(actual).containsExactly(EXPECTED_KEY_PURPOSE); + } + + @Test + public void testParseAttestationRecordWithAttestKeysAndFakeLeaf() throws Exception { + fakeLeafException.expect(IllegalArgumentException.class); + fakeLeafException.expectMessage("Found non-ATTEST_KEY attestation after leaf."); + ParsedAttestationRecord.createParsedAttestationRecord( + loadCertificateChain(TEST_FAKE_KEY_CERT_CHAIN_PATH)); } @Test public void testCreateAndParseAttestationRecord() { - AuthorizationList.Builder teeEnforcedBuilder = AuthorizationList.builder(); - teeEnforcedBuilder.userAuthType = ImmutableSet.of(UserAuthType.FINGERPRINT); - teeEnforcedBuilder.attestationIdBrand = "free food".getBytes(UTF_8); ParsedAttestationRecord expected = ParsedAttestationRecord.create( /* attestationVersion= */ 2, @@ -147,7 +133,8 @@ public void testCreateAndParseAttestationRecord() { /* softwareEnforced= */ AuthorizationList.builder().build(), /* teeEnforced= */ AuthorizationList.builder() .setUserAuthType(ImmutableSet.of(UserAuthType.FINGERPRINT)) - .setAttestationIdBrand("free food".getBytes(UTF_8)).build()); + .setAttestationIdBrand("free food".getBytes(UTF_8)) + .build()); ASN1Sequence seq = expected.toAsn1Sequence(); ParsedAttestationRecord actual = ParsedAttestationRecord.create(seq); assertThat(actual.attestationVersion).isEqualTo(expected.attestationVersion); diff --git a/server/src/test/resources/cert_chain_with_attest_keys.pem b/server/src/test/resources/cert_chain_with_attest_keys.pem new file mode 100644 index 0000000..860240f --- /dev/null +++ b/server/src/test/resources/cert_chain_with_attest_keys.pem @@ -0,0 +1,108 @@ +-----BEGIN CERTIFICATE----- +MIICoDCCAkWgAwIBAgIBATAKBggqhkjOPQQDAjAfMR0wGwYDVQQDExRBbmRyb2lkIEtleXN0b3Jl +IEtleTAeFw03MDAxMDEwMDAwMDBaFw00ODAxMDEwMDAwMDBaMB8xHTAbBgNVBAMTFEFuZHJvaWQg +S2V5c3RvcmUgS2V5MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAElgYY6VfGVE1TJ+kIU2py/40p +E1TljDo2ttKzRLgo8kE5NxbbRleHsGU+hIsxX7uMG+xSh8HO5Qoo6qQKaSZKyqOCAXAwggFsMA4G +A1UdDwEB/wQEAwIHgDCCAVgGCisGAQQB1nkCAREEggFIMIIBRAICAMgKAQECAgDICgEBBAljaGFs +bGVuZ2UEADCBgr+DEAgCBgGGwaaDHr+DEQgCBgGGwbXFXr+DEggCBgGGwcUHnr+FPQgCBgGGwaaq +Zb+FRU4ETDBKMSQwIgQdY29tLmdvb2dsZS5hdHRlc3RhdGlvbmV4YW1wbGUCAQExIgQgaIVtHQb2 +N9YlX6zlsiTbQ6lRSs5Ti7FUi4REgPzYXIcwgaGhBTEDAgECogMCAQOjBAICAQClBTEDAgEEqgMC +AQG/g3cCBQC/hT4DAgEAv4VATDBKBCAmrExgvrHjeDV8rQwwYTR6+N9vuruw2M6iRFhV7gHjaAEB +/woBAAQg6qRTOVd036ERIVxge30J8SVX92UV0fqXFpbHHasWfkG/hUEFAgMB+9C/hUIFAgMDFj6/ +hU4GAgQBNLA9v4VPBgIEATSwPTAKBggqhkjOPQQDAgNJADBGAiEAwblB/wUhD526XA6x1dkFZJ93 +VhdT9ZgTI8E3ixWYj6gCIQCV5mTOgGsvVUTOFBqpLd+4bIVqAPA25WZ/P/j87+h/nw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICmTCCAj6gAwIBAgIBATAKBggqhkjOPQQDAjAfMR0wGwYDVQQDExRBbmRyb2lkIEtleXN0b3Jl +IEtleTAeFw03MDAxMDEwMDAwMDBaFw00ODAxMDEwMDAwMDBaMB8xHTAbBgNVBAMTFEFuZHJvaWQg +S2V5c3RvcmUgS2V5MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEq/opEcKRCLCVgpRgfoL6mdoV +42aFEUOnHQdejZRMksmcmzp+2PAdZ76nMin11MDpRAjyU7EMrkKA7Hyms87XHKOCAWkwggFlMA4G +A1UdDwEB/wQEAwIHgDCCAVEGCisGAQQB1nkCAREEggFBMIIBPQICAMgKAQECAgDICgEBBAljaGFs +bGVuZ2UEADCBgr+DEAgCBgGGwaaDHr+DEQgCBgGGwcUHnr+DEggCBgGGwcUHnr+FPQgCBgGGwaaq +UL+FRU4ETDBKMSQwIgQdY29tLmdvb2dsZS5hdHRlc3RhdGlvbmV4YW1wbGUCAQExIgQgaIVtHQb2 +N9YlX6zlsiTbQ6lRSs5Ti7FUi4REgPzYXIcwgZqhBTEDAgEHogMCAQOjBAICAQCqAwIBAb+DdwIF +AL+FPgMCAQC/hUBMMEoEICasTGC+seN4NXytDDBhNHr432+6u7DYzqJEWFXuAeNoAQH/CgEABCDq +pFM5V3TfoREhXGB7fQnxJVf3ZRXR+pcWlscdqxZ+Qb+FQQUCAwH70L+FQgUCAwMWPr+FTgYCBAE0 +sD2/hU8GAgQBNLA9MAoGCCqGSM49BAMCA0kAMEYCIQDIjmhdukN0xjQmUn3oGkmTbO6EAM03h5zK +x5YwjIKFOwIhAI4bbEgXaMoVCHoOC6ilNxKM2CWGM8xZP3SN+mqjSAKR +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICsTCCAligAwIBAgIBATAKBggqhkjOPQQDAjA5MQwwCgYDVQQKEwNURUUxKTAnBgNVBAMTIGQw +NWZhY2Y0NDNlZDUzNTU0OGQ5OTRmNjg0NWU2ZDNjMB4XDTcwMDEwMTAwMDAwMFoXDTQ4MDEwMTAw +MDAwMFowHzEdMBsGA1UEAxMUQW5kcm9pZCBLZXlzdG9yZSBLZXkwWTATBgcqhkjOPQIBBggqhkjO +PQMBBwNCAASf7jR8k7v332bjrsPDkLiiSRhjY9nPAvHGh/rU7XsdYEVNydtZjVNLURA/nZoZ5VlV +GOCQT3jIlBl6B9AoAeeio4IBaTCCAWUwDgYDVR0PAQH/BAQDAgeAMIIBUQYKKwYBBAHWeQIBEQSC +AUEwggE9AgIAyAoBAQICAMgKAQEECWNoYWxsZW5nZQQAMIGCv4MQCAIGAYbBpoMev4MRCAIGAYbB +xQeev4MSCAIGAYbBxQeev4U9CAIGAYbBpqo2v4VFTgRMMEoxJDAiBB1jb20uZ29vZ2xlLmF0dGVz +dGF0aW9uZXhhbXBsZQIBATEiBCBohW0dBvY31iVfrOWyJNtDqVFKzlOLsVSLhESA/NhchzCBmqEF +MQMCAQeiAwIBA6MEAgIBAKoDAgEBv4N3AgUAv4U+AwIBAL+FQEwwSgQgJqxMYL6x43g1fK0MMGE0 +evjfb7q7sNjOokRYVe4B42gBAf8KAQAEIOqkUzlXdN+hESFcYHt9CfElV/dlFdH6lxaWxx2rFn5B +v4VBBQIDAfvQv4VCBQIDAxY+v4VOBgIEATSwPb+FTwYCBAE0sD0wCgYIKoZIzj0EAwIDRwAwRAIg +OtRthSg7Zqrkd+j1q/fFVTrlvD5t7vnlYkT4JxUd7aMCIHFNhGYXMGXx0MakRwO8PIqTc6y5EXtc +be47ZzJUmlcY +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIBxDCCAWqgAwIBAgIRANBfrPRD7VNVSNmU9oRebTwwCgYIKoZIzj0EAwIwKTETMBEGA1UEChMK +R29vZ2xlIExMQzESMBAGA1UEAxMJRHJvaWQgQ0EzMB4XDTIzMDIxODAxMzM1MloXDTIzMDMyNDAx +MzM1MlowOTEMMAoGA1UEChMDVEVFMSkwJwYDVQQDEyBkMDVmYWNmNDQzZWQ1MzU1NDhkOTk0ZjY4 +NDVlNmQzYzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABHExGJmFHbe4bBnbxXer2haFmsyBMRCy +HPdjwUzOQ1jKt+OhQ2JI0EQdJuDC4tyM2byZhxXlvP6itjzkLSju69qjYzBhMB0GA1UdDgQWBBQp +APiyZzxgyCuIv++2jELSN/zsMjAfBgNVHSMEGDAWgBRgBjXo561pHSkjTd05NGwF7DylCjAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwICBDAKBggqhkjOPQQDAgNIADBFAiBZK4xVrYp17UeA +3XpKV9aXjFB8nXGdhpL6irqADHXBcgIhAItlP0fTqTocHWBuz4vxnZsZyAUgyio14rgmwsi0eVkb +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIB2DCCAV2gAwIBAgIUAIGiWxUvRzifGggDzLZIEaw9lcIwCgYIKoZIzj0EAwMwKTETMBEGA1UE +ChMKR29vZ2xlIExMQzESMBAGA1UEAxMJRHJvaWQgQ0EyMB4XDTIzMDIxOTE4MjgzNloXDTIzMDMy +NjE4MjgzNVowKTETMBEGA1UEChMKR29vZ2xlIExMQzESMBAGA1UEAxMJRHJvaWQgQ0EzMFkwEwYH +KoZIzj0CAQYIKoZIzj0DAQcDQgAEFIf+wsXWQsQwKh86h02Jx/Lk2pn+n4SFErM0ypR4P9mtc1w3 +/FOnR/XYUSL4raXE2t0oc1tFtjXtebOajn1GMqNjMGEwDgYDVR0PAQH/BAQDAgIEMA8GA1UdEwEB +/wQFMAMBAf8wHQYDVR0OBBYEFGAGNejnrWkdKSNN3Tk0bAXsPKUKMB8GA1UdIwQYMBaAFKYLhqTw +yH8ztWE5Ys0956c6QoNIMAoGCCqGSM49BAMDA2kAMGYCMQDRxapkNz6xvgZugF/pEkeUNt2LdZS2 +dXFt+kF4OsY0VtuQFduSrLFa/FhuK46trWUCMQCRsy7zJhac0BU9/FeJ0v8M7N8zMQdnqRPpQWed +9Zl0n6uyCpb50qiVVEH/dFgrX9k= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDgDCCAWigAwIBAgIKA4gmZ2BliZaGDjANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQFExBmOTIw +MDllODUzYjZiMDQ1MB4XDTIyMDEyNjIyNDk0NVoXDTM3MDEyMjIyNDk0NVowKTETMBEGA1UEChMK +R29vZ2xlIExMQzESMBAGA1UEAxMJRHJvaWQgQ0EyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE+9mb +WCdCNnrRYaLr7VbNLAc72LMfLYTQmVdcLAz77DA0kz4o/jNcARQ9NDlJ9m31OW+ytv7djZF3Nvv1 +fYPvpnW+kqERpifwBvUnGOtCykgO4j0+4Gf+fqtLZxDz2SQqo2YwZDAdBgNVHQ4EFgQUpguGpPDI +fzO1YTlizT3npzpCg0gwHwYDVR0jBBgwFoAUNmHhAHyIBQlRi0RsR/8aTMnqTxIwEgYDVR0TAQH/ +BAgwBgEB/wIBAjAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAK6Qdni2yhzXEukN +03dze2QoFSzdKgOwm6DPhbbuGGAHB8Yfnv7JO0+1zoOUuHfWvww+5iF4BDUgTwf31agpwWkgyjSd +51Lgtf/YHE/eaeJCiaNLanLFsPFoClSYTbmQje3f84hy4kUXKyrWo/eOEx87Mu7wfqUmou4E2of0 +Saw0CPdWw1CYJXfP6f0AG1Z2APKPprDtLESsYBdVeULgcAU36XZKrIai958AZtLKH6iP6zPiTkGr +2t/iLqx735M4qIjidLhSZwRlY6WRcBsLJsisM5ft6kSpZB4IADird5UEOBoiZzgptdCa8T2tmWtC +uv5MpOmMr70XBTWouXo95zCiT4Pnnhtp0k+jenjxbmnqDUJw+F5GoBhREGM3Kr7HRbJrG1BTIIRZ +e8xFWHbHLkoAhvd/cMVtSYCshuXHuwiONN9vMPSLjn/JlEv1t4uI0n8agiW3oMqP0ig6QyC54SVA +ctE93zfJr/QMjtLqCQZb56ICFb9knaWFLfdr8johjMtycf2UVoyEWu4iFd1Z4yyP/6YAq10CzIp2 +VhFrMVcYNuZ65PLt9p2XeuwyTd5Nhbn0W7Jh2ZcvQi6ND+/ZZCBAt64ny6qiXg8h0DWgTFAugUg2 +eUSQrTI0mcNsS+c9F/f8wbClT5DFutYTISs1ZmDS3tQyUADUT/np67uYtaF5 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFHDCCAwSgAwIBAgIJANUP8luj8tazMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNVBAUTEGY5MjAw +OWU4NTNiNmIwNDUwHhcNMTkxMTIyMjAzNzU4WhcNMzQxMTE4MjAzNzU4WjAbMRkwFwYDVQQFExBm +OTIwMDllODUzYjZiMDQ1MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAr7bHgiuxpwHs +K7Qui8xUFmOr75gvMsd/dTEDDJdSSxtf6An7xyqpRR90PL2abxM1dEqlXnf2tqw1Ne4Xwl5jlRfd +nJLmN0pTy/4lj4/7tv0Sk3iiKkypnEUtR6WfMgH0QZfKHM1+di+y9TFRtv6y//0rb+T+W8a9nsNL +/ggjnar86461qO0rOs2cXjp3kOG1FEJ5MVmFmBGtnrKpa73XpXyTqRxB/M0n1n/W9nGqC4FSYa04 +T6N5RIZGBN2z2MT5IKGbFlbC8UrW0DxW7AYImQQcHtGl/m00QLVWutHQoVJYnFPlXTcHYvASLu+R +hhsbDmxMgJJ0mcDpvsC4PjvB+TxywElgS70vE0XmLD+OJtvsBslHZvPBKCOdT0MS+tgSOIfga+z1 +Z1g7+DVagf7quvmag8jfPioyKvxnK/EgsTUVi2ghzq8wm27ud/mIM7AY2qEORR8Go3TVB4HzWQgp +Zrt3i5MIlCaY504LzSRiigHCzAPlHws+W0rB5N+er5/2pJKnfBSDiCiFAVtCLOZ7gLiMm0jhO2B6 +tUXHI/+MRPjy02i59lINMRRev56GKtcd9qO/0kUJWdZTdA2XoS82ixPvZtXQpUpuL12ab+9EaDK8 +Z4RHJYYfCT3Q5vNAXaiWQ+8PTWm2QgBR/bkwSWc+NpUFgNPN9PvQi8WEg5UmAGMCAwEAAaNjMGEw +HQYDVR0OBBYEFDZh4QB8iAUJUYtEbEf/GkzJ6k8SMB8GA1UdIwQYMBaAFDZh4QB8iAUJUYtEbEf/ +GkzJ6k8SMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgIEMA0GCSqGSIb3DQEBCwUAA4IC +AQBOMaBc8oumXb2voc7XCWnuXKhBBK3e2KMGz39t7lA3XXRe2ZLLAkLM5y3J7tURkf5a1SutfdOy +XAmeE6SRo83Uh6WszodmMkxK5GM4JGrnt4pBisu5igXEydaW7qq2CdC6DOGjG+mEkN8/TA6p3cno +L/sPyz6evdjLlSeJ8rFBH6xWyIZCbrcpYEJzXaUOEaxxXxgYz5/cTiVKN2M1G2okQBUIYSY6bjEL +4aUN5cfo7ogP3UvliEo3Eo0YgwuzR2v0KR6C1cZqZJSTnghIC/vAD32KdNQ+c3N+vl2OTsUVMC1G +iWkngNx1OO1+kXW+YTnnTUOtOIswUP/Vqd5SYgAImMAfY8U9/iIgkQj6T2W6FsScy94IN9fFhE1U +tzmLoBIuUFsVXJMTz+Jucth+IqoWFua9v1R93/k98p41pjtFX+H8DslVgfP097vju4KDlqN64xV1 +grw3ZLl4CiOe/A91oeLm2UHOq6wn3esB4r2EIQKb6jTVGu5sYCcdWpXr0AUVqcABPdgL+H7qJguB +w09ojm6xNIrw2OocrDKsudk/okr/AwqEyPKw9WnMlQgLIKw1rODG2NvU9oR3GVGdMkUBZutL8VuF +kERQGt6vQ2OCw0sV47VMkuYbacK/xyZFiRcrPJPb41zgbQj9XAEyLKCHex0SdDrx+tWUDqG8At2J +HA== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/server/src/test/resources/fake_cert_chain_with_attest_keys.pem b/server/src/test/resources/fake_cert_chain_with_attest_keys.pem new file mode 100644 index 0000000..13127c0 --- /dev/null +++ b/server/src/test/resources/fake_cert_chain_with_attest_keys.pem @@ -0,0 +1,122 @@ +-----BEGIN CERTIFICATE----- +MIICfjCCAiSgAwIBAgIBATAKBggqhkjOPQQDAjAfMR0wGwYDVQQDExRBbmRyb2lkIEtleXN0b3Jl +IEtleTAeFw0yMzAzMDgxNTE4MTBaFw0yNDAzMDgxNTE4MTBaMA4xDDAKBgNVBAMMA2ZvbzBZMBMG +ByqGSM49AgEGCCqGSM49AwEHA0IABNKtElbRfb/Ru89GShsmS7snW3j5galv97kCBmE2uEZSaXYM +fXel5FgjV8PV3kw9om52dH5x5HThjBAl2jdGL02jggFgMIIBXDCCAVgGCisGAQQB1nkCAREEggFI +MIIBRAICAMgKAQECAgDICgEBBAljaGFsbGVuZ2UEADCBgr+DEAgCBgGGwcz0Qr+DEQgCBgGGwdw2 +gr+DEggCBgGGwet4wr+FPQgCBgGGwc0bvL+FRU4ETDBKMSQwIgQdY29tLmdvb2dsZS5hdHRlc3Rh +dGlvbmV4YW1wbGUCAQExIgQgaIVtHQb2N9YlX6zlsiTbQ6lRSs5Ti7FUi4REgPzYXIcwgaGhBTED +AgECogMCAQOjBAICAQClBTEDAgEEqgMCAQG/g3cCBQC/hT4DAgEAv4VATDBKBCAmrExgvrHjeDV8 +rQwwYTR6+N9vuruw2M6iRFhV7gHjaAEB/woBAAQg6qRTOVd036ERIVxge30J8SVX92UV0fqXFpbH +HasWfkG/hUEFAgMB+9C/hUIFAgMDFj6/hU4GAgQBNLA9v4VPBgIEATSwPTAKBggqhkjOPQQDAgNI +ADBFAiEAudKg42DP60KG6csLJPIHI5fyxene1EAdvOBMEMIbBUQCIHnzbt5aRjnNLrwEg8awSYDr +M9L8OyEVU+bdj1A3HAFH +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICnzCCAkWgAwIBAgIBATAKBggqhkjOPQQDAjAfMR0wGwYDVQQDExRBbmRyb2lkIEtleXN0b3Jl +IEtleTAeFw03MDAxMDEwMDAwMDBaFw00ODAxMDEwMDAwMDBaMB8xHTAbBgNVBAMTFEFuZHJvaWQg +S2V5c3RvcmUgS2V5MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE+d9YJNnblaJJIZMcsurfw82P +s6C7wBiWHuBY/G1ubjoGr7oN0WmzFVvLt9VHV/62RpossZ3KtT9v/6wEIkx6CaOCAXAwggFsMA4G +A1UdDwEB/wQEAwIHgDCCAVgGCisGAQQB1nkCAREEggFIMIIBRAICAMgKAQECAgDICgEBBAljaGFs +bGVuZ2UEADCBgr+DEAgCBgGGwcz0Qr+DEQgCBgGGwdw2gr+DEggCBgGGwet4wr+FPQgCBgGGwc0b +vL+FRU4ETDBKMSQwIgQdY29tLmdvb2dsZS5hdHRlc3RhdGlvbmV4YW1wbGUCAQExIgQgaIVtHQb2 +N9YlX6zlsiTbQ6lRSs5Ti7FUi4REgPzYXIcwgaGhBTEDAgECogMCAQOjBAICAQClBTEDAgEEqgMC +AQG/g3cCBQC/hT4DAgEAv4VATDBKBCAmrExgvrHjeDV8rQwwYTR6+N9vuruw2M6iRFhV7gHjaAEB +/woBAAQg6qRTOVd036ERIVxge30J8SVX92UV0fqXFpbHHasWfkG/hUEFAgMB+9C/hUIFAgMDFj6/ +hU4GAgQBNLA9v4VPBgIEATSwPTAKBggqhkjOPQQDAgNIADBFAiBOeTUgRukDlR9qJogkgNy/12vU +0fc7YRsjqaz69sSHNAIhAK1SeuOja411RlWjzczeQJEVxETZ0X0vh6VBpNUtLG9b +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICmDCCAj6gAwIBAgIBATAKBggqhkjOPQQDAjAfMR0wGwYDVQQDExRBbmRyb2lkIEtleXN0b3Jl +IEtleTAeFw03MDAxMDEwMDAwMDBaFw00ODAxMDEwMDAwMDBaMB8xHTAbBgNVBAMTFEFuZHJvaWQg +S2V5c3RvcmUgS2V5MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEzYNhwbo7IzSsIty/ifWHJpfk +bTlmbb7Q9Y4Qm3guDcukwfpvoE5eHtJ8kIQtDe8t9FSxPuAXd66fX30mfOL/u6OCAWkwggFlMA4G +A1UdDwEB/wQEAwIHgDCCAVEGCisGAQQB1nkCAREEggFBMIIBPQICAMgKAQECAgDICgEBBAljaGFs +bGVuZ2UEADCBgr+DEAgCBgGGwcz0Qr+DEQgCBgGGwet4wr+DEggCBgGGwet4wr+FPQgCBgGGwc0b +hb+FRU4ETDBKMSQwIgQdY29tLmdvb2dsZS5hdHRlc3RhdGlvbmV4YW1wbGUCAQExIgQgaIVtHQb2 +N9YlX6zlsiTbQ6lRSs5Ti7FUi4REgPzYXIcwgZqhBTEDAgEHogMCAQOjBAICAQCqAwIBAb+DdwIF +AL+FPgMCAQC/hUBMMEoEICasTGC+seN4NXytDDBhNHr432+6u7DYzqJEWFXuAeNoAQH/CgEABCDq +pFM5V3TfoREhXGB7fQnxJVf3ZRXR+pcWlscdqxZ+Qb+FQQUCAwH70L+FQgUCAwMWPr+FTgYCBAE0 +sD2/hU8GAgQBNLA9MAoGCCqGSM49BAMCA0gAMEUCIE/rD8Md49xMd9/UI+4d8NKCSljDT/Jji43D +d2TfFcbXAiEA6gWtZ4K2PfsE/BDCKxYKgNVSOg3TrTAUsmbZwvkNfcc= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICszCCAligAwIBAgIBATAKBggqhkjOPQQDAjA5MQwwCgYDVQQKEwNURUUxKTAnBgNVBAMTIGQw +NWZhY2Y0NDNlZDUzNTU0OGQ5OTRmNjg0NWU2ZDNjMB4XDTcwMDEwMTAwMDAwMFoXDTQ4MDEwMTAw +MDAwMFowHzEdMBsGA1UEAxMUQW5kcm9pZCBLZXlzdG9yZSBLZXkwWTATBgcqhkjOPQIBBggqhkjO +PQMBBwNCAARumgw+nY2PrWVwoNFMdC060TQb4nHqVQzFpyRL4dBi5VOq+eUDKqxSXn2UzBV5fvAo +AekBOTICIeH+DzaEpw1ro4IBaTCCAWUwDgYDVR0PAQH/BAQDAgeAMIIBUQYKKwYBBAHWeQIBEQSC +AUEwggE9AgIAyAoBAQICAMgKAQEECWNoYWxsZW5nZQQAMIGCv4MQCAIGAYbBzPRCv4MRCAIGAYbB +63jCv4MSCAIGAYbB63jCv4U9CAIGAYbBzRtXv4VFTgRMMEoxJDAiBB1jb20uZ29vZ2xlLmF0dGVz +dGF0aW9uZXhhbXBsZQIBATEiBCBohW0dBvY31iVfrOWyJNtDqVFKzlOLsVSLhESA/NhchzCBmqEF +MQMCAQeiAwIBA6MEAgIBAKoDAgEBv4N3AgUAv4U+AwIBAL+FQEwwSgQgJqxMYL6x43g1fK0MMGE0 +evjfb7q7sNjOokRYVe4B42gBAf8KAQAEIOqkUzlXdN+hESFcYHt9CfElV/dlFdH6lxaWxx2rFn5B +v4VBBQIDAfvQv4VCBQIDAxY+v4VOBgIEATSwPb+FTwYCBAE0sD0wCgYIKoZIzj0EAwIDSQAwRgIh +AOUJl+arFbXfr4rkKTCjKwXPAZsM6t95ep1S+pBeL4TuAiEAyFEvWvwcsSczYGg1GN8ZYPPqVhsz +CiLh5Lq3IVTyLrY= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIBxDCCAWqgAwIBAgIRANBfrPRD7VNVSNmU9oRebTwwCgYIKoZIzj0EAwIwKTETMBEGA1UEChMK +R29vZ2xlIExMQzESMBAGA1UEAxMJRHJvaWQgQ0EzMB4XDTIzMDIxODAxMzM1MloXDTIzMDMyNDAx +MzM1MlowOTEMMAoGA1UEChMDVEVFMSkwJwYDVQQDEyBkMDVmYWNmNDQzZWQ1MzU1NDhkOTk0ZjY4 +NDVlNmQzYzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABHExGJmFHbe4bBnbxXer2haFmsyBMRCy +HPdjwUzOQ1jKt+OhQ2JI0EQdJuDC4tyM2byZhxXlvP6itjzkLSju69qjYzBhMB0GA1UdDgQWBBQp +APiyZzxgyCuIv++2jELSN/zsMjAfBgNVHSMEGDAWgBRgBjXo561pHSkjTd05NGwF7DylCjAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwICBDAKBggqhkjOPQQDAgNIADBFAiBZK4xVrYp17UeA +3XpKV9aXjFB8nXGdhpL6irqADHXBcgIhAItlP0fTqTocHWBuz4vxnZsZyAUgyio14rgmwsi0eVkb +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIB2DCCAV2gAwIBAgIUAIGiWxUvRzifGggDzLZIEaw9lcIwCgYIKoZIzj0EAwMwKTETMBEGA1UE +ChMKR29vZ2xlIExMQzESMBAGA1UEAxMJRHJvaWQgQ0EyMB4XDTIzMDIxOTE4MjgzNloXDTIzMDMy +NjE4MjgzNVowKTETMBEGA1UEChMKR29vZ2xlIExMQzESMBAGA1UEAxMJRHJvaWQgQ0EzMFkwEwYH +KoZIzj0CAQYIKoZIzj0DAQcDQgAEFIf+wsXWQsQwKh86h02Jx/Lk2pn+n4SFErM0ypR4P9mtc1w3 +/FOnR/XYUSL4raXE2t0oc1tFtjXtebOajn1GMqNjMGEwDgYDVR0PAQH/BAQDAgIEMA8GA1UdEwEB +/wQFMAMBAf8wHQYDVR0OBBYEFGAGNejnrWkdKSNN3Tk0bAXsPKUKMB8GA1UdIwQYMBaAFKYLhqTw +yH8ztWE5Ys0956c6QoNIMAoGCCqGSM49BAMDA2kAMGYCMQDRxapkNz6xvgZugF/pEkeUNt2LdZS2 +dXFt+kF4OsY0VtuQFduSrLFa/FhuK46trWUCMQCRsy7zJhac0BU9/FeJ0v8M7N8zMQdnqRPpQWed +9Zl0n6uyCpb50qiVVEH/dFgrX9k= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDgDCCAWigAwIBAgIKA4gmZ2BliZaGDjANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQFExBmOTIw +MDllODUzYjZiMDQ1MB4XDTIyMDEyNjIyNDk0NVoXDTM3MDEyMjIyNDk0NVowKTETMBEGA1UEChMK +R29vZ2xlIExMQzESMBAGA1UEAxMJRHJvaWQgQ0EyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE+9mb +WCdCNnrRYaLr7VbNLAc72LMfLYTQmVdcLAz77DA0kz4o/jNcARQ9NDlJ9m31OW+ytv7djZF3Nvv1 +fYPvpnW+kqERpifwBvUnGOtCykgO4j0+4Gf+fqtLZxDz2SQqo2YwZDAdBgNVHQ4EFgQUpguGpPDI +fzO1YTlizT3npzpCg0gwHwYDVR0jBBgwFoAUNmHhAHyIBQlRi0RsR/8aTMnqTxIwEgYDVR0TAQH/ +BAgwBgEB/wIBAjAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAK6Qdni2yhzXEukN +03dze2QoFSzdKgOwm6DPhbbuGGAHB8Yfnv7JO0+1zoOUuHfWvww+5iF4BDUgTwf31agpwWkgyjSd +51Lgtf/YHE/eaeJCiaNLanLFsPFoClSYTbmQje3f84hy4kUXKyrWo/eOEx87Mu7wfqUmou4E2of0 +Saw0CPdWw1CYJXfP6f0AG1Z2APKPprDtLESsYBdVeULgcAU36XZKrIai958AZtLKH6iP6zPiTkGr +2t/iLqx735M4qIjidLhSZwRlY6WRcBsLJsisM5ft6kSpZB4IADird5UEOBoiZzgptdCa8T2tmWtC +uv5MpOmMr70XBTWouXo95zCiT4Pnnhtp0k+jenjxbmnqDUJw+F5GoBhREGM3Kr7HRbJrG1BTIIRZ +e8xFWHbHLkoAhvd/cMVtSYCshuXHuwiONN9vMPSLjn/JlEv1t4uI0n8agiW3oMqP0ig6QyC54SVA +ctE93zfJr/QMjtLqCQZb56ICFb9knaWFLfdr8johjMtycf2UVoyEWu4iFd1Z4yyP/6YAq10CzIp2 +VhFrMVcYNuZ65PLt9p2XeuwyTd5Nhbn0W7Jh2ZcvQi6ND+/ZZCBAt64ny6qiXg8h0DWgTFAugUg2 +eUSQrTI0mcNsS+c9F/f8wbClT5DFutYTISs1ZmDS3tQyUADUT/np67uYtaF5 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFHDCCAwSgAwIBAgIJANUP8luj8tazMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNVBAUTEGY5MjAw +OWU4NTNiNmIwNDUwHhcNMTkxMTIyMjAzNzU4WhcNMzQxMTE4MjAzNzU4WjAbMRkwFwYDVQQFExBm +OTIwMDllODUzYjZiMDQ1MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAr7bHgiuxpwHs +K7Qui8xUFmOr75gvMsd/dTEDDJdSSxtf6An7xyqpRR90PL2abxM1dEqlXnf2tqw1Ne4Xwl5jlRfd +nJLmN0pTy/4lj4/7tv0Sk3iiKkypnEUtR6WfMgH0QZfKHM1+di+y9TFRtv6y//0rb+T+W8a9nsNL +/ggjnar86461qO0rOs2cXjp3kOG1FEJ5MVmFmBGtnrKpa73XpXyTqRxB/M0n1n/W9nGqC4FSYa04 +T6N5RIZGBN2z2MT5IKGbFlbC8UrW0DxW7AYImQQcHtGl/m00QLVWutHQoVJYnFPlXTcHYvASLu+R +hhsbDmxMgJJ0mcDpvsC4PjvB+TxywElgS70vE0XmLD+OJtvsBslHZvPBKCOdT0MS+tgSOIfga+z1 +Z1g7+DVagf7quvmag8jfPioyKvxnK/EgsTUVi2ghzq8wm27ud/mIM7AY2qEORR8Go3TVB4HzWQgp +Zrt3i5MIlCaY504LzSRiigHCzAPlHws+W0rB5N+er5/2pJKnfBSDiCiFAVtCLOZ7gLiMm0jhO2B6 +tUXHI/+MRPjy02i59lINMRRev56GKtcd9qO/0kUJWdZTdA2XoS82ixPvZtXQpUpuL12ab+9EaDK8 +Z4RHJYYfCT3Q5vNAXaiWQ+8PTWm2QgBR/bkwSWc+NpUFgNPN9PvQi8WEg5UmAGMCAwEAAaNjMGEw +HQYDVR0OBBYEFDZh4QB8iAUJUYtEbEf/GkzJ6k8SMB8GA1UdIwQYMBaAFDZh4QB8iAUJUYtEbEf/ +GkzJ6k8SMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgIEMA0GCSqGSIb3DQEBCwUAA4IC +AQBOMaBc8oumXb2voc7XCWnuXKhBBK3e2KMGz39t7lA3XXRe2ZLLAkLM5y3J7tURkf5a1SutfdOy +XAmeE6SRo83Uh6WszodmMkxK5GM4JGrnt4pBisu5igXEydaW7qq2CdC6DOGjG+mEkN8/TA6p3cno +L/sPyz6evdjLlSeJ8rFBH6xWyIZCbrcpYEJzXaUOEaxxXxgYz5/cTiVKN2M1G2okQBUIYSY6bjEL +4aUN5cfo7ogP3UvliEo3Eo0YgwuzR2v0KR6C1cZqZJSTnghIC/vAD32KdNQ+c3N+vl2OTsUVMC1G +iWkngNx1OO1+kXW+YTnnTUOtOIswUP/Vqd5SYgAImMAfY8U9/iIgkQj6T2W6FsScy94IN9fFhE1U +tzmLoBIuUFsVXJMTz+Jucth+IqoWFua9v1R93/k98p41pjtFX+H8DslVgfP097vju4KDlqN64xV1 +grw3ZLl4CiOe/A91oeLm2UHOq6wn3esB4r2EIQKb6jTVGu5sYCcdWpXr0AUVqcABPdgL+H7qJguB +w09ojm6xNIrw2OocrDKsudk/okr/AwqEyPKw9WnMlQgLIKw1rODG2NvU9oR3GVGdMkUBZutL8VuF +kERQGt6vQ2OCw0sV47VMkuYbacK/xyZFiRcrPJPb41zgbQj9XAEyLKCHex0SdDrx+tWUDqG8At2J +HA== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/server/src/test/resources/normal_cert_chain.pem b/server/src/test/resources/normal_cert_chain.pem new file mode 100644 index 0000000..26af952 --- /dev/null +++ b/server/src/test/resources/normal_cert_chain.pem @@ -0,0 +1,80 @@ +-----BEGIN CERTIFICATE----- +MIICuTCCAl+gAwIBAgIBATAKBggqhkjOPQQDAjA5MQwwCgYDVQQKEwNURUUxKTAnBgNVBAMTIGQw +NWZhY2Y0NDNlZDUzNTU0OGQ5OTRmNjg0NWU2ZDNjMB4XDTcwMDEwMTAwMDAwMFoXDTQ4MDEwMTAw +MDAwMFowHzEdMBsGA1UEAxMUQW5kcm9pZCBLZXlzdG9yZSBLZXkwWTATBgcqhkjOPQIBBggqhkjO +PQMBBwNCAATlEk81F62fSuW5++oaWJuzZbgUovEpFp0uCA8tALfCeTtktSK61cUp86sMVI9lFxvo +6QpTneTaRn3VkgaDeuXYo4IBcDCCAWwwDgYDVR0PAQH/BAQDAgeAMIIBWAYKKwYBBAHWeQIBEQSC +AUgwggFEAgIAyAoBAQICAMgKAQEECWNoYWxsZW5nZQQAMIGCv4MQCAIGAYbBoxs/v4MRCAIGAYbB +sl1/v4MSCAIGAYbBwZ+/v4U9CAIGAYbBo0KWv4VFTgRMMEoxJDAiBB1jb20uZ29vZ2xlLmF0dGVz +dGF0aW9uZXhhbXBsZQIBATEiBCBohW0dBvY31iVfrOWyJNtDqVFKzlOLsVSLhESA/NhchzCBoaEF +MQMCAQKiAwIBA6MEAgIBAKUFMQMCAQSqAwIBAb+DdwIFAL+FPgMCAQC/hUBMMEoEICasTGC+seN4 +NXytDDBhNHr432+6u7DYzqJEWFXuAeNoAQH/CgEABCDqpFM5V3TfoREhXGB7fQnxJVf3ZRXR+pcW +lscdqxZ+Qb+FQQUCAwH70L+FQgUCAwMWPr+FTgYCBAE0sD2/hU8GAgQBNLA9MAoGCCqGSM49BAMC +A0gAMEUCIQDn6o9XqsHmkT2d1EyzlGWJcZEyoXARjM3Hkmzm7vMvNwIgBWhp60QJKwr1VSNggJp+ +pJv2WJOxkdTOLHy85MJMXhU= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIBxDCCAWqgAwIBAgIRANBfrPRD7VNVSNmU9oRebTwwCgYIKoZIzj0EAwIwKTETMBEGA1UEChMK +R29vZ2xlIExMQzESMBAGA1UEAxMJRHJvaWQgQ0EzMB4XDTIzMDIxODAxMzM1MloXDTIzMDMyNDAx +MzM1MlowOTEMMAoGA1UEChMDVEVFMSkwJwYDVQQDEyBkMDVmYWNmNDQzZWQ1MzU1NDhkOTk0ZjY4 +NDVlNmQzYzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABHExGJmFHbe4bBnbxXer2haFmsyBMRCy +HPdjwUzOQ1jKt+OhQ2JI0EQdJuDC4tyM2byZhxXlvP6itjzkLSju69qjYzBhMB0GA1UdDgQWBBQp +APiyZzxgyCuIv++2jELSN/zsMjAfBgNVHSMEGDAWgBRgBjXo561pHSkjTd05NGwF7DylCjAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwICBDAKBggqhkjOPQQDAgNIADBFAiBZK4xVrYp17UeA +3XpKV9aXjFB8nXGdhpL6irqADHXBcgIhAItlP0fTqTocHWBuz4vxnZsZyAUgyio14rgmwsi0eVkb +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIB2DCCAV2gAwIBAgIUAIGiWxUvRzifGggDzLZIEaw9lcIwCgYIKoZIzj0EAwMwKTETMBEGA1UE +ChMKR29vZ2xlIExMQzESMBAGA1UEAxMJRHJvaWQgQ0EyMB4XDTIzMDIxOTE4MjgzNloXDTIzMDMy +NjE4MjgzNVowKTETMBEGA1UEChMKR29vZ2xlIExMQzESMBAGA1UEAxMJRHJvaWQgQ0EzMFkwEwYH +KoZIzj0CAQYIKoZIzj0DAQcDQgAEFIf+wsXWQsQwKh86h02Jx/Lk2pn+n4SFErM0ypR4P9mtc1w3 +/FOnR/XYUSL4raXE2t0oc1tFtjXtebOajn1GMqNjMGEwDgYDVR0PAQH/BAQDAgIEMA8GA1UdEwEB +/wQFMAMBAf8wHQYDVR0OBBYEFGAGNejnrWkdKSNN3Tk0bAXsPKUKMB8GA1UdIwQYMBaAFKYLhqTw +yH8ztWE5Ys0956c6QoNIMAoGCCqGSM49BAMDA2kAMGYCMQDRxapkNz6xvgZugF/pEkeUNt2LdZS2 +dXFt+kF4OsY0VtuQFduSrLFa/FhuK46trWUCMQCRsy7zJhac0BU9/FeJ0v8M7N8zMQdnqRPpQWed +9Zl0n6uyCpb50qiVVEH/dFgrX9k= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDgDCCAWigAwIBAgIKA4gmZ2BliZaGDjANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQFExBmOTIw +MDllODUzYjZiMDQ1MB4XDTIyMDEyNjIyNDk0NVoXDTM3MDEyMjIyNDk0NVowKTETMBEGA1UEChMK +R29vZ2xlIExMQzESMBAGA1UEAxMJRHJvaWQgQ0EyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE+9mb +WCdCNnrRYaLr7VbNLAc72LMfLYTQmVdcLAz77DA0kz4o/jNcARQ9NDlJ9m31OW+ytv7djZF3Nvv1 +fYPvpnW+kqERpifwBvUnGOtCykgO4j0+4Gf+fqtLZxDz2SQqo2YwZDAdBgNVHQ4EFgQUpguGpPDI +fzO1YTlizT3npzpCg0gwHwYDVR0jBBgwFoAUNmHhAHyIBQlRi0RsR/8aTMnqTxIwEgYDVR0TAQH/ +BAgwBgEB/wIBAjAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAK6Qdni2yhzXEukN +03dze2QoFSzdKgOwm6DPhbbuGGAHB8Yfnv7JO0+1zoOUuHfWvww+5iF4BDUgTwf31agpwWkgyjSd +51Lgtf/YHE/eaeJCiaNLanLFsPFoClSYTbmQje3f84hy4kUXKyrWo/eOEx87Mu7wfqUmou4E2of0 +Saw0CPdWw1CYJXfP6f0AG1Z2APKPprDtLESsYBdVeULgcAU36XZKrIai958AZtLKH6iP6zPiTkGr +2t/iLqx735M4qIjidLhSZwRlY6WRcBsLJsisM5ft6kSpZB4IADird5UEOBoiZzgptdCa8T2tmWtC +uv5MpOmMr70XBTWouXo95zCiT4Pnnhtp0k+jenjxbmnqDUJw+F5GoBhREGM3Kr7HRbJrG1BTIIRZ +e8xFWHbHLkoAhvd/cMVtSYCshuXHuwiONN9vMPSLjn/JlEv1t4uI0n8agiW3oMqP0ig6QyC54SVA +ctE93zfJr/QMjtLqCQZb56ICFb9knaWFLfdr8johjMtycf2UVoyEWu4iFd1Z4yyP/6YAq10CzIp2 +VhFrMVcYNuZ65PLt9p2XeuwyTd5Nhbn0W7Jh2ZcvQi6ND+/ZZCBAt64ny6qiXg8h0DWgTFAugUg2 +eUSQrTI0mcNsS+c9F/f8wbClT5DFutYTISs1ZmDS3tQyUADUT/np67uYtaF5 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFHDCCAwSgAwIBAgIJANUP8luj8tazMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNVBAUTEGY5MjAw +OWU4NTNiNmIwNDUwHhcNMTkxMTIyMjAzNzU4WhcNMzQxMTE4MjAzNzU4WjAbMRkwFwYDVQQFExBm +OTIwMDllODUzYjZiMDQ1MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAr7bHgiuxpwHs +K7Qui8xUFmOr75gvMsd/dTEDDJdSSxtf6An7xyqpRR90PL2abxM1dEqlXnf2tqw1Ne4Xwl5jlRfd +nJLmN0pTy/4lj4/7tv0Sk3iiKkypnEUtR6WfMgH0QZfKHM1+di+y9TFRtv6y//0rb+T+W8a9nsNL +/ggjnar86461qO0rOs2cXjp3kOG1FEJ5MVmFmBGtnrKpa73XpXyTqRxB/M0n1n/W9nGqC4FSYa04 +T6N5RIZGBN2z2MT5IKGbFlbC8UrW0DxW7AYImQQcHtGl/m00QLVWutHQoVJYnFPlXTcHYvASLu+R +hhsbDmxMgJJ0mcDpvsC4PjvB+TxywElgS70vE0XmLD+OJtvsBslHZvPBKCOdT0MS+tgSOIfga+z1 +Z1g7+DVagf7quvmag8jfPioyKvxnK/EgsTUVi2ghzq8wm27ud/mIM7AY2qEORR8Go3TVB4HzWQgp +Zrt3i5MIlCaY504LzSRiigHCzAPlHws+W0rB5N+er5/2pJKnfBSDiCiFAVtCLOZ7gLiMm0jhO2B6 +tUXHI/+MRPjy02i59lINMRRev56GKtcd9qO/0kUJWdZTdA2XoS82ixPvZtXQpUpuL12ab+9EaDK8 +Z4RHJYYfCT3Q5vNAXaiWQ+8PTWm2QgBR/bkwSWc+NpUFgNPN9PvQi8WEg5UmAGMCAwEAAaNjMGEw +HQYDVR0OBBYEFDZh4QB8iAUJUYtEbEf/GkzJ6k8SMB8GA1UdIwQYMBaAFDZh4QB8iAUJUYtEbEf/ +GkzJ6k8SMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgIEMA0GCSqGSIb3DQEBCwUAA4IC +AQBOMaBc8oumXb2voc7XCWnuXKhBBK3e2KMGz39t7lA3XXRe2ZLLAkLM5y3J7tURkf5a1SutfdOy +XAmeE6SRo83Uh6WszodmMkxK5GM4JGrnt4pBisu5igXEydaW7qq2CdC6DOGjG+mEkN8/TA6p3cno +L/sPyz6evdjLlSeJ8rFBH6xWyIZCbrcpYEJzXaUOEaxxXxgYz5/cTiVKN2M1G2okQBUIYSY6bjEL +4aUN5cfo7ogP3UvliEo3Eo0YgwuzR2v0KR6C1cZqZJSTnghIC/vAD32KdNQ+c3N+vl2OTsUVMC1G +iWkngNx1OO1+kXW+YTnnTUOtOIswUP/Vqd5SYgAImMAfY8U9/iIgkQj6T2W6FsScy94IN9fFhE1U +tzmLoBIuUFsVXJMTz+Jucth+IqoWFua9v1R93/k98p41pjtFX+H8DslVgfP097vju4KDlqN64xV1 +grw3ZLl4CiOe/A91oeLm2UHOq6wn3esB4r2EIQKb6jTVGu5sYCcdWpXr0AUVqcABPdgL+H7qJguB +w09ojm6xNIrw2OocrDKsudk/okr/AwqEyPKw9WnMlQgLIKw1rODG2NvU9oR3GVGdMkUBZutL8VuF +kERQGt6vQ2OCw0sV47VMkuYbacK/xyZFiRcrPJPb41zgbQj9XAEyLKCHex0SdDrx+tWUDqG8At2J +HA== +-----END CERTIFICATE----- \ No newline at end of file