Skip to content

Commit 280d8e5

Browse files
Only check validity of certs in the chain of the node certificates (#4979)
Signed-off-by: Craig Perkins <[email protected]> Co-authored-by: Darshit Chanpura <[email protected]>
1 parent 37d259c commit 280d8e5

File tree

10 files changed

+220
-26
lines changed

10 files changed

+220
-26
lines changed

src/main/java/org/opensearch/security/ssl/SslConfiguration.java

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@
1717
import java.security.PrivilegedExceptionAction;
1818
import java.util.List;
1919
import java.util.Objects;
20+
import java.util.Set;
2021
import java.util.stream.Collectors;
2122
import java.util.stream.Stream;
2223
import java.util.stream.StreamSupport;
2324
import javax.net.ssl.KeyManagerFactory;
2425
import javax.net.ssl.TrustManagerFactory;
26+
import javax.security.auth.x500.X500Principal;
2527

2628
import org.apache.logging.log4j.LogManager;
2729
import org.apache.logging.log4j.Logger;
@@ -74,7 +76,10 @@ public KeyManagerFactory keyStoreFactory() {
7476
}
7577

7678
public TrustManagerFactory trustStoreFactory() {
77-
return trustStoreConfiguration.createTrustManagerFactory(sslParameters.shouldValidateNewCertDNs());
79+
return trustStoreConfiguration.createTrustManagerFactory(
80+
sslParameters.shouldValidateNewCertDNs(),
81+
keyStoreConfiguration.getIssuerDns()
82+
);
7883
}
7984

8085
public SslParameters sslParameters() {
@@ -84,10 +89,10 @@ public SslParameters sslParameters() {
8489
@SuppressWarnings("removal")
8590
SslContext buildServerSslContext(final boolean validateCertificates) {
8691
try {
87-
return AccessController.doPrivileged(
88-
(PrivilegedExceptionAction<SslContext>) () -> SslContextBuilder.forServer(
89-
keyStoreConfiguration.createKeyManagerFactory(validateCertificates)
90-
)
92+
return AccessController.doPrivileged((PrivilegedExceptionAction<SslContext>) () -> {
93+
KeyManagerFactory kmFactory = keyStoreConfiguration.createKeyManagerFactory(validateCertificates);
94+
Set<X500Principal> issuerDns = keyStoreConfiguration.getIssuerDns();
95+
return SslContextBuilder.forServer(kmFactory)
9196
.sslProvider(sslParameters.provider())
9297
.clientAuth(sslParameters.clientAuth())
9398
.protocols(sslParameters.allowedProtocols().toArray(new String[0]))
@@ -112,9 +117,9 @@ SslContext buildServerSslContext(final boolean validateCertificates) {
112117
ApplicationProtocolNames.HTTP_1_1
113118
)
114119
)
115-
.trustManager(trustStoreConfiguration.createTrustManagerFactory(validateCertificates))
116-
.build()
117-
);
120+
.trustManager(trustStoreConfiguration.createTrustManagerFactory(validateCertificates, issuerDns))
121+
.build();
122+
});
118123
} catch (PrivilegedActionException e) {
119124
throw new OpenSearchException("Failed to build server SSL context", e);
120125
}
@@ -123,19 +128,21 @@ SslContext buildServerSslContext(final boolean validateCertificates) {
123128
@SuppressWarnings("removal")
124129
SslContext buildClientSslContext(final boolean validateCertificates) {
125130
try {
126-
return AccessController.doPrivileged(
127-
(PrivilegedExceptionAction<SslContext>) () -> SslContextBuilder.forClient()
131+
return AccessController.doPrivileged((PrivilegedExceptionAction<SslContext>) () -> {
132+
KeyManagerFactory kmFactory = keyStoreConfiguration.createKeyManagerFactory(validateCertificates);
133+
Set<X500Principal> issuerDns = keyStoreConfiguration.getIssuerDns();
134+
return SslContextBuilder.forClient()
128135
.sslProvider(sslParameters.provider())
129136
.protocols(sslParameters.allowedProtocols())
130137
.ciphers(sslParameters.allowedCiphers())
131138
.applicationProtocolConfig(ApplicationProtocolConfig.DISABLED)
132139
.sessionCacheSize(0)
133140
.sessionTimeout(0)
134141
.sslProvider(sslParameters.provider())
135-
.keyManager(keyStoreConfiguration.createKeyManagerFactory(validateCertificates))
136-
.trustManager(trustStoreConfiguration.createTrustManagerFactory(validateCertificates))
137-
.build()
138-
);
142+
.keyManager(kmFactory)
143+
.trustManager(trustStoreConfiguration.createTrustManagerFactory(validateCertificates, issuerDns))
144+
.build();
145+
});
139146
} catch (PrivilegedActionException e) {
140147
throw new OpenSearchException("Failed to build client SSL context", e);
141148
}

src/main/java/org/opensearch/security/ssl/config/KeyStoreConfiguration.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,12 @@
1818
import java.security.cert.X509Certificate;
1919
import java.util.Arrays;
2020
import java.util.Collections;
21+
import java.util.HashSet;
2122
import java.util.List;
2223
import java.util.Objects;
24+
import java.util.Set;
2325
import javax.net.ssl.KeyManagerFactory;
26+
import javax.security.auth.x500.X500Principal;
2427

2528
import com.google.common.collect.ImmutableList;
2629

@@ -41,6 +44,15 @@ default KeyManagerFactory createKeyManagerFactory(boolean validateCertificates)
4144
return buildKeyManagerFactory(keyStore.v1(), keyStore.v2());
4245
}
4346

47+
default Set<X500Principal> getIssuerDns() {
48+
Set<X500Principal> issuerDns = new HashSet<>();
49+
final List<Certificate> certificates = loadCertificates();
50+
for (Certificate certificate : certificates) {
51+
issuerDns.add(certificate.x509Certificate().getIssuerX500Principal());
52+
}
53+
return issuerDns;
54+
}
55+
4456
default KeyManagerFactory buildKeyManagerFactory(final KeyStore keyStore, final char[] password) {
4557
try {
4658
final var keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());

src/main/java/org/opensearch/security/ssl/config/KeyStoreUtils.java

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,16 @@
2424
import java.security.cert.CertificateException;
2525
import java.security.cert.X509Certificate;
2626
import java.security.spec.InvalidKeySpecException;
27+
import java.util.Arrays;
2728
import java.util.List;
29+
import java.util.Set;
2830
import javax.crypto.NoSuchPaddingException;
2931
import javax.net.ssl.SSLEngine;
3032
import javax.net.ssl.SSLSessionContext;
33+
import javax.security.auth.x500.X500Principal;
34+
35+
import org.apache.logging.log4j.LogManager;
36+
import org.apache.logging.log4j.Logger;
3137

3238
import org.opensearch.OpenSearchException;
3339

@@ -37,6 +43,8 @@
3743

3844
final class KeyStoreUtils {
3945

46+
private final static Logger log = LogManager.getLogger(KeyStoreUtils.class);
47+
4048
private final static class SecuritySslContext extends SslContext {
4149

4250
private SecuritySslContext() {}
@@ -141,15 +149,10 @@ public static void validateKeyStoreCertificates(final KeyStore keyStore) {
141149
final var a = aliases.nextElement();
142150
if (keyStore.isCertificateEntry(a)) {
143151
final var c = (X509Certificate) keyStore.getCertificate(a);
144-
if (c == null) {
145-
throw new CertificateException("Alias " + a + " does not contain a certificate entry");
146-
}
147152
c.checkValidity();
148-
} else if (keyStore.isKeyEntry(a)) {
149-
final var cc = keyStore.getCertificateChain(a);
150-
if (cc == null) {
151-
throw new CertificateException("Alias " + a + " does not contain a certificate chain");
152-
}
153+
}
154+
final var cc = keyStore.getCertificateChain(a);
155+
if (cc != null) {
153156
for (final var c : cc) {
154157
((X509Certificate) c).checkValidity();
155158
}
@@ -162,6 +165,44 @@ public static void validateKeyStoreCertificates(final KeyStore keyStore) {
162165
}
163166
}
164167

168+
// If dnsToCheck is present, this method will only validate the certificates that match the dns in this list or
169+
// up the chain
170+
public static void validateKeyStoreCertificates(final KeyStore keyStore, Set<X500Principal> dnsToCheck) {
171+
try {
172+
final var aliases = keyStore.aliases();
173+
while (aliases.hasMoreElements()) {
174+
final var a = aliases.nextElement();
175+
if (keyStore.isCertificateEntry(a)) {
176+
final var c = (X509Certificate) keyStore.getCertificate(a);
177+
if (dnsToCheck.contains(c.getSubjectX500Principal())) {
178+
c.checkValidity();
179+
final var cc = keyStore.getCertificateChain(a);
180+
if (cc != null) {
181+
for (final var c1 : cc) {
182+
((X509Certificate) c1).checkValidity();
183+
}
184+
}
185+
} else {
186+
log.info("Skipping validation for " + c.getSubjectX500Principal().getName());
187+
}
188+
} else {
189+
final var cc = keyStore.getCertificateChain(a);
190+
if (cc != null) {
191+
if (Arrays.stream(cc).anyMatch(c -> dnsToCheck.contains(((X509Certificate) c).getSubjectX500Principal()))) {
192+
for (final var c : cc) {
193+
((X509Certificate) c).checkValidity();
194+
}
195+
}
196+
}
197+
}
198+
}
199+
} catch (KeyStoreException e) {
200+
throw new OpenSearchException("Couldn't load keys store", e);
201+
} catch (CertificateException e) {
202+
throw new OpenSearchException("Invalid certificates", e);
203+
}
204+
}
205+
165206
public static KeyStore loadKeyStore(final Path path, final String type, final char[] password) {
166207
try {
167208
final var keyStore = KeyStore.getInstance(type);

src/main/java/org/opensearch/security/ssl/config/TrustStoreConfiguration.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@
1919
import java.util.Collections;
2020
import java.util.List;
2121
import java.util.Objects;
22+
import java.util.Set;
2223
import java.util.stream.Collectors;
2324
import java.util.stream.Stream;
2425
import javax.net.ssl.TrustManagerFactory;
26+
import javax.security.auth.x500.X500Principal;
2527

2628
import com.google.common.collect.ImmutableList;
2729

@@ -46,7 +48,7 @@ public KeyStore createTrustStore() {
4648
}
4749

4850
@Override
49-
public TrustManagerFactory createTrustManagerFactory(boolean validateCertificates) {
51+
public TrustManagerFactory createTrustManagerFactory(boolean validateCertificates, Set<X500Principal> issuerDns) {
5052
return null;
5153
}
5254
};
@@ -55,10 +57,10 @@ public TrustManagerFactory createTrustManagerFactory(boolean validateCertificate
5557

5658
List<Certificate> loadCertificates();
5759

58-
default TrustManagerFactory createTrustManagerFactory(boolean validateCertificates) {
60+
default TrustManagerFactory createTrustManagerFactory(boolean validateCertificates, Set<X500Principal> issuerDns) {
5961
final var trustStore = createTrustStore();
6062
if (validateCertificates) {
61-
KeyStoreUtils.validateKeyStoreCertificates(trustStore);
63+
KeyStoreUtils.validateKeyStoreCertificates(trustStore, issuerDns);
6264
}
6365
return buildTrustManagerFactory(trustStore);
6466
}

src/test/java/org/opensearch/security/ssl/SSLTest.java

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,81 @@ public void testHttps() throws Exception {
122122

123123
}
124124

125+
@Test
126+
public void testHttpsWithTrustStoreContainingValidCertsNotInChain() throws Exception {
127+
128+
final Settings settings = Settings.builder()
129+
.put(ConfigConstants.SECURITY_SSL_ONLY, true)
130+
.put(SSLConfigConstants.SECURITY_SSL_HTTP_ENABLED, true)
131+
.put(
132+
SSLConfigConstants.SECURITY_SSL_HTTP_KEYSTORE_FILEPATH,
133+
FileHelper.getAbsoluteFilePathFromClassPath("ssl/node-0-keystore.jks")
134+
)
135+
.put(
136+
SSLConfigConstants.SECURITY_SSL_HTTP_TRUSTSTORE_FILEPATH,
137+
FileHelper.getAbsoluteFilePathFromClassPath("ssl/truststore_valid.jks")
138+
)
139+
.build();
140+
141+
setupSslOnlyMode(settings);
142+
143+
RestHelper rh = restHelper();
144+
rh.enableHTTPClientSSL = true;
145+
rh.trustHTTPServerCertificate = true;
146+
rh.sendAdminCertificate = true;
147+
rh.keystore = "node-untspec5-keystore.p12";
148+
149+
String res = rh.executeSimpleRequest("_opendistro/_security/sslinfo?pretty&show_dn=true");
150+
Assert.assertTrue(res.contains("[email protected]"));
151+
Assert.assertTrue(res.contains("local_certificates_list"));
152+
Assert.assertFalse(
153+
rh.executeSimpleRequest("_opendistro/_security/sslinfo?pretty&show_dn=false").contains("local_certificates_list")
154+
);
155+
Assert.assertFalse(rh.executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("local_certificates_list"));
156+
res = rh.executeSimpleRequest("_nodes/settings?pretty");
157+
Assert.assertTrue(res.contains(clusterInfo.clustername));
158+
Assert.assertFalse(res.contains("\"opendistro_security\""));
159+
Assert.assertFalse(res.contains("keystore_filepath"));
160+
}
161+
162+
@Test
163+
public void testHttpsWithTrustStoreContainingInvalidCertsNotInChain() throws Exception {
164+
165+
final Settings settings = Settings.builder()
166+
.put(ConfigConstants.SECURITY_SSL_ONLY, true)
167+
.put(SSLConfigConstants.SECURITY_SSL_HTTP_ENABLED, true)
168+
.put(
169+
SSLConfigConstants.SECURITY_SSL_HTTP_KEYSTORE_FILEPATH,
170+
FileHelper.getAbsoluteFilePathFromClassPath("ssl/node-0-keystore.jks")
171+
)
172+
.put(
173+
SSLConfigConstants.SECURITY_SSL_HTTP_TRUSTSTORE_FILEPATH,
174+
FileHelper.getAbsoluteFilePathFromClassPath("ssl/truststore_invalid.jks")
175+
)
176+
.build();
177+
178+
setupSslOnlyMode(settings);
179+
180+
RestHelper rh = restHelper();
181+
rh.enableHTTPClientSSL = true;
182+
rh.trustHTTPServerCertificate = true;
183+
rh.sendAdminCertificate = true;
184+
rh.keystore = "node-untspec5-keystore.p12";
185+
186+
String res = rh.executeSimpleRequest("_opendistro/_security/sslinfo?pretty&show_dn=true");
187+
Assert.assertTrue(res.contains("[email protected]"));
188+
Assert.assertTrue(res.contains("local_certificates_list"));
189+
Assert.assertFalse(
190+
rh.executeSimpleRequest("_opendistro/_security/sslinfo?pretty&show_dn=false").contains("local_certificates_list")
191+
);
192+
Assert.assertFalse(rh.executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("local_certificates_list"));
193+
194+
res = rh.executeSimpleRequest("_nodes/settings?pretty");
195+
Assert.assertTrue(res.contains(clusterInfo.clustername));
196+
Assert.assertFalse(res.contains("\"opendistro_security\""));
197+
Assert.assertFalse(res.contains("keystore_filepath"));
198+
}
199+
125200
@Test
126201
public void testCipherAndProtocols() throws Exception {
127202

src/test/java/org/opensearch/security/ssl/config/SslCertificatesLoaderTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
import java.nio.file.Path;
1515
import java.util.List;
16+
import java.util.Set;
1617

1718
import com.carrotsearch.randomizedtesting.RandomizedTest;
1819
import org.junit.ClassRule;
@@ -49,7 +50,7 @@ void assertTrustStoreConfiguration(
4950
assertThat("Truststore configuration created", nonNull(trustStoreConfiguration));
5051
assertThat(trustStoreConfiguration.file(), is(expectedFile));
5152
assertThat(trustStoreConfiguration.loadCertificates(), containsInAnyOrder(expectedCertificates));
52-
assertThat(trustStoreConfiguration.createTrustManagerFactory(true), is(notNullValue()));
53+
assertThat(trustStoreConfiguration.createTrustManagerFactory(true, Set.of()), is(notNullValue()));
5354
}
5455

5556
void assertKeyStoreConfiguration(
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIE2DCCA8CgAwIBAgIUI6tTo8QuZUoMod2uJWb587o/WSQwDQYJKoZIhvcNAQEL
3+
BQAwgZUxEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJkiaJk/IsZAEZFgdleGFt
4+
cGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSQwIgYDVQQLDBtFeGFtcGxl
5+
IENvbSBJbmMuIEludmFsaWQgQ0ExJDAiBgNVBAMMG0V4YW1wbGUgQ29tIEluYy4g
6+
SW52YWxpZCBDQTAeFw0yNTA0MDgxOTAwMzNaFw0yNTA0MDkxOTAwMzNaMIGVMRMw
7+
EQYKCZImiZPyLGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTEZMBcG
8+
A1UECgwQRXhhbXBsZSBDb20gSW5jLjEkMCIGA1UECwwbRXhhbXBsZSBDb20gSW5j
9+
LiBJbnZhbGlkIENBMSQwIgYDVQQDDBtFeGFtcGxlIENvbSBJbmMuIEludmFsaWQg
10+
Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCmFZGps52e1aA0bmAo
11+
Gy8cIT5ZbqZlBK9jEAXj8m4snFPpS87MtEN5vDA3OLsB44tt3mRLKc/GkvG4v4yl
12+
MDILNSarVWME53fGzoyc0i0gd/VZxPwxR0e+LphnmCbec44GzfN3dOxCdqZ3AnZA
13+
9JCsogf36omgb6hYXsi6FsPkB0YxnUHviiYVtxPcV/Q11cGLq55kwm5INSnGuUxX
14+
NEz0RRj9Hm+4PEGnGBRyWOuAAxQYeexXGHpXDy2II8X7uyCb1gbd3zI+hlM9hgeA
15+
bMUaR4P42INB6SJkk/nzHg+g3ssZ+N3ZFN9QxDCG+v+LA6p6oRNL1J6iICkN6vfi
16+
ZuVdAgMBAAGjggEcMIIBGDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB
17+
hjAdBgNVHQ4EFgQUA+uQ1+AW5h2XztdP2wbwhix8XWgwgdUGA1UdIwSBzTCByoAU
18+
A+uQ1+AW5h2XztdP2wbwhix8XWihgZukgZgwgZUxEzARBgoJkiaJk/IsZAEZFgNj
19+
b20xFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMRkwFwYDVQQKDBBFeGFtcGxlIENv
20+
bSBJbmMuMSQwIgYDVQQLDBtFeGFtcGxlIENvbSBJbmMuIEludmFsaWQgQ0ExJDAi
21+
BgNVBAMMG0V4YW1wbGUgQ29tIEluYy4gSW52YWxpZCBDQYIUI6tTo8QuZUoMod2u
22+
JWb587o/WSQwDQYJKoZIhvcNAQELBQADggEBAIxYxDaCwhovQmvSkK/E8BqwSuG5
23+
yKbfo5BHYlhNbhmBzOvXkoF9jka2TqKRZceWCq4MTztKLQrjpm3jnKAGxNnhTXqL
24+
/edEE3RJ13EuzJyk13Chem8asgoZlXwjJwSFqWJS30P75HTuVwFwMFNLLtbCGvKb
25+
oobDQMM6lHtlnvagUrAQG9sT0wPO43sfRzEabWs2CvMnbMZpJ7mn7zDmiIU1z+ub
26+
rXCG2eSDILaFB0FACkRRdpm0SStF2ftPua3HSKKGh99TjGECxmpcQoO0kKp+fsdA
27+
SdyR6KGYHKFRftw0eMZ6RsOwF1BhGq8nT3UlEJTpaBJSAkzzgbMeUFkLRGk=
28+
-----END CERTIFICATE-----
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIEzDCCA7SgAwIBAgIUBVbjdAIYKfChQdrfXZpAIyNs2mswDQYJKoZIhvcNAQEL
3+
BQAwgZExEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJkiaJk/IsZAEZFgdleGFt
4+
cGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSIwIAYDVQQLDBlFeGFtcGxl
5+
IENvbSBJbmMuIE90aGVyIENBMSIwIAYDVQQDDBlFeGFtcGxlIENvbSBJbmMuIE90
6+
aGVyIENBMB4XDTI1MDQwODE4NTQwM1oXDTM1MDQwNjE4NTQwM1owgZExEzARBgoJ
7+
kiaJk/IsZAEZFgNjb20xFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMRkwFwYDVQQK
8+
DBBFeGFtcGxlIENvbSBJbmMuMSIwIAYDVQQLDBlFeGFtcGxlIENvbSBJbmMuIE90
9+
aGVyIENBMSIwIAYDVQQDDBlFeGFtcGxlIENvbSBJbmMuIE90aGVyIENBMIIBIjAN
10+
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtX0FZtu9rARzLJ3Ql8ugU64yALps
11+
mhD9j5CnvuNLAmeTqEsTXS/9mqH43OCTFyF1fqXrSXlk0W/JAWMhXZZswsPkYZoj
12+
zUoZNT+e8OXlqMPik00EKhdnH2CdSSDBBgLfpcOfMDYoLLRWiz7RnajHKRsRSnKl
13+
5YDrbQqMOOtOX7ImzRNwFJ8DNh1OUzY/Id3cjosH57clxRyJ3U+q88+UDejeT8JT
14+
7hOtzAqufgIqvungpZt+BtqeIeZonxoUyDifp1i/mC+2sLxx3//cmP7wLCzMM3Eq
15+
tBp8F3DsgfvsMAD/yYPTCIdX75/aWbSywrRwxA27UZaASrEkQx+6uaQa4wIDAQAB
16+
o4IBGDCCARQwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0O
17+
BBYEFO8uD2PZZw/PpBp1JxW9KlO1cXAHMIHRBgNVHSMEgckwgcaAFO8uD2PZZw/P
18+
pBp1JxW9KlO1cXAHoYGXpIGUMIGRMRMwEQYKCZImiZPyLGQBGRYDY29tMRcwFQYK
19+
CZImiZPyLGQBGRYHZXhhbXBsZTEZMBcGA1UECgwQRXhhbXBsZSBDb20gSW5jLjEi
20+
MCAGA1UECwwZRXhhbXBsZSBDb20gSW5jLiBPdGhlciBDQTEiMCAGA1UEAwwZRXhh
21+
bXBsZSBDb20gSW5jLiBPdGhlciBDQYIUBVbjdAIYKfChQdrfXZpAIyNs2mswDQYJ
22+
KoZIhvcNAQELBQADggEBAHNxdIYNhLV5EdRGTV//yzfemsgCHU1DUnHKMn4TtSYe
23+
nYFL8rmX1tkOpzRI6/mrzE4IBsaEidAjbwYMWrn3rDHCkoHc6XTqr8WCW7y1KruJ
24+
5MVlNLdPDDQuuP+loWzDao9qdzPqQwp9ue44o9prikvyAUmWZBEbNLxarrgjiPUn
25+
VLli1agzG3kXIS0oWL+ZcwIzS+rQ6Ma5jTuCR7ljxEtobVrSioxfJQ9bZNKwAdd6
26+
fv7XqZ0T2Fz4x+gRs22M9Uu1dzkX4waRfA/JfIOVYR91Lz0Iw6HIn9V8bHZliI6E
27+
wgxliW2yzFUt1FZDO7PCZPGuxF0g7WK6fva3AqokK+Y=
28+
-----END CERTIFICATE-----
2.32 KB
Binary file not shown.
2.31 KB
Binary file not shown.

0 commit comments

Comments
 (0)