X509 SVID: adding validations and tests

Signed-off-by: Max Lambrecht <maxlambrecht@gmail.com>
This commit is contained in:
Max Lambrecht 2020-05-16 14:10:33 -03:00
parent 8d9bbc065a
commit 5abd112c58
15 changed files with 658 additions and 68 deletions

View File

@ -5,15 +5,15 @@ import spiffe.spiffeid.SpiffeId;
import spiffe.spiffeid.TrustDomain;
import java.io.ByteArrayInputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
import static org.apache.commons.lang3.StringUtils.startsWith;
@ -25,21 +25,40 @@ public class CertificateUtils {
private static final String SPIFFE_PREFIX = "spiffe://";
private static final int SAN_VALUE_INDEX = 1;
private static final String PRIVATE_KEY_ALGORITHM = "EC";
private static final String PUBLIC_KEY_INFRASTRUCTURE_ALGORITHM = "PKIX";
private static final String X509_CERTIFICATE_TYPE = "X.509";
// X509Certificate Key Usage indexes
private static final int DIGITAL_SIGNATURE = 0;
private static final int NON_REPUDIATION = 1;
private static final int KEY_ENCIPHERMENT = 2;
private static final int DATA_ENCIPHERMENT = 3;
private static final int KEY_AGREEMENT = 4;
private static final int KEY_CERT_SIGN = 5;
private static final int CRL_SIGN = 6;
private static final int ENCIPHER_ONLY = 7;
private static final int DECIPHER_ONLY = 8;
/**
* Generate a list of X.509 certificates from a byte array.
*
* @param input as byte array representing a list of X.509 certificates, as a DER or PEM
* @return a List of {@link X509Certificate}
*/
public static List<X509Certificate> generateCertificates(byte[] input) throws CertificateException {
val certificateFactory = getCertificateFactory();
public static List<X509Certificate> generateCertificates(byte[] input) throws CertificateParsingException {
CertificateFactory certificateFactory = null;
try {
certificateFactory = getCertificateFactory();
} catch (CertificateException e) {
throw new IllegalStateException("Could not create Certificate Factory", e);
}
val certificates = certificateFactory
.generateCertificates(new ByteArrayInputStream(input));
Collection<? extends Certificate> certificates;
try {
certificates = certificateFactory.generateCertificates(new ByteArrayInputStream(input));
} catch (CertificateException e) {
throw new CertificateParsingException("Certificate could not be parsed from cert bytes");
}
return certificates.stream()
.map(X509Certificate.class::cast)
@ -54,7 +73,7 @@ public class CertificateUtils {
* @throws InvalidKeySpecException
* @throws NoSuchAlgorithmException
*/
public static PrivateKey generatePrivateKey(byte[] privateKeyBytes) throws InvalidKeySpecException, NoSuchAlgorithmException {
public static PrivateKey generatePrivateKey(byte[] privateKeyBytes) throws InvalidKeySpecException, NoSuchAlgorithmException, InvalidKeyException {
PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(privateKeyBytes);
PrivateKey privateKey = null;
try {
@ -103,7 +122,7 @@ public class CertificateUtils {
}
if (spiffeIds.size() < 1) {
throw new CertificateException("No SPIFFE ID found in the certificate");
throw new CertificateException("Certificate does not contain SPIFFE ID in the URI SAN");
}
return SpiffeId.parse(spiffeIds.get(0));
@ -114,7 +133,6 @@ public class CertificateUtils {
*
* @param chain a list of {@link X509Certificate}
* @return a {@link TrustDomain}
*
* @throws CertificateException
*/
public static TrustDomain getTrustDomain(List<X509Certificate> chain) throws CertificateException {
@ -122,6 +140,56 @@ public class CertificateUtils {
return spiffeId.getTrustDomain();
}
/**
* Validates that the private key and the public key in the x509Certificate match by
* creating a signature with the private key and verifying with the public key.
*
* @throws InvalidKeyException if the keys don't match
*/
public static void validatePrivateKey(PrivateKey privateKey, X509Certificate x509Certificate) throws InvalidKeyException, NoSuchAlgorithmException, SignatureException {
// create a challenge
byte[] challenge = new byte[1000];
ThreadLocalRandom.current().nextBytes(challenge);
Signature sig = null;
if ("RSA".equals(privateKey.getAlgorithm())) {
sig = Signature.getInstance("SHA256withRSA");
} else {
sig = Signature.getInstance("SHA1withECDSA");
}
sig.initSign(privateKey);
sig.update(challenge);
byte[] signature = sig.sign();
sig.initVerify(x509Certificate.getPublicKey());
sig.update(challenge);
if (!sig.verify(signature)) {
throw new InvalidKeyException("Private Key does not match Certificate Public Key");
}
}
public static boolean isCA(X509Certificate cert) {
return cert.getBasicConstraints() != -1;
}
public static boolean hasKeyUsageCertSign(X509Certificate cert) {
boolean[] keyUsage = cert.getKeyUsage();
return keyUsage[KEY_CERT_SIGN];
}
public static boolean hasKeyUsageDigitalSignature(X509Certificate cert) {
boolean[] keyUsage = cert.getKeyUsage();
return keyUsage[DIGITAL_SIGNATURE];
}
public static boolean hasKeyUsageCRLSign(X509Certificate cert) {
boolean[] keyUsage = cert.getKeyUsage();
return keyUsage[CRL_SIGN];
}
private static List<String> getSpiffeIds(X509Certificate certificate) throws CertificateParsingException {
return certificate.getSubjectAlternativeNames()
.stream()
@ -131,7 +199,11 @@ public class CertificateUtils {
}
private static PrivateKey generatePrivateKeyWithSpec(PKCS8EncodedKeySpec kspec) throws NoSuchAlgorithmException, InvalidKeySpecException {
return KeyFactory.getInstance(PRIVATE_KEY_ALGORITHM).generatePrivate(kspec);
try {
return KeyFactory.getInstance("EC").generatePrivate(kspec);
} catch (InvalidKeySpecException e) {
return KeyFactory.getInstance("RSA").generatePrivate(kspec);
}
}
// Create an instance of PKIXParameters used as input for the PKIX CertPathValidator
@ -158,13 +230,18 @@ public class CertificateUtils {
}
// Given a private key in PEM format, encode it as DER
private static byte[] toDerFormat(byte[] privateKeyPem) {
private static byte[] toDerFormat(byte[] privateKeyPem) throws InvalidKeyException {
String privateKeyAsString = new String(privateKeyPem);
privateKeyAsString = privateKeyAsString.replaceAll("(-+BEGIN PRIVATE KEY-+\\r?\\n|-+END PRIVATE KEY-+\\r?\\n?)", "");
privateKeyAsString = privateKeyAsString.replaceAll("\n", "");
val decoder = Base64.getDecoder();
return decoder.decode(privateKeyAsString);
try {
return decoder.decode(privateKeyAsString);
} catch (Exception e) {
throw new InvalidKeyException(e);
}
}
private CertificateUtils() {}
private CertificateUtils() {
}
}

View File

@ -2,7 +2,6 @@ package spiffe.svid.x509svid;
import lombok.NonNull;
import lombok.Value;
import lombok.val;
import spiffe.exception.X509SvidException;
import spiffe.internal.CertificateUtils;
import spiffe.spiffeid.SpiffeId;
@ -10,20 +9,25 @@ import spiffe.spiffeid.SpiffeId;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.SignatureException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.util.List;
import static spiffe.internal.CertificateUtils.*;
/**
* A <code>X509Svid</code> represents a SPIFFE X.509 SVID.
* <p>
* Contains a SPIFFE ID, a private key and a chain of X.509 certificates.
*/
@Value
public class X509Svid {
public class X509Svid implements X509SvidSource {
SpiffeId spiffeId;
@ -51,17 +55,22 @@ public class X509Svid {
* @param certsFilePath path to X.509 certificate chain file
* @param privateKeyFilePath path to private key file
* @return an instance of {@link X509Svid}
*
* @throws X509SvidException if there is an error parsing the given certsFilePath or the privateKeyFilePath
*/
public static X509Svid load(@NonNull Path certsFilePath, @NonNull Path privateKeyFilePath) throws X509SvidException {
byte[] certsBytes;
byte[] privateKeyBytes;
try {
certsBytes = Files.readAllBytes(certsFilePath);
} catch (IOException e) {
throw new X509SvidException("Cannot read certificate file", e);
}
try {
privateKeyBytes = Files.readAllBytes(privateKeyFilePath);
} catch (IOException e) {
throw new X509SvidException(String.format("Could not load X509Svid from certsFilePath %s and privateKeyFilePath %s", certsFilePath, privateKeyFilePath), e);
throw new X509SvidException("Cannot read private key file", e);
}
return createX509Svid(certsBytes, privateKeyBytes);
}
@ -73,7 +82,6 @@ public class X509Svid {
* @param certsBytes chain of certificates as a byte array
* @param privateKeyBytes private key as byte array
* @return a {@link X509Svid} parsed from the given certBytes and privateKeyBytes
*
* @throws X509SvidException if the given certsBytes or privateKeyBytes cannot be parsed
*/
public static X509Svid parse(@NonNull byte[] certsBytes, @NonNull byte[] privateKeyBytes) throws X509SvidException {
@ -88,16 +96,80 @@ public class X509Svid {
}
private static X509Svid createX509Svid(byte[] certsBytes, byte[] privateKeyBytes) throws X509SvidException {
List<X509Certificate> x509Certificates = null;
List<X509Certificate> x509Certificates;
PrivateKey privateKey;
SpiffeId spiffeId;
try {
x509Certificates = CertificateUtils.generateCertificates(certsBytes);
val privateKey = CertificateUtils.generatePrivateKey(privateKeyBytes);
val spiffeId = CertificateUtils.getSpiffeId(x509Certificates.get(0));
return new X509Svid(spiffeId, x509Certificates, privateKey);
} catch (CertificateParsingException e) {
throw new X509SvidException("Certificate could not be parsed from cert bytes", e);
}
try {
privateKey = CertificateUtils.generatePrivateKey(privateKeyBytes);
} catch (InvalidKeySpecException | InvalidKeyException | NoSuchAlgorithmException e) {
throw new X509SvidException("Private Key could not be parsed from key bytes", e);
}
try {
spiffeId = CertificateUtils.getSpiffeId(x509Certificates.get(0));
} catch (CertificateException e) {
throw new X509SvidException("X509 SVID could not be parsed from cert bytes", e);
} catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
throw new X509SvidException("X509 SVID Private Key could not be parsed from privateKeyBytes", e);
throw new X509SvidException(e.getMessage(), e);
}
validatePrivateKey(privateKey, x509Certificates);
validateLeafCertificate(x509Certificates.get(0));
if (x509Certificates.size() > 1) {
validateSigningCertificates(x509Certificates.subList(1, x509Certificates.size()));
}
return new X509Svid(spiffeId, x509Certificates, privateKey);
}
private static void validateSigningCertificates(List<X509Certificate> certificates) throws X509SvidException {
for (X509Certificate cert : certificates) {
if (!isCA(cert)) {
throw new X509SvidException("Signing certificate must have CA flag set to true");
}
if (!hasKeyUsageCertSign(cert)) {
throw new X509SvidException("Signing certificate must have 'keyCertSign' as key usage");
}
}
}
private static void validateLeafCertificate(X509Certificate leaf) throws X509SvidException {
if (isCA(leaf)) {
throw new X509SvidException("Leaf certificate must not have CA flag set to true");
}
validateKeyUsage(leaf);
}
private static void validateKeyUsage(X509Certificate leaf) throws X509SvidException {
if (!hasKeyUsageDigitalSignature(leaf)) {
throw new X509SvidException("Leaf certificate must have 'digitalSignature' as key usage");
}
if (hasKeyUsageCertSign(leaf)) {
throw new X509SvidException("Leaf certificate must not have 'keyCertSign' as key usage");
}
if (hasKeyUsageCRLSign(leaf)) {
throw new X509SvidException("Leaf certificate must not have 'cRLSign' as key usage");
}
}
private static void validatePrivateKey(PrivateKey privateKey, List<X509Certificate> x509Certificates) throws X509SvidException {
try {
CertificateUtils.validatePrivateKey(privateKey, x509Certificates.get(0));
} catch (InvalidKeyException e) {
throw new X509SvidException("Private Key does not match Certificate Public Key", e);
} catch (NoSuchAlgorithmException | SignatureException e) {
throw new IllegalStateException("Could not validate private key", e);
}
}
@Override
public X509Svid getX509Svid() {
return this;
}
}

View File

@ -1,62 +1,252 @@
package spiffe.svid.x509svid;
import lombok.val;
import lombok.Builder;
import lombok.Value;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.platform.commons.util.StringUtils;
import spiffe.exception.X509SvidException;
import spiffe.spiffeid.SpiffeId;
import spiffe.spiffeid.TrustDomain;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.*;
public class X509SvidTest {
@Test
void parse_GivenCertAndPrivateKeyPEMsInByteArrays_ReturnsX509Svid() throws X509SvidException, IOException {
val certPem = Files.readAllBytes(Paths.get("../testdata/x509cert.pem"));
val keyPem = Files.readAllBytes(Paths.get("../testdata/pkcs8key.pem"));
val x509Svid = X509Svid.parse(certPem, keyPem);
assertAll("X509-SVID",
() -> assertEquals("spiffe://example.org/test", x509Svid.getSpiffeId().toString()),
() -> assertEquals(1, x509Svid.getChain().size()),
() -> assertNotNull(x509Svid.getPrivateKey())
);
}
static String keyRSA = "testdata/x509svid/key-pkcs8-rsa.pem";
static String certSingle = "testdata/x509svid/good-leaf-only.pem";
static String leafNoDigitalSignature = "testdata/x509svid/wrong-leaf-no-digital-signature.pem";
static String leafCRLSign = "testdata/x509svid/wrong-leaf-crl-sign.pem";
static String leafCertSign = "testdata/x509svid/wrong-leaf-cert-sign.pem";
static String leafCAtrue = "testdata/x509svid/wrong-leaf-ca-true.pem";
static String leafEmptyID = "testdata/x509svid/wrong-leaf-empty-id.pem";
static String signNoCA = "testdata/x509svid/wrong-intermediate-no-ca.pem";
static String signNoKeyCertSign = "testdata/x509svid/wrong-intermediate-no-key-cert-sign.pem";
static String keyECDSA = "testdata/x509svid/key-pkcs8-ecdsa.pem";
static String certMultiple = "testdata/x509svid/good-leaf-and-intermediate.pem";
static String corrupted = "testdata/x509svid/corrupted";
@Test
void parse_GivenChainOfCertsAndPrivateKeyPEMsInByteArrays_ReturnsX509Svid() throws IOException, X509SvidException {
val certPem = Files.readAllBytes(Paths.get("../testdata/x509chain.pem"));
val keyPem = Files.readAllBytes(Paths.get("../testdata/pkcs8key.pem"));
void testLoad_Success() throws URISyntaxException {
val result = X509Svid.parse(certPem, keyPem);
assertAll("X509-SVID",
() -> assertEquals("spiffe://example.org/test", result.getSpiffeId().toString()),
() -> assertEquals(4, result.getChain().size()),
() -> assertNotNull(result.getPrivateKey())
);
}
@Test
void load_GivenCertAndPrivateKeyPaths_ReturnsX509Svid() throws X509SvidException {
val certsFile = Paths.get("../testdata/x509cert.pem");
val privateKeyFile = Paths.get("../testdata/pkcs8key.pem");
X509Svid result;
Path certPath = Paths.get(loadResource(certSingle));
Path keyPath = Paths.get(loadResource(keyRSA));
try {
result = X509Svid.load(certsFile, privateKeyFile);
X509Svid x509Svid = X509Svid.load(certPath, keyPath);
assertEquals("spiffe://example.org/workload-1", x509Svid.getSpiffeId().toString());
} catch (X509SvidException e) {
fail("Not expected exception", e);
throw e;
fail(e);
}
}
assertAll("X509-SVID",
() -> assertEquals("spiffe://example.org/test", result.getSpiffeId().toString()),
() -> assertEquals(1, result.getChain().size()),
() -> assertNotNull(result.getPrivateKey())
@Test
void testLoad_FailsCannotReadCertFile() throws URISyntaxException {
Path keyPath = Paths.get(loadResource(keyRSA));
try {
X509Svid.load(Paths.get("not-existent-cert"), keyPath);
fail("should have thrown IOException");
} catch (X509SvidException e) {
assertEquals("Cannot read certificate file", e.getMessage());
}
}
@Test
void testLoad_FailsCannotReadKeyFile() throws URISyntaxException {
Path certPath = Paths.get(loadResource(certSingle));
try {
X509Svid.load(certPath, Paths.get("not-existent-key"));
fail("should have thrown IOException");
} catch (X509SvidException e) {
assertEquals("Cannot read private key file", e.getMessage());
}
}
@ParameterizedTest
@MethodSource("provideX509SvidScenarios")
void parseJwt(TestCase testCase) {
try {
Path certPath = Paths.get(loadResource(testCase.certsPath));
Path keyPath = Paths.get(loadResource(testCase.keyPath));
byte[] certBytes = Files.readAllBytes(certPath);
byte[] keyBytes = Files.readAllBytes(keyPath);
X509Svid x509Svid = X509Svid.parse(certBytes, keyBytes);
if (StringUtils.isNotBlank(testCase.expectedError)) {
fail(String.format("Error was expected: %s", testCase.expectedError));
}
assertNotNull(x509Svid);
assertNotNull(x509Svid.getSpiffeId());
assertNotNull(x509Svid.getChain());
assertNotNull(x509Svid.getPrivateKey());
assertEquals(testCase.expectedNumberOfCerts, x509Svid.getChain().size());
assertEquals(testCase.expectedSpiffeId, x509Svid.getSpiffeId());
assertEquals(testCase.expectedPrivateKeyAlgorithm, x509Svid.getPrivateKey().getAlgorithm());
} catch (Exception e) {
if (StringUtils.isBlank(testCase.expectedError)) {
fail(e);
}
assertEquals(testCase.expectedError, e.getMessage());
}
}
static Stream<Arguments> provideX509SvidScenarios() {
return Stream.of(
Arguments.of(TestCase
.builder()
.name("Single certificate and key")
.certsPath(certSingle)
.keyPath(keyRSA)
.expectedSpiffeId(SpiffeId.of(TrustDomain.of("example.org"), "workload-1"))
.expectedNumberOfCerts(1)
.expectedPrivateKeyAlgorithm("RSA")
.build()
),
Arguments.of(TestCase
.builder()
.name("Certificate with intermediate and key")
.certsPath(certMultiple)
.keyPath(keyECDSA)
.expectedSpiffeId(SpiffeId.of(TrustDomain.of("example.org"), "workload-1"))
.expectedNumberOfCerts(2)
.expectedPrivateKeyAlgorithm("EC")
.build()
),
Arguments.of(TestCase
.builder()
.name("Missing certificate")
.certsPath(keyRSA)
.keyPath(keyRSA)
.expectedError("Certificate could not be parsed from cert bytes")
.build()
),
Arguments.of(TestCase
.builder()
.name("Missing key")
.certsPath(certSingle)
.keyPath(certSingle)
.expectedError("Private Key could not be parsed from key bytes")
.build()
),
Arguments.of(TestCase
.builder()
.name("Corrupted private key")
.certsPath(certSingle)
.keyPath(corrupted)
.expectedError("Private Key could not be parsed from key bytes")
.build()
),
Arguments.of(TestCase
.builder()
.name("Corrupted certificate")
.certsPath(corrupted)
.keyPath(keyRSA)
.expectedError("Certificate could not be parsed from cert bytes")
.build()
),
Arguments.of(TestCase
.builder()
.name("Certificate does not match private key")
.certsPath(certMultiple)
.keyPath(keyRSA)
.expectedError("Private Key does not match Certificate Public Key")
.build()
),
Arguments.of(TestCase
.builder()
.name("Certificate without SPIFFE ID")
.certsPath(leafEmptyID)
.keyPath(keyRSA)
.expectedError("Certificate does not contain SPIFFE ID in the URI SAN")
.build()
),
Arguments.of(TestCase
.builder()
.name("Leaf certificate with CA flag set to true")
.certsPath(leafCAtrue)
.keyPath(keyRSA)
.expectedError("Leaf certificate must not have CA flag set to true")
.build()
),
Arguments.of(TestCase
.builder()
.name("Leaf certificate without digitalSignature as key usage")
.certsPath(leafNoDigitalSignature)
.keyPath(keyRSA)
.expectedError("Leaf certificate must have 'digitalSignature' as key usage")
.build()
),
Arguments.of(TestCase
.builder()
.name("Leaf certificate with certSign as key usage")
.certsPath(leafCertSign)
.keyPath(keyRSA)
.expectedError("Leaf certificate must not have 'keyCertSign' as key usage")
.build()
),
Arguments.of(TestCase
.builder()
.name("Leaf certificate with cRLSign as key usage")
.certsPath(leafCRLSign)
.keyPath(keyRSA)
.expectedError("Leaf certificate must not have 'cRLSign' as key usage")
.build()
),
Arguments.of(TestCase
.builder()
.name("Signing certificate without CA flag")
.certsPath(signNoCA)
.keyPath(keyRSA)
.expectedError("Signing certificate must have CA flag set to true")
.build()
),
Arguments.of(TestCase
.builder()
.name("Signing certificate without CA flag")
.certsPath(signNoKeyCertSign)
.keyPath(keyRSA)
.expectedError("Signing certificate must have 'keyCertSign' as key usage")
.build()
)
);
}
@Value
static class TestCase {
String name;
String certsPath;
String keyPath;
SpiffeId expectedSpiffeId;
int expectedNumberOfCerts;
String expectedPrivateKeyAlgorithm;
String expectedError;
@Builder
public TestCase(String name, String certsPath, String keyPath, SpiffeId expectedSpiffeId, int expectedNumberOfCerts, String expectedPrivateKeyAlgorithm, String expectedError) {
this.name = name;
this.certsPath = certsPath;
this.keyPath = keyPath;
this.expectedSpiffeId = expectedSpiffeId;
this.expectedNumberOfCerts = expectedNumberOfCerts;
this.expectedPrivateKeyAlgorithm = expectedPrivateKeyAlgorithm;
this.expectedError = expectedError;
}
}
private URI loadResource(String path) throws URISyntaxException {
return getClass().getClassLoader().getResource(path).toURI();
}
}

View File

@ -0,0 +1 @@
not-pem not-der

View File

@ -0,0 +1,26 @@
-----BEGIN CERTIFICATE-----
MIICBzCCAY2gAwIBAgIRAJ4TY883AKQzW4gEzxTP5ekwCgYIKoZIzj0EAwMwHjEL
MAkGA1UEBhMCVVMxDzANBgNVBAoTBlNQSUZGRTAeFw0yMDAzMjQxNDA3MzBaFw0y
MDAzMjQxNTA3NDBaMB0xCzAJBgNVBAYTAlVTMQ4wDAYDVQQKEwVTUElSRTBZMBMG
ByqGSM49AgEGCCqGSM49AwEHA0IABI6NiQ4HU4ZS8koPLevFZOzNPJRBGmsr6CMj
qww2LVQDxF2/QiJUtVf6yPhtXYI/uWh8yBvRNxLfMmscAYf1gBOjgawwgakwDgYD
VR0PAQH/BAQDAgOoMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNV
HRMBAf8EAjAAMB0GA1UdDgQWBBSyUx1gdahNKPD13hnr5SJq7QdHqzAfBgNVHSME
GDAWgBR1/vyENH1J5W0G0zexqR4Q2UVIGjAqBgNVHREEIzAhhh9zcGlmZmU6Ly9l
eGFtcGxlLm9yZy93b3JrbG9hZC0xMAoGCCqGSM49BAMDA2gAMGUCMQDsFcGtMDZi
w2aypdxvr1tvN/Opahi4zJ3DIlfAIhSNQ8gDp7LS7u06Ob/6ouh/1c4CMEpVoyS4
ZTnENACY3TXXmRt/mZsXyyHSgQGyEFqmvehpsDLIAL2+nKLfcyzENZn4Rg==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB/DCCAYOgAwIBAgIQBRQ/CSzrgkGFpQ7mVSr7yjAKBggqhkjOPQQDAzAeMQsw
CQYDVQQGEwJVUzEPMA0GA1UECgwGU1BJRkZFMB4XDTIwMDMyNDE0MDUwM1oXDTIw
MDMyNTE0MDUxM1owHjELMAkGA1UEBhMCVVMxDzANBgNVBAoTBlNQSUZGRTB2MBAG
ByqGSM49AgEGBSuBBAAiA2IABExZXvtfcorJWkVs8pdriln6Y5aewz+r0ibFXdKt
lHOg31MQsnZkh3wlOxuVwwyuuTlpb8LwIyOhuYbb6lbWHDDhSHXh3ye021PifZGc
X8pHXRQk6D8SP1+260sOmCTI1qOBhTCBgjAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0T
AQH/BAUwAwEB/zAdBgNVHQ4EFgQUdf78hDR9SeVtBtM3sakeENlFSBowHwYDVR0j
BBgwFoAUh6XzV6LwNazA+GTEVOdu07o5yOgwHwYDVR0RBBgwFoYUc3BpZmZlOi8v
ZXhhbXBsZS5vcmcwCgYIKoZIzj0EAwMDZwAwZAIwApQtPxHc1mx+aOES1D0RFttH
IyVP9szoPz1wjSFXnxA8zY8ikVGx6FdviaHe4RXaAjBA3tN4AJf/yBzJU7cStXR8
Y8l67Q87PUKX5SyAdGgoqVX2V+i/kH1ZFt0BikmRWtA=
-----END CERTIFICATE-----

View File

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDKjCCAhKgAwIBAgIJAPKy5MTuxkq7MA0GCSqGSIb3DQEBDQUAMB4xCzAJBgNV
BAYTAlVTMQ8wDQYDVQQKDAZTUElGRkUwHhcNMjAwMzMwMTkwMDM3WhcNMjUwMzI5
MTkwMDM3WjAeMQswCQYDVQQGEwJVUzEPMA0GA1UECgwGU1BJRkZFMIIBIjANBgkq
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvudksUDCwrAb5Ag5zbRaMv0OWcehfN/1
ejrDJUu0gmnYGOrs0xdMPCIacHkOEm0nSJ2b35REBbw13FTCHHaFH9tC0EZrz+Fk
mhoP2HTcGRsiibfBvRpyd346sP6JqocpTNljhQxbhKCy4WkAS/KKjrD8NdkQ8zdM
h8vBzEkzDwjbjbn3rWgvHcBOU3Zu2mn5/LP4B8oXlGM4n7ZMWK35s+yXKzmwkltp
QtVVTmtkCmTLfckBsSgBESnRgIjY/jfwJqrugvPdmx0ToINljiahz0Uci3hRLhYc
3zAsQJoFXaNrm6qFCtOR/xHK/RCKY9bHKEvavVx+F2Wvx3MphddztQIDAQABo2sw
aTAdBgNVHQ4EFgQUy4VolgQJBL0rLYyI/JQHlBB0whEwDAYDVR0TAQH/BAIwADAO
BgNVHQ8BAf8EBAMCB4AwKgYDVR0RBCMwIYYfc3BpZmZlOi8vZXhhbXBsZS5vcmcv
d29ya2xvYWQtMTANBgkqhkiG9w0BAQ0FAAOCAQEAsgNGb0lDyvPYsOMtNCZxpEQh
WDM4nPc/fWmRQv2GE24VPDxTa+KF8QASuK4SK3aHgixIAUiugOpFr5ZuyX7nWhcb
5lPXOfuAB7SL5rq9E4kaikhNiJOCDxMORNZmpe9fii+l4clrmqIaryDHOhCGZFvr
ppPOxLFPY1pnFBUtEjrM8TnpVMdV6jB4im7lKfOse/1BhzRQQ/dJg4EFk1S9pHse
ryc0wJMM685dgAmELRigWx2IpU7Ma/09WlcCG7AmToeXPcEOa0xFS3CNEat8+bv+
BaWSJ31+se8tDTjjEfV3M23OdUmyv29aTb74wd33u6+jsliFK5psZKbcg3hGCA==
-----END CERTIFICATE-----

View File

@ -0,0 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgmgpKax+BCcPM3gcZ
1zvl2zquf76KwRhQWfQJQTKhGfKhRANCAASOjYkOB1OGUvJKDy3rxWTszTyUQRpr
K+gjI6sMNi1UA8Rdv0IiVLVX+sj4bV2CP7lofMgb0TcS3zJrHAGH9YAT
-----END PRIVATE KEY-----

View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC+52SxQMLCsBvk
CDnNtFoy/Q5Zx6F83/V6OsMlS7SCadgY6uzTF0w8IhpweQ4SbSdInZvflEQFvDXc
VMIcdoUf20LQRmvP4WSaGg/YdNwZGyKJt8G9GnJ3fjqw/omqhylM2WOFDFuEoLLh
aQBL8oqOsPw12RDzN0yHy8HMSTMPCNuNufetaC8dwE5Tdm7aafn8s/gHyheUYzif
tkxYrfmz7JcrObCSW2lC1VVOa2QKZMt9yQGxKAERKdGAiNj+N/Amqu6C892bHROg
g2WOJqHPRRyLeFEuFhzfMCxAmgVdo2ubqoUK05H/Ecr9EIpj1scoS9q9XH4XZa/H
cymF13O1AgMBAAECggEAKb363G8mpt9PGetaiEoZNvDyRFtMSjvGNzXGGc+V5rYy
FDC6G+YKO1PRqCowE4NehZhAzwBiZ0aiGE1ILGUV8sNEtrnPNSM5liCAunnC7pJq
WOafLDQuN0aYmr7tZyYqt60I/7yV/kgNFRCaigC8nzq/yx5tgGDlEQRSmdKfoXeS
2mmHtpB06bMDU+cptfsG1S/eChVAngJcKAYdIukud5GGgsYp3TiXxM/IZ2wapclT
T4ATAERvysT58sYR4sCGpphFzsAkjd6oFZoADSw58bKrq8Afb/txjHdXwhV+crPu
BDbozuk5F2r9U/cGtpTI3Ay1T+VHOHkKuUJCYz97gQKBgQD72Hr+DxpBkn4cgPGx
jBe7/Uixs5+cQL44lqIEOd6uLLE+xrPOZgpuOqz7FPVcAnBgh+knf1Kz5SgQwrTU
22SlYPsS2+D3Rcnp5UMfqfwFq1/X9UGF62l3VHwgs40iP4k28H9Y4GYeXRNIigyu
CDImn1FU6cJx1w1aUnYrIoEDMQKBgQDCDY/T/mm8DmLeV6wxAzSJYfKhgrvZ/Jc0
qGQdp9yGpZDqV1zRtoJE7jno1YRt01ye0xXLZYsgYbG04kWNSTDy9yfLPBDN28m/
yiYNz6ckYI2HNts8BSIGjF3cuF4XGaEkaMRlnx5iAb9BZ6692itWGJ4skGuUdKXh
cFNt1hovxQKBgQDz6QW1aQsU1rws/vUV74hNGVF+SWkb+9g/FiRz01hHeCFxmyAp
lcokV8+QnQvEwNf1pau6BSYj9JyJHwnj3Vfsk7CW4z1OPtj/HnuT/x2GoCODFJUR
Dp5mY/yT71GRCdfqzaGIgkxku+AhMRJ2uplXrpUml/8qIg1cnOC1hgVNAQKBgDQs
21AfpqRGpfSsVAL1nqmVqVwdv45z6N/iqtCCcrvNRnKLvMwyK0KHXxCoYCv7WXrm
vIRssASr39EHybWcSUn6hDuT0dzXzJ4Bp0utWn5ga41AhZ/UrXpfQVl4ROwnGvmk
JbJBHzUwzRCz5Prs7xv+EIFg71wCJRvBTN1KZM4VAoGBAK7ud6KNqLtesyFQxmlA
ccHLqIFDVZy30nghXEHGIhUwEXstA6wb0R563svaBVFd+q5SAtfRKPoWNz+yxnUn
r9DvXKB/A2jFzmZ5HKQoc6YD5U+jIwWX9HBw/UK1pNIemIbnhkJCbqaC09nZ03nM
7OCe8CKM5vdVTa2hHowYf3ci
-----END PRIVATE KEY-----

View File

@ -0,0 +1,38 @@
-----BEGIN CERTIFICATE-----
MIIDKjCCAhKgAwIBAgIJAPKy5MTuxkq7MA0GCSqGSIb3DQEBDQUAMB4xCzAJBgNV
BAYTAlVTMQ8wDQYDVQQKDAZTUElGRkUwHhcNMjAwMzMwMTkwMDM3WhcNMjUwMzI5
MTkwMDM3WjAeMQswCQYDVQQGEwJVUzEPMA0GA1UECgwGU1BJRkZFMIIBIjANBgkq
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvudksUDCwrAb5Ag5zbRaMv0OWcehfN/1
ejrDJUu0gmnYGOrs0xdMPCIacHkOEm0nSJ2b35REBbw13FTCHHaFH9tC0EZrz+Fk
mhoP2HTcGRsiibfBvRpyd346sP6JqocpTNljhQxbhKCy4WkAS/KKjrD8NdkQ8zdM
h8vBzEkzDwjbjbn3rWgvHcBOU3Zu2mn5/LP4B8oXlGM4n7ZMWK35s+yXKzmwkltp
QtVVTmtkCmTLfckBsSgBESnRgIjY/jfwJqrugvPdmx0ToINljiahz0Uci3hRLhYc
3zAsQJoFXaNrm6qFCtOR/xHK/RCKY9bHKEvavVx+F2Wvx3MphddztQIDAQABo2sw
aTAdBgNVHQ4EFgQUy4VolgQJBL0rLYyI/JQHlBB0whEwDAYDVR0TAQH/BAIwADAO
BgNVHQ8BAf8EBAMCB4AwKgYDVR0RBCMwIYYfc3BpZmZlOi8vZXhhbXBsZS5vcmcv
d29ya2xvYWQtMTANBgkqhkiG9w0BAQ0FAAOCAQEAsgNGb0lDyvPYsOMtNCZxpEQh
WDM4nPc/fWmRQv2GE24VPDxTa+KF8QASuK4SK3aHgixIAUiugOpFr5ZuyX7nWhcb
5lPXOfuAB7SL5rq9E4kaikhNiJOCDxMORNZmpe9fii+l4clrmqIaryDHOhCGZFvr
ppPOxLFPY1pnFBUtEjrM8TnpVMdV6jB4im7lKfOse/1BhzRQQ/dJg4EFk1S9pHse
ryc0wJMM685dgAmELRigWx2IpU7Ma/09WlcCG7AmToeXPcEOa0xFS3CNEat8+bv+
BaWSJ31+se8tDTjjEfV3M23OdUmyv29aTb74wd33u6+jsliFK5psZKbcg3hGCA==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDHzCCAgegAwIBAgIJAKs91lAuGzzQMA0GCSqGSIb3DQEBDQUAMB4xCzAJBgNV
BAYTAlVTMQ8wDQYDVQQKDAZTUElGRkUwHhcNMjAwMzMxMTUxMjU3WhcNMjUwMzMw
MTUxMjU3WjAeMQswCQYDVQQGEwJVUzEPMA0GA1UECgwGU1BJRkZFMIIBIjANBgkq
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvudksUDCwrAb5Ag5zbRaMv0OWcehfN/1
ejrDJUu0gmnYGOrs0xdMPCIacHkOEm0nSJ2b35REBbw13FTCHHaFH9tC0EZrz+Fk
mhoP2HTcGRsiibfBvRpyd346sP6JqocpTNljhQxbhKCy4WkAS/KKjrD8NdkQ8zdM
h8vBzEkzDwjbjbn3rWgvHcBOU3Zu2mn5/LP4B8oXlGM4n7ZMWK35s+yXKzmwkltp
QtVVTmtkCmTLfckBsSgBESnRgIjY/jfwJqrugvPdmx0ToINljiahz0Uci3hRLhYc
3zAsQJoFXaNrm6qFCtOR/xHK/RCKY9bHKEvavVx+F2Wvx3MphddztQIDAQABo2Aw
XjAdBgNVHQ4EFgQUy4VolgQJBL0rLYyI/JQHlBB0whEwDAYDVR0TAQH/BAIwADAO
BgNVHQ8BAf8EBAMCAQYwHwYDVR0RBBgwFoYUc3BpZmZlOi8vZXhhbXBsZS5vcmcw
DQYJKoZIhvcNAQENBQADggEBAHO2gZiRBlhbCsBSbpaAujVauM4IHhEtoZP1b+cu
22bAm21PTC3T4XAfDj286PrdOYL91FNmbpvR2hL+MrMKH+SBFQCnvNE8FYnMkNRx
ysJItGTHdB2yXlBZbpZeRoOCL5oiS5vpQebHU6+AD6hsyM+9rSu4z6gwM2xFLQYQ
Dc2IIV8LoB6s/9BB5rLcjVkjdhOR7spsAgFdK6ZYU0K8FoEPvBeEY7CORzenAbhI
8ExVH/3aNB2dfhIu4gFVGVnBh+UQ43YPR6Qs/ON5CS91xpUI0U0tJZgqMfD6kn3A
2U9PgiZyKoKrt+AyLe9OTg1Kb6QoxEFOeCljNp5+J+YPVjU=
-----END CERTIFICATE-----

View File

@ -0,0 +1,38 @@
-----BEGIN CERTIFICATE-----
MIIDKjCCAhKgAwIBAgIJAPKy5MTuxkq7MA0GCSqGSIb3DQEBDQUAMB4xCzAJBgNV
BAYTAlVTMQ8wDQYDVQQKDAZTUElGRkUwHhcNMjAwMzMwMTkwMDM3WhcNMjUwMzI5
MTkwMDM3WjAeMQswCQYDVQQGEwJVUzEPMA0GA1UECgwGU1BJRkZFMIIBIjANBgkq
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvudksUDCwrAb5Ag5zbRaMv0OWcehfN/1
ejrDJUu0gmnYGOrs0xdMPCIacHkOEm0nSJ2b35REBbw13FTCHHaFH9tC0EZrz+Fk
mhoP2HTcGRsiibfBvRpyd346sP6JqocpTNljhQxbhKCy4WkAS/KKjrD8NdkQ8zdM
h8vBzEkzDwjbjbn3rWgvHcBOU3Zu2mn5/LP4B8oXlGM4n7ZMWK35s+yXKzmwkltp
QtVVTmtkCmTLfckBsSgBESnRgIjY/jfwJqrugvPdmx0ToINljiahz0Uci3hRLhYc
3zAsQJoFXaNrm6qFCtOR/xHK/RCKY9bHKEvavVx+F2Wvx3MphddztQIDAQABo2sw
aTAdBgNVHQ4EFgQUy4VolgQJBL0rLYyI/JQHlBB0whEwDAYDVR0TAQH/BAIwADAO
BgNVHQ8BAf8EBAMCB4AwKgYDVR0RBCMwIYYfc3BpZmZlOi8vZXhhbXBsZS5vcmcv
d29ya2xvYWQtMTANBgkqhkiG9w0BAQ0FAAOCAQEAsgNGb0lDyvPYsOMtNCZxpEQh
WDM4nPc/fWmRQv2GE24VPDxTa+KF8QASuK4SK3aHgixIAUiugOpFr5ZuyX7nWhcb
5lPXOfuAB7SL5rq9E4kaikhNiJOCDxMORNZmpe9fii+l4clrmqIaryDHOhCGZFvr
ppPOxLFPY1pnFBUtEjrM8TnpVMdV6jB4im7lKfOse/1BhzRQQ/dJg4EFk1S9pHse
ryc0wJMM685dgAmELRigWx2IpU7Ma/09WlcCG7AmToeXPcEOa0xFS3CNEat8+bv+
BaWSJ31+se8tDTjjEfV3M23OdUmyv29aTb74wd33u6+jsliFK5psZKbcg3hGCA==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDIjCCAgqgAwIBAgIJAIzsgdc6VayiMA0GCSqGSIb3DQEBDQUAMB4xCzAJBgNV
BAYTAlVTMQ8wDQYDVQQKDAZTUElGRkUwHhcNMjAwMzMxMTUxNjU0WhcNMjUwMzMw
MTUxNjU0WjAeMQswCQYDVQQGEwJVUzEPMA0GA1UECgwGU1BJRkZFMIIBIjANBgkq
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvudksUDCwrAb5Ag5zbRaMv0OWcehfN/1
ejrDJUu0gmnYGOrs0xdMPCIacHkOEm0nSJ2b35REBbw13FTCHHaFH9tC0EZrz+Fk
mhoP2HTcGRsiibfBvRpyd346sP6JqocpTNljhQxbhKCy4WkAS/KKjrD8NdkQ8zdM
h8vBzEkzDwjbjbn3rWgvHcBOU3Zu2mn5/LP4B8oXlGM4n7ZMWK35s+yXKzmwkltp
QtVVTmtkCmTLfckBsSgBESnRgIjY/jfwJqrugvPdmx0ToINljiahz0Uci3hRLhYc
3zAsQJoFXaNrm6qFCtOR/xHK/RCKY9bHKEvavVx+F2Wvx3MphddztQIDAQABo2Mw
YTAdBgNVHQ4EFgQUy4VolgQJBL0rLYyI/JQHlBB0whEwDwYDVR0TAQH/BAUwAwEB
/zAOBgNVHQ8BAf8EBAMCAQIwHwYDVR0RBBgwFoYUc3BpZmZlOi8vZXhhbXBsZS5v
cmcwDQYJKoZIhvcNAQENBQADggEBAHzixgdMjrXVEtBfLNTdLrdiBLjlNRcmLbgq
6yBZInw4UieIhj5wnkYlFiZAt3l+v4BxHHBVpW0FFEgXJSUBcyHSiqIY4myiNpGW
GsU7rsy3XdmM37y8vc69lhGpaKjDqyN5NWBaPS1N6ZXZAfrCgbzzA20lo9Kebo0/
rItx6r+Q7TQbIdPUwWv5vIms25JODwtmiXxZ3GTOdc79pb396HO0azm4mEPSeadk
dYrgeviEsManUlhlGfKREONAMkY1DG5cRoyWLFKSvgFtGu24qLsg2CSReM4nFhcf
T8+sSz+RFBwJkb1pfra4IGdIrJtWAQY9TYnVzeV3xroqtQDbeS4=
-----END CERTIFICATE-----

View File

@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDLTCCAhWgAwIBAgIJAIATiUHEG6XPMA0GCSqGSIb3DQEBDQUAMB4xCzAJBgNV
BAYTAlVTMQ8wDQYDVQQKDAZTUElGRkUwHhcNMjAwMzMwMTg1MDAzWhcNMjUwMzI5
MTg1MDAzWjAeMQswCQYDVQQGEwJVUzEPMA0GA1UECgwGU1BJRkZFMIIBIjANBgkq
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvudksUDCwrAb5Ag5zbRaMv0OWcehfN/1
ejrDJUu0gmnYGOrs0xdMPCIacHkOEm0nSJ2b35REBbw13FTCHHaFH9tC0EZrz+Fk
mhoP2HTcGRsiibfBvRpyd346sP6JqocpTNljhQxbhKCy4WkAS/KKjrD8NdkQ8zdM
h8vBzEkzDwjbjbn3rWgvHcBOU3Zu2mn5/LP4B8oXlGM4n7ZMWK35s+yXKzmwkltp
QtVVTmtkCmTLfckBsSgBESnRgIjY/jfwJqrugvPdmx0ToINljiahz0Uci3hRLhYc
3zAsQJoFXaNrm6qFCtOR/xHK/RCKY9bHKEvavVx+F2Wvx3MphddztQIDAQABo24w
bDAdBgNVHQ4EFgQUy4VolgQJBL0rLYyI/JQHlBB0whEwDwYDVR0TAQH/BAUwAwEB
/zAOBgNVHQ8BAf8EBAMCB4AwKgYDVR0RBCMwIYYfc3BpZmZlOi8vZXhhbXBsZS5v
cmcvd29ya2xvYWQtMTANBgkqhkiG9w0BAQ0FAAOCAQEAPWpG81EVmPVbb99qEVnc
yxPVy524isxJkx2OAOUXcBmYlZEKa6qEnZh02Qs+8nuBIH6cSwrFqLupycwbW9wo
32fe2Y+UuVEG7b9+vjFofzeVePx0dX5gk9WTb0b+OesmnF/m9uJFZ8ZDw/DFKO1y
0gcqJKPl3HHAz5s83mnBwiugy/G22iorO7iJBkChQrAxdpN2hvsEo88kn1wmopLq
kFSeMVc3vrLI9/FL2WnNOYUKbM1J/xrMQFPgs2y9Md/ZZfBQMTQSn1MyRFhLNfq7
vFH1bKDl8R1F6c8n/cU1ZTS84kWpCg5bkpJTKLESbgUj4I6ULxREeNIvNddyU6Qf
AA==
-----END CERTIFICATE-----

View File

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDKjCCAhKgAwIBAgIJAP/AfgtzAqe1MA0GCSqGSIb3DQEBDQUAMB4xCzAJBgNV
BAYTAlVTMQ8wDQYDVQQKDAZTUElGRkUwHhcNMjAwMzMwMTk1ODQxWhcNMjUwMzI5
MTk1ODQxWjAeMQswCQYDVQQGEwJVUzEPMA0GA1UECgwGU1BJRkZFMIIBIjANBgkq
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvudksUDCwrAb5Ag5zbRaMv0OWcehfN/1
ejrDJUu0gmnYGOrs0xdMPCIacHkOEm0nSJ2b35REBbw13FTCHHaFH9tC0EZrz+Fk
mhoP2HTcGRsiibfBvRpyd346sP6JqocpTNljhQxbhKCy4WkAS/KKjrD8NdkQ8zdM
h8vBzEkzDwjbjbn3rWgvHcBOU3Zu2mn5/LP4B8oXlGM4n7ZMWK35s+yXKzmwkltp
QtVVTmtkCmTLfckBsSgBESnRgIjY/jfwJqrugvPdmx0ToINljiahz0Uci3hRLhYc
3zAsQJoFXaNrm6qFCtOR/xHK/RCKY9bHKEvavVx+F2Wvx3MphddztQIDAQABo2sw
aTAdBgNVHQ4EFgQUy4VolgQJBL0rLYyI/JQHlBB0whEwDAYDVR0TAQH/BAIwADAO
BgNVHQ8BAf8EBAMCAoQwKgYDVR0RBCMwIYYfc3BpZmZlOi8vZXhhbXBsZS5vcmcv
d29ya2xvYWQtMTANBgkqhkiG9w0BAQ0FAAOCAQEAsBgFKbbIo4hJMcgcRqLstLUU
rzuyePs9Q7jIMr0dnriy++c+3DfNLQj3jnnhTaTMWoFyLL1tab6xanhxE0+/TkU6
h4Z8hIsFcvZ0GJQ4MFxYpo4i7rly2OfbGXVKCc9Ho5hOcOhiwCpcbRxljVfdlK1x
U03VBhgGN4yTxBZv7f9RhqiUo9KTWW1LaTwV0e/B+plMiXWZsDiILndM/1YVvnFU
FIvABFDquhkIzN65WMBpUm1U8sjrgGdpAQxJw//dyb59A/HtfAM8tkLiZ4Teuh43
gt88H1PK/f8ksL5rHZcCcvzoq6Dfzfu6QjWNAJg7d6nv3kOd2G+dAGEau3SmPQ==
-----END CERTIFICATE-----

View File

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDKjCCAhKgAwIBAgIJAMhI+pO57LUFMA0GCSqGSIb3DQEBDQUAMB4xCzAJBgNV
BAYTAlVTMQ8wDQYDVQQKDAZTUElGRkUwHhcNMjAwMzMwMjAwNDEzWhcNMjUwMzI5
MjAwNDEzWjAeMQswCQYDVQQGEwJVUzEPMA0GA1UECgwGU1BJRkZFMIIBIjANBgkq
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvudksUDCwrAb5Ag5zbRaMv0OWcehfN/1
ejrDJUu0gmnYGOrs0xdMPCIacHkOEm0nSJ2b35REBbw13FTCHHaFH9tC0EZrz+Fk
mhoP2HTcGRsiibfBvRpyd346sP6JqocpTNljhQxbhKCy4WkAS/KKjrD8NdkQ8zdM
h8vBzEkzDwjbjbn3rWgvHcBOU3Zu2mn5/LP4B8oXlGM4n7ZMWK35s+yXKzmwkltp
QtVVTmtkCmTLfckBsSgBESnRgIjY/jfwJqrugvPdmx0ToINljiahz0Uci3hRLhYc
3zAsQJoFXaNrm6qFCtOR/xHK/RCKY9bHKEvavVx+F2Wvx3MphddztQIDAQABo2sw
aTAdBgNVHQ4EFgQUy4VolgQJBL0rLYyI/JQHlBB0whEwDAYDVR0TAQH/BAIwADAO
BgNVHQ8BAf8EBAMCAYIwKgYDVR0RBCMwIYYfc3BpZmZlOi8vZXhhbXBsZS5vcmcv
d29ya2xvYWQtMTANBgkqhkiG9w0BAQ0FAAOCAQEAS/j2y8U79cAY6WxVvd3TgPSy
Uh56MbuS9pVKnRMLtwlRK8HoiMeqVYFXDu0xjz+7inVq6xtsr3SV8vy4uYLEr+SA
qqQbw3rEWxph6oahFNkc9LOw9c3RHA8cH6izWYtQFsG2TxtMR3fvCQx7x/hxeTD0
xfJEd4LPHfoiVFAtFn1CmglShNp0DA9Y+83s7QfBMfwCc7ih0d79903gpY9o5IVU
SNk6Dd7trgkkoEN7P8pq5Rqx4M8XKv4Q1w9lAbL1wQJceM3ANtPhxANXazOhYLfS
jH1L7u4I/Kp61hRcdqux/2lNGimka1b0W6TmAiGEu1m2AvIE2sy2P9+L3UfeSA==
-----END CERTIFICATE-----

View File

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDFjCCAf6gAwIBAgIJAOMjYtQS4O0MMA0GCSqGSIb3DQEBDQUAMB4xCzAJBgNV
BAYTAlVTMQ8wDQYDVQQKDAZTUElGRkUwHhcNMjAwMzMxMTI0NjI2WhcNMjUwMzMw
MTI0NjI2WjAeMQswCQYDVQQGEwJVUzEPMA0GA1UECgwGU1BJRkZFMIIBIjANBgkq
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvudksUDCwrAb5Ag5zbRaMv0OWcehfN/1
ejrDJUu0gmnYGOrs0xdMPCIacHkOEm0nSJ2b35REBbw13FTCHHaFH9tC0EZrz+Fk
mhoP2HTcGRsiibfBvRpyd346sP6JqocpTNljhQxbhKCy4WkAS/KKjrD8NdkQ8zdM
h8vBzEkzDwjbjbn3rWgvHcBOU3Zu2mn5/LP4B8oXlGM4n7ZMWK35s+yXKzmwkltp
QtVVTmtkCmTLfckBsSgBESnRgIjY/jfwJqrugvPdmx0ToINljiahz0Uci3hRLhYc
3zAsQJoFXaNrm6qFCtOR/xHK/RCKY9bHKEvavVx+F2Wvx3MphddztQIDAQABo1cw
VTAdBgNVHQ4EFgQUy4VolgQJBL0rLYyI/JQHlBB0whEwDAYDVR0TAQH/BAIwADAO
BgNVHQ8BAf8EBAMCB4AwFgYDVR0RBA8wDYILZXhhbXBsZS5vcmcwDQYJKoZIhvcN
AQENBQADggEBADJgmurhe2YuHULCYsmDPNQO1hJ79tzVwSZmHo9vLejv3zx7w25z
983CiqbeMRWHh+9gfXsdcwJnn4AQU2VfdYboXchBcA8tK4w8Bpev6DvOketrZ/KR
l7LrTv2VV4+eigdXl5dSAQ/4mnLoICvksrKZllxCZWXyay3ctwIa75HCc4xYKGXT
WuDNF7jSb21gB4K38pugwQhkH1eMdYvu2zAsBN0ClU7VEEsu1NEXO91+74CHCfDO
e/+MPfqspoYrPrDsvkVGjYKxG3IxwsV3XdqB0ofvjoEv8ZqpPmrrfVYc11WBXFIY
musYpNAVVBBkn1ILoeJarftnZCZU6VG18mo=
-----END CERTIFICATE-----

View File

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDKjCCAhKgAwIBAgIJAK/ds1rcEPTnMA0GCSqGSIb3DQEBDQUAMB4xCzAJBgNV
BAYTAlVTMQ8wDQYDVQQKDAZTUElGRkUwHhcNMjAwMzMwMTk1MzU1WhcNMjUwMzI5
MTk1MzU1WjAeMQswCQYDVQQGEwJVUzEPMA0GA1UECgwGU1BJRkZFMIIBIjANBgkq
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvudksUDCwrAb5Ag5zbRaMv0OWcehfN/1
ejrDJUu0gmnYGOrs0xdMPCIacHkOEm0nSJ2b35REBbw13FTCHHaFH9tC0EZrz+Fk
mhoP2HTcGRsiibfBvRpyd346sP6JqocpTNljhQxbhKCy4WkAS/KKjrD8NdkQ8zdM
h8vBzEkzDwjbjbn3rWgvHcBOU3Zu2mn5/LP4B8oXlGM4n7ZMWK35s+yXKzmwkltp
QtVVTmtkCmTLfckBsSgBESnRgIjY/jfwJqrugvPdmx0ToINljiahz0Uci3hRLhYc
3zAsQJoFXaNrm6qFCtOR/xHK/RCKY9bHKEvavVx+F2Wvx3MphddztQIDAQABo2sw
aTAdBgNVHQ4EFgQUy4VolgQJBL0rLYyI/JQHlBB0whEwDAYDVR0TAQH/BAIwADAO
BgNVHQ8BAf8EBAMCAQYwKgYDVR0RBCMwIYYfc3BpZmZlOi8vZXhhbXBsZS5vcmcv
d29ya2xvYWQtMTANBgkqhkiG9w0BAQ0FAAOCAQEAlYTex0bigAfH4BPtLiGXUsDB
Tw8p1ztElGHxBHyHs+WAC2Tm2Mlnpxa5e7457WQnta93IuzoU6Ws+TkPFy7IhA8z
kjT4LYJGnDGOZ5te6epMpv+1Dul1aVwLTpm3oXmTBRtw2fGubexhj6UVFr9/dqae
OihD5OmOTpMzs40SGCibqsKWEUIFtRjtN91kzzbwgAGLbHWrgBmNEimGZ8ASTWs7
PdtnPGqdfKBGT1oHSlnDj3yCeNf9j5isirp2vtaYxVBz1P2wMrUdCKScOc23m2Sm
tS2EsyMmLP3GncYiSjDXT4rtNr/NKG3n6g/Km5ZhPWDXtwOz0ur6lovKQyz+wg==
-----END CERTIFICATE-----