diff --git a/src/java.base/macosx/classes/apple/security/KeychainStore.java b/src/java.base/macosx/classes/apple/security/KeychainStore.java index 6f70fccbb244b..45385312c7724 100644 --- a/src/java.base/macosx/classes/apple/security/KeychainStore.java +++ b/src/java.base/macosx/classes/apple/security/KeychainStore.java @@ -878,15 +878,9 @@ private void createTrustedCertEntry(String alias, List inputTrust, } if (tce.trustSettings.isEmpty()) { - if (isSelfSigned) { - // If a self-signed certificate has trust settings without specific entries, - // trust it for all purposes - tce.trustedKeyUsageValue = KnownOIDs.anyExtendedKeyUsage.value(); - } else { - // Otherwise, return immediately. The certificate is not - // added into entries. - return; - } + // If there is no trust settings then the certificate was verified against other trusted certificates already + // or it is self-signed + tce.trustedKeyUsageValue = KnownOIDs.anyExtendedKeyUsage.value(); } else { List values = new ArrayList<>(); for (var oneTrust : tce.trustSettings) { diff --git a/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m b/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m index 31572eaeb81f6..c5d9c18b09d89 100644 --- a/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m +++ b/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m @@ -458,6 +458,34 @@ static bool createTrustedCertEntry(JNIEnv *env, jobject keyStore, return true; } +static bool validateCertificate(SecCertificateRef certRef) { + SecTrustRef secTrust = NULL; + CFMutableArrayRef subjCerts = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks); + CFArraySetValueAtIndex(subjCerts, 0, certRef); + + SecPolicyRef policy = SecPolicyCreateBasicX509(); + OSStatus ortn = SecTrustCreateWithCertificates(subjCerts, policy, &secTrust); + bool result = false; + if (ortn) { + /* should never happen */ + cssmPerror("SecTrustCreateWithCertificates", ortn); + goto errOut; + } + + result = SecTrustEvaluateWithError(secTrust, NULL); +errOut: + if (policy) { + CFRelease(policy); + } + if (secTrust) { + CFRelease(secTrust); + } + if (subjCerts) { + CFRelease(subjCerts); + } + return result; +} + static void addCertificatesToKeystore(JNIEnv *env, jobject keyStore, jmethodID jm_createTrustedCertEntry, jclass jc_arrayListClass, @@ -492,9 +520,14 @@ static void addCertificatesToKeystore(JNIEnv *env, jobject keyStore, goto errOut; } - // Only add certificates with trust settings + // If no trust settings we need to verify the certificate first if (inputTrust == NULL) { - continue; + bool valid = validateCertificate(certRef); + if (valid) { + inputTrust = (*env)->NewObject(env, jc_arrayListClass, jm_arrayListCons); + } else { + continue; + } } // Create java object for certificate with trust settings diff --git a/test/jdk/TEST.groups b/test/jdk/TEST.groups index d3b0b3009cafc..8eaab28c9cd51 100644 --- a/test/jdk/TEST.groups +++ b/test/jdk/TEST.groups @@ -657,7 +657,8 @@ jdk_core_manual_interactive = \ jdk_security_manual_interactive = \ sun/security/tools/keytool/i18n.java \ com/sun/security/auth/callback/TextCallbackHandler/Password.java \ - sun/security/krb5/config/native/TestDynamicStore.java + sun/security/krb5/config/native/TestDynamicStore.java \ + java/security/KeyStore/CheckMacOSKeyChainIntermediateCATrust.java # Test sets for running inside container environment jdk_containers_extended = \ diff --git a/test/jdk/java/security/KeyStore/CheckMacOSKeyChainIntermediateCATrust.java b/test/jdk/java/security/KeyStore/CheckMacOSKeyChainIntermediateCATrust.java new file mode 100644 index 0000000000000..1369d7826fc1a --- /dev/null +++ b/test/jdk/java/security/KeyStore/CheckMacOSKeyChainIntermediateCATrust.java @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.nio.file.Path; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.cert.X509Certificate; +import java.util.Iterator; +import java.util.List; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.stream.StreamSupport; + +import jdk.test.lib.process.ProcessTools; + +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/* + * @test + * @bug 8347067 + * @library /test/lib + * @requires os.family == "mac" + * @summary Check whether loading of certificates from macOS Keychain correctly + * loads intermediate CA certificates + * @run junit/manual CheckMacOSKeyChainIntermediateCATrust + */ +public class CheckMacOSKeyChainIntermediateCATrust { + + private static final String DIR = System.getProperty("test.src", "."); + static boolean verbose = false; // avoid too verbose output + + @Test + public void test() throws Throwable { + KeyStore ks = KeyStore.getInstance("KeychainStore"); + ks.load(null, null); + + Iterator iterator = ks.aliases().asIterator(); + List certificates = StreamSupport.stream( + Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false) + .sorted() + .map(alias -> { + try { + return (X509Certificate) ks.getCertificate(alias); + } catch (KeyStoreException e) { + throw new RuntimeException(e); + } + }) + .toList(); + + System.out.println("Verifying expected certificates are trusted"); + + String rootCASubjectName = "CN=Example CA,O=Example,C=US"; + assertThat(containsSubjectName(certificates, rootCASubjectName), + "Root CA not found " + rootCASubjectName, certificates); + + String intermediateCASubjectName = "CN=Example Intermediate CA,O=Example,C=US"; + assertThat(containsSubjectName(certificates, intermediateCASubjectName), + "Intermediate CA not found " + intermediateCASubjectName, certificates); + + String nonTrustedCASubjectName = "CN=Non Trusted Example CA,O=Example,C=US"; + assertThat(not(containsSubjectName(certificates, nonTrustedCASubjectName)), + "Non trusted CA found " + nonTrustedCASubjectName, certificates); + + String nonTrustedIntermediateCASubjectName = "CN=Non Trusted Example Intermediate CA,O=Example,C=US"; + assertThat(not(containsSubjectName(certificates, nonTrustedIntermediateCASubjectName)), + "Non trusted intermediate CA found " + nonTrustedIntermediateCASubjectName, certificates); + } + + @BeforeEach + void setup() { + System.out.println("Adding certificates to key chain"); + addCertificatesToKeyChain(); + } + + @AfterEach + void cleanup() { + System.out.println("Cleaning up"); + deleteCertificatesFromKeyChain(); + } + + private static void addCertificatesToKeyChain() { + String loginKeyChain = getLoginKeyChain(); + + Path caPath = Path.of("%s/%s".formatted(DIR, "test-ca.pem")); + List args = List.of( + "/usr/bin/security", + "add-trusted-cert", + "-k", loginKeyChain, + caPath.toString() + ); + executeProcess(args); + + caPath = Path.of("%s/%s".formatted(DIR, "non-trusted-test-ca.pem")); + args = List.of( + "/usr/bin/security", + "add-certificates", + "-k", loginKeyChain, + caPath.toString() + ); + executeProcess(args); + + caPath = Path.of("%s/%s".formatted(DIR, "test-intermediate-ca.pem")); + args = List.of( + "/usr/bin/security", + "add-certificates", + "-k", loginKeyChain, + caPath.toString() + ); + executeProcess(args); + + } + + private static String getLoginKeyChain() { + return Path.of(System.getProperty("user.home"), "Library/Keychains/login.keychain-db").toString(); + } + + private static void executeProcess(List params) { + System.out.println("Command line: " + params); + try { + ProcessTools.executeProcess(params.toArray(new String[0])) + .shouldHaveExitValue(0); + } catch (Exception e) { + fail("Unexpected exception: " + e); + } + } + + private static void deleteCertificatesFromKeyChain() { + executeProcess( + List.of( + "/usr/bin/security", + "delete-certificate", + "-c", "Non Trusted Example CA", + "-t" + ) + ); + + executeProcess( + List.of( + "/usr/bin/security", + "delete-certificate", + "-c", "Example CA", + "-t" + ) + ); + + executeProcess( + List.of( + "/usr/bin/security", + "delete-certificate", + "-c", "Example Intermediate CA", + "-t" + ) + ); + } + + private static boolean not(boolean condition) { + return !condition; + } + + private static boolean containsSubjectName(List certificates, String subjectName) { + return certificates.stream() + .map(cert -> cert.getSubjectX500Principal().getName()) + .anyMatch(name -> name.contains(subjectName)); + } + + private static List getSubjects(List certificates) { + return certificates.stream() + .map(cert -> cert.getSubjectX500Principal().getName()) + .toList(); + } + + private static void assertThat(boolean expected, String message, List certificates) { + if (!expected) { + String errMessage = message; + if (verbose) { + errMessage += ", subjects: " + String.join(" | ", getSubjects(certificates)); + } + throw new AssertionError(errMessage); + } + } +} diff --git a/test/jdk/java/security/KeyStore/generate-mac-os-intermediate-ca-certs.sh b/test/jdk/java/security/KeyStore/generate-mac-os-intermediate-ca-certs.sh new file mode 100644 index 0000000000000..5434f4baa8f9b --- /dev/null +++ b/test/jdk/java/security/KeyStore/generate-mac-os-intermediate-ca-certs.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash + +set -ex + +cd "$(dirname "$0")" + +openssl genrsa -out root.key 2048 +openssl req -x509 -sha256 -nodes -extensions v3_ca -key root.key -subj "/C=US/O=Example/CN=Example CA" -days 3650 -out test-ca.pem + +openssl genrsa -out intermediate.key 2048 +openssl req -new -sha256 -nodes -key intermediate.key \ + -subj "/C=US/O=Example/CN=Example Intermediate CA" -out test-intermediate-ca.csr + +openssl x509 -req \ + -extensions v3_ca \ + -extfile openssl.cnf \ + -in test-intermediate-ca.csr \ + -CA test-ca.pem \ + -CAkey root.key \ + -CAcreateserial \ + -out test-intermediate-ca.pem \ + -days 3650 \ + -sha256 + +openssl genrsa -out non-trusted-root.key 2048 +openssl req -x509 -sha256 -nodes -extensions v3_ca -key non-trusted-root.key -subj "/C=US/O=Example/CN=Non Trusted Example CA" -days 3650 -out non-trusted-test-ca.pem + +openssl genrsa -out non-trusted-intermediate.key 2048 +openssl req -new -sha256 -nodes -key non-trusted-intermediate.key \ + -subj "/C=US/O=Example/CN=Non Trusted Example Intermediate CA" -out non-trusted-intermediate-ca.csr + +openssl x509 -req \ + -extensions v3_ca \ + -extfile openssl.cnf \ + -in non-trusted-intermediate-ca.csr \ + -CA non-trusted-test-ca.pem \ + -CAkey non-trusted-root.key \ + -CAcreateserial \ + -out non-trusted-intermediate-ca.pem \ + -days 3650 \ + -sha256 + +rm -f non-trusted-root.key root.key test-intermediate-ca.csr intermediate.key test-ca.srl non-trusted-intermediate.key \ + non-trusted-intermediate-ca.csr non-trusted-test-ca.srl diff --git a/test/jdk/java/security/KeyStore/non-trusted-intermediate-ca.pem b/test/jdk/java/security/KeyStore/non-trusted-intermediate-ca.pem new file mode 100644 index 0000000000000..f4ab40a96508f --- /dev/null +++ b/test/jdk/java/security/KeyStore/non-trusted-intermediate-ca.pem @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIIDyTCCArGgAwIBAgIUFqJJqie2b55pDsftOOBqkWJuX6owDQYJKoZIhvcNAQEL +BQAwQDELMAkGA1UEBhMCVVMxEDAOBgNVBAoMB0V4YW1wbGUxHzAdBgNVBAMMFk5v +biBUcnVzdGVkIEV4YW1wbGUgQ0EwHhcNMjUwMTI3MjEyNDM2WhcNMzUwMTI1MjEy +NDM2WjBNMQswCQYDVQQGEwJVUzEQMA4GA1UECgwHRXhhbXBsZTEsMCoGA1UEAwwj +Tm9uIFRydXN0ZWQgRXhhbXBsZSBJbnRlcm1lZGlhdGUgQ0EwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCszrhwXVvR5QkSOoIJg0S5Ij1CqAuYf+WS9Ym6 +itSzk744j4P2pVd7rM+1SfUfVqY7dFoE7JSQBTw3i/ruo7Zl/USuXFZa93w6g3TB +g0sqA2N4UmNm5Y588Dd2cGIBZgNVvwQzsiG6zWdTppH0rL91hgy32M/CGkVH6WaU +nK4xCe5PiheGkvJBn6OaeqWpG0K76fDWmucUzaMv0b+DmRQ4GsXbwloiKndchGzE +/56EcHNAr1mgvnh+ADTXPKjEsHWv+1cQk4ql4Di53GvVJ/n6eh6K8aGD10OyQlIL +Tk82LI+FxiPvRHF/uBUjndgZsK9k/txDm5VY1z4mpMCd2h1nAgMBAAGjga0wgaow +HQYDVR0OBBYEFIhW8ihXHrc2ywJqt9xZbrcYcNzlMHsGA1UdIwR0MHKAFAy/+rvH +8b9QCumbjj7Q6+9hW9ImoUSkQjBAMQswCQYDVQQGEwJVUzEQMA4GA1UECgwHRXhh +bXBsZTEfMB0GA1UEAwwWTm9uIFRydXN0ZWQgRXhhbXBsZSBDQYIUQWptFePVwo9i +HM6KUT93F4mkQvYwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAfEsL +/d07gw8xFs8hMTvXK/5PKEw4WuxoytrWDfwIUJpWJBOjcCmlZnSmwdZ12PHQ1mB9 +oHLr/RZKxYYn2MP9GqDrFTV+wAAAiIw5eU92HQOmPEgXIYhzsvfm29qwR1tdiAQE +4tXc7Y3O2B1b7lcJGbhjAt+/RkDcvT7Pi5jYd2F3apsKPo8GsC0zCsX/t7SnOxhj +qmPsEsBphBfE/dzqkow/iVWPGjvaV2rOrspGOfjF+j+APJNqBuH05uFR7GGaQ2Fm +mhh+nWmmDod/rJpQP5ToTdLeYki9DMsaJjqth1VF5rWUhOzfWczdOFD5szrxxJcV +L+iJJspxFIvQpS3Pgg== +-----END CERTIFICATE----- diff --git a/test/jdk/java/security/KeyStore/non-trusted-test-ca.pem b/test/jdk/java/security/KeyStore/non-trusted-test-ca.pem new file mode 100644 index 0000000000000..9d19a49a71d10 --- /dev/null +++ b/test/jdk/java/security/KeyStore/non-trusted-test-ca.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDYTCCAkmgAwIBAgIUQWptFePVwo9iHM6KUT93F4mkQvYwDQYJKoZIhvcNAQEL +BQAwQDELMAkGA1UEBhMCVVMxEDAOBgNVBAoMB0V4YW1wbGUxHzAdBgNVBAMMFk5v +biBUcnVzdGVkIEV4YW1wbGUgQ0EwHhcNMjUwMTI3MjEyMzU4WhcNMzUwMTI1MjEy +MzU4WjBAMQswCQYDVQQGEwJVUzEQMA4GA1UECgwHRXhhbXBsZTEfMB0GA1UEAwwW +Tm9uIFRydXN0ZWQgRXhhbXBsZSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAKMh6zqtUcvDLwQJTQcKX4XLQ65MrS81OXpzgajZmgd4vgdv/1PtcXkR +Tzqpeyi137BSvn0VM3CM5e4YLHVwg7iarv92v+gEq+sZcErONbdIvHYGp4J9t+1o +YQHfFsGf1juJe6Ey2s4P10FdWLQN+3BMZXwAnaaGCXnYCixs7ocdIpbobUdRLasF +N0NRQ4BZk+vgmqcC69rB66bNUJhkb40mdcqf0aPCpWnd/MHit/NQ/VXyAIEjllZk +i4Jd5aoouOvjI8a7Pp0z+GHFU4RwQjuFfbJvSyeQ5OL1PAn74amwLMnHF+FBJIuW +jwIWmPNDyU9I9WL2YEmi42xhc3R5XIkCAwEAAaNTMFEwHQYDVR0OBBYEFAy/+rvH +8b9QCumbjj7Q6+9hW9ImMB8GA1UdIwQYMBaAFAy/+rvH8b9QCumbjj7Q6+9hW9Im +MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHouuX960Xzb4M1m +QcNV6m7mAjZDdAlRkuTq3ba1dycH8hJrsT3uE3YNXEKiBIkGCYcX1KXomCgWNOdR +AFc10nV4GV0Com149kmD5oeBp9auqmaSPWTJQxyi7dj/gjNGCfbjf/GD3O1qmfqN +RjKQqluP0koXZjUqL3LJro91XNMDxcQH0CcDdhHv6R7Ob0UndaW1neIljo8U0JFx +yMA+pIua3QppElvynSBSlK5jSDmuVTLrRM401hx/1isKAUmCoz9zuVzjygxt8bdL +gKu66Ze/7RRUee2HxEOxkw53gYfBan+918UXd6feq3nC8A9g6v2L6M6/UkWeTiLs +4KjanI4= +-----END CERTIFICATE----- diff --git a/test/jdk/java/security/KeyStore/openssl.cnf b/test/jdk/java/security/KeyStore/openssl.cnf new file mode 100644 index 0000000000000..d7dd4e40a40a3 --- /dev/null +++ b/test/jdk/java/security/KeyStore/openssl.cnf @@ -0,0 +1,17 @@ +[ v3_ca ] + + +# Extensions for a typical CA + + +# PKIX recommendation. + +subjectKeyIdentifier=hash + +authorityKeyIdentifier=keyid:always,issuer:always + +# This is what PKIX recommends but some broken software chokes on critical +# extensions. +#basicConstraints = critical,CA:true +# So we do this instead. +basicConstraints = CA:true diff --git a/test/jdk/java/security/KeyStore/test-ca.pem b/test/jdk/java/security/KeyStore/test-ca.pem new file mode 100644 index 0000000000000..36543be983af9 --- /dev/null +++ b/test/jdk/java/security/KeyStore/test-ca.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDSTCCAjGgAwIBAgIUHYTHHRJWyWjKpg5H2acbXj0aDeUwDQYJKoZIhvcNAQEL +BQAwNDELMAkGA1UEBhMCVVMxEDAOBgNVBAoMB0V4YW1wbGUxEzARBgNVBAMMCkV4 +YW1wbGUgQ0EwHhcNMjUwMTA3MTUxMzExWhcNMzUwMTA1MTUxMzExWjA0MQswCQYD +VQQGEwJVUzEQMA4GA1UECgwHRXhhbXBsZTETMBEGA1UEAwwKRXhhbXBsZSBDQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANQtNFDwJ8KayH0hFHCioT18 +aMToU8SNBT+ogKT7rQhWkqC4aBVS+H3JSN1vG/RN+qWFS/DrTpUb5tVY9mYH5s4p +PqnXXN1EIoOgn+2vYB7sMY/MyAzn3MynDNHE0QYKdxK3H06BrmTgDiDcpYEexRex +B/3p9daJrU9L/EK4l41Vk7jOqu3wq39ECvAdMpt1eIg02nUS1EIxLmfoFRSHHtRf +rRPAU84BdGCYMWuBfxcXqMn4PumfkS3AoG6ul277FUNsvjlmEoQeotuXwCz1ELyy +U3uHnSFItPs/69Bg2FxAeig9zbAnYO9eCYPrhME452tROnOqhm0LjZjR8R4Lbl0C +AwEAAaNTMFEwHQYDVR0OBBYEFGt4wbms5GC1yWwh2TytpEuHpMReMB8GA1UdIwQY +MBaAFGt4wbms5GC1yWwh2TytpEuHpMReMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI +hvcNAQELBQADggEBAAaq5JrVfinF53fBQKwBZYXv7Afr/H04GYVhXqAtl1n65Maj +si4GRBDSyhMWUrwHFNH4SIGHu4LZU2aROXIXrJl3qFXFl3WfdyVZTNjssgVcKFxl +Uav+pISUiIpAZPV55tFkE/2gmpkLUyhaiUQvql4XTZDSU8mTcWovzMVusXQtfo+L +O848Fspo30BvPEUUt1BOhqKwWbHV/2WJ4vYJPt6jFGnDMZHdILCp/DOXBxHS0pxd +0Tofrfum0MUbtScuzjM/otMduwjSalrDhkNLsLxLueXTf6dtnE9CLxaWXhWlAJ70 +0mGFdwvYtLEbLTJKtqqq+lafAt5Af69VoqM1jjo= +-----END CERTIFICATE----- diff --git a/test/jdk/java/security/KeyStore/test-intermediate-ca.pem b/test/jdk/java/security/KeyStore/test-intermediate-ca.pem new file mode 100644 index 0000000000000..41f3219b7c0cd --- /dev/null +++ b/test/jdk/java/security/KeyStore/test-intermediate-ca.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDpTCCAo2gAwIBAgIUBdWVSNEFs3LuTagptBgmihEZrVowDQYJKoZIhvcNAQEL +BQAwNDELMAkGA1UEBhMCVVMxEDAOBgNVBAoMB0V4YW1wbGUxEzARBgNVBAMMCkV4 +YW1wbGUgQ0EwHhcNMjUwMTA3MTUxMzExWhcNMzUwMTA1MTUxMzExWjBBMQswCQYD +VQQGEwJVUzEQMA4GA1UECgwHRXhhbXBsZTEgMB4GA1UEAwwXRXhhbXBsZSBJbnRl +cm1lZGlhdGUgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCXK7MQ +/LfR/zm8fV677S2NCsBVdizTsE5ugYuXGNlrbF26pcyJhK8N/T2l2HAz2UszzRB2 +ZpqyE21SpepYATvG9M3moPEkFiojmhS+3mPhRhgTAxAIYA+hQ+8ics6C2zCvl2vw +5PpHdbZiL+2K/j+DtZxfmJoG0HYWMHeqlbA3smEkNOfOS9rc0kGpu3Q4mCLO+kmb +IofGf9ASsuyWH9GgxCcmUlu6UTRvt57LlTcaz3mncq6V++UDZHOmyTa6q9GIgTUc +sTfcS0aMXfBvsw6eZhlTcWvkXQaJRVb6UeGJwx/Kq715XphWJ9wXc4pT/f7nHinc +utdXjnayO+o3Vk85AgMBAAGjgaEwgZ4wHQYDVR0OBBYEFGlsam1VG6UErlvVa1+p +40CuawniMG8GA1UdIwRoMGaAFGt4wbms5GC1yWwh2TytpEuHpMReoTikNjA0MQsw +CQYDVQQGEwJVUzEQMA4GA1UECgwHRXhhbXBsZTETMBEGA1UEAwwKRXhhbXBsZSBD +QYIUHYTHHRJWyWjKpg5H2acbXj0aDeUwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B +AQsFAAOCAQEAS9n0MIie2TCo+5Wbur7RrX4aOMrKooZwSYxyvb4c+U6zNYBZmkwI +Pqk/LYNU6FMCKCg/PT4kcgGAu+UeYb6K2Llwyej4Tjy/8bCOXgrPTzP4f0COg2wi +y1SlMSEolhslJV46HlZHtrASpE8mj7mh3RRTAkn86gCEd7A/CdQgMrTiwVjOGrza +B5/UGJpVUvm7W5H1UXunYqFrVaMIN0zWfaj4lRgzLAkZ7ldLdBA7mIbc2/C9JSvX +dCezRkjJpIHbXjojtDek1vDy/UopyQRYpz2CPu62o8iM9Iw6M7SzF6d8ud9rzeZ1 +zwtxTCJqohwP3t132oxoYwEyYpF+Xcrvhg== +-----END CERTIFICATE-----