From 4d299094b62475c711ada71d0e54de80d8c49a2d Mon Sep 17 00:00:00 2001 From: Axel Hanikel Date: Thu, 24 Jun 2021 17:41:12 +0200 Subject: [PATCH] OAK-9473 - Cold Standby: configure decryption password for SSL key in OSGi --- .../segment/standby/client/StandbyClient.java | 18 ++-- .../standby/client/StandbyClientSync.java | 22 ++-- .../segment/standby/server/StandbyServer.java | 20 ++-- .../standby/server/StandbyServerSync.java | 36 ++++--- .../standby/store/StandbyStoreService.java | 33 +++--- .../oak/segment/standby/StandbyTestIT.java | 101 +++++++++++++++++- .../oak/segment/standby/TestBase.java | 95 ++++++++++++++++ 7 files changed, 277 insertions(+), 48 deletions(-) diff --git a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/client/StandbyClient.java b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/client/StandbyClient.java index 2105df0d02..3e92a738e1 100644 --- a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/client/StandbyClient.java +++ b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/client/StandbyClient.java @@ -73,8 +73,9 @@ class StandbyClient implements AutoCloseable { private int readTimeoutMs; private File spoolFolder; private String sslKeyFile; + private String sslKeyPassword; private String sslChainFile; - public String sslServerSubjectPattern; + public String sslSubjectPattern; private Builder() {} @@ -118,13 +119,18 @@ class StandbyClient implements AutoCloseable { return this; } + public Builder withSSLKeyPassword(String sslKeyPassword) { + this.sslKeyPassword = sslKeyPassword; + return this; + } + public Builder withSSLChainFile(String sslChainFile) { this.sslChainFile = sslChainFile; return this; } - public Builder withSSLServerSubjectPattern(String sslServerSubjectPattern) { - this.sslServerSubjectPattern = sslServerSubjectPattern; + public Builder withSSLSubjectPattern(String sslServerSubjectPattern) { + this.sslSubjectPattern = sslServerSubjectPattern; return this; } @@ -169,14 +175,14 @@ class StandbyClient implements AutoCloseable { if (builder.secure) { SslContext sslContext; if (builder.sslKeyFile != null && !"".equals(builder.sslKeyFile)) { - sslContext = SslContextBuilder.forClient().keyManager(new File(builder.sslChainFile), new File(builder.sslKeyFile)).build(); + sslContext = SslContextBuilder.forClient().keyManager(new File(builder.sslChainFile), new File(builder.sslKeyFile), builder.sslKeyPassword).build(); } else { sslContext = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build(); } p.addLast("ssl", sslContext.newHandler(ch.alloc())); - if (builder.sslServerSubjectPattern != null) { - p.addLast(new SSLSubjectMatcher(builder.sslServerSubjectPattern)); + if (builder.sslSubjectPattern != null) { + p.addLast(new SSLSubjectMatcher(builder.sslSubjectPattern)); } } diff --git a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/client/StandbyClientSync.java b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/client/StandbyClientSync.java index 6af99db075..ebca61dc96 100644 --- a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/client/StandbyClientSync.java +++ b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/client/StandbyClientSync.java @@ -59,8 +59,9 @@ public final class StandbyClientSync implements ClientStandbyStatusMBean, Runnab private boolean autoClean; private File spoolFolder; private String sslKeyFile; + private String sslKeyPassword; private String sslChainFile; - private String sslServerSubjectPattern; + private String sslSubjectPattern; private Builder() {} @@ -104,13 +105,18 @@ public final class StandbyClientSync implements ClientStandbyStatusMBean, Runnab return this; } + public Builder withSSLKeyPassword(String sslKeyPassword) { + this.sslKeyPassword = sslKeyPassword; + return this; + } + public Builder withSSLChainFile(String sslChainFile) { this.sslChainFile = sslChainFile; return this; } - public Builder withSSLServerSubjectPattern(String sslServerSubjectPattern) { - this.sslServerSubjectPattern = sslServerSubjectPattern; + public Builder withSSLSubjectPattern(String sslSubjectPattern) { + this.sslSubjectPattern = sslSubjectPattern; return this; } @@ -149,9 +155,11 @@ public final class StandbyClientSync implements ClientStandbyStatusMBean, Runnab private final String sslKeyFile; + private final String sslKeyPassword; + private final String sslChainFile; - private final String sslServerSubjectPattern; + private final String sslSubjectPattern; private int failedRequests; @@ -192,8 +200,9 @@ public final class StandbyClientSync implements ClientStandbyStatusMBean, Runnab this.execution = new StandbyClientSyncExecution(fileStore, () -> running); this.spoolFolder = builder.spoolFolder; this.sslKeyFile = builder.sslKeyFile; + this.sslKeyPassword = builder.sslKeyPassword; this.sslChainFile = builder.sslChainFile; - this.sslServerSubjectPattern = builder.sslServerSubjectPattern; + this.sslSubjectPattern = builder.sslSubjectPattern; try { ManagementFactory.getPlatformMBeanServer().registerMBean(new StandardMBean(this, ClientStandbyStatusMBean.class), new ObjectName(this.getMBeanName())); } catch (Exception e) { @@ -253,8 +262,9 @@ public final class StandbyClientSync implements ClientStandbyStatusMBean, Runnab .withReadTimeoutMs(readTimeoutMs) .withSpoolFolder(spoolFolder) .withSSLKeyFile(sslKeyFile) + .withSSLKeyPassword(sslKeyPassword) .withSSLChainFile(sslChainFile) - .withSSLServerSubjectPattern(sslServerSubjectPattern).build()) { + .withSSLSubjectPattern(sslSubjectPattern).build()) { execution.execute(client); } diff --git a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/server/StandbyServer.java b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/server/StandbyServer.java index b1e2d66d11..29adcba866 100644 --- a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/server/StandbyServer.java +++ b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/server/StandbyServer.java @@ -109,11 +109,13 @@ class StandbyServer implements AutoCloseable { private String sslKeyFile; + private String sslKeyPassword; + private String sslChainFile; private boolean sslClientValidation; - public String sslClientSubjectPattern; + private String sslSubjectPattern; private Builder(final int port, final StoreProvider storeProvider, final int blobChunkSize) { this.port = port; @@ -166,6 +168,11 @@ class StandbyServer implements AutoCloseable { return this; } + Builder withSSLKeyPassword(String sslKeyPassword) { + this.sslKeyPassword = sslKeyPassword; + return this; + } + Builder withSSLChainFile(String sslChainFile) { this.sslChainFile = sslChainFile; return this; @@ -176,8 +183,8 @@ class StandbyServer implements AutoCloseable { return this; } - Builder withSSLClientSubjectPattern(String sslClientSubjectPattern) { - this.sslClientSubjectPattern = sslClientSubjectPattern; + Builder withSSLSubjectPattern(String sslSubjectPattern) { + this.sslSubjectPattern = sslSubjectPattern; return this; } @@ -204,7 +211,6 @@ class StandbyServer implements AutoCloseable { return new StandbyServer(this); } - } private StandbyServer(final Builder builder) throws CertificateException, SSLException { @@ -212,7 +218,7 @@ class StandbyServer implements AutoCloseable { if (builder.secure) { if (builder.sslKeyFile != null && !"".equals(builder.sslKeyFile)) { - sslContext = SslContextBuilder.forServer(new File(builder.sslChainFile), new File(builder.sslKeyFile)).build(); + sslContext = SslContextBuilder.forServer(new File(builder.sslChainFile), new File(builder.sslKeyFile), builder.sslKeyPassword).build(); } else { SelfSignedCertificate ssc = new SelfSignedCertificate(); sslContext = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build(); @@ -244,8 +250,8 @@ class StandbyServer implements AutoCloseable { handler.engine().setNeedClientAuth(builder.sslClientValidation); p.addLast("ssl", handler); - if (builder.sslClientSubjectPattern != null) { - p.addLast(new SSLSubjectMatcher(builder.sslClientSubjectPattern)); + if (builder.sslSubjectPattern != null) { + p.addLast(new SSLSubjectMatcher(builder.sslSubjectPattern)); } } diff --git a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/server/StandbyServerSync.java b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/server/StandbyServerSync.java index d54797340e..5917d5ecf1 100644 --- a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/server/StandbyServerSync.java +++ b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/server/StandbyServerSync.java @@ -69,7 +69,9 @@ public class StandbyServerSync implements StandbyStatusMBean, StateConsumer, Sto private boolean sslValidateClient; - public String sslClientSubjectPattern; + private String sslKeyPassword; + + private String sslSubjectPattern; private Builder() { // Prevent external instantiation @@ -132,6 +134,11 @@ public class StandbyServerSync implements StandbyStatusMBean, StateConsumer, Sto return this; } + public Builder withSSLKeyPassword(String sslKeyPassword) { + this.sslKeyPassword = sslKeyPassword; + return this; + } + public Builder withSSLChainFile(String sslChainFile) { this.sslChainFile = sslChainFile; return this; @@ -142,8 +149,8 @@ public class StandbyServerSync implements StandbyStatusMBean, StateConsumer, Sto return this; } - public Builder withSSLClientSubjectPattern(String sslClientSubjectPattern) { - this.sslClientSubjectPattern = sslClientSubjectPattern; + public Builder withSSLSubjectPattern(String sslSubjectPattern) { + this.sslSubjectPattern = sslSubjectPattern; return this; } @@ -153,7 +160,6 @@ public class StandbyServerSync implements StandbyStatusMBean, StateConsumer, Sto checkArgument(blobChunkSize > 0); return new StandbyServerSync(this); } - } private static final Logger log = LoggerFactory.getLogger(StandbyServer.class); @@ -184,13 +190,15 @@ public class StandbyServerSync implements StandbyStatusMBean, StateConsumer, Sto private StandbyServer server; - private final String sslCertificate; + private final String sslKeyFile; + + private final String sslKeyPassword; - private final String sslChain; + private final String sslChainFile; private final boolean sslValidateClient; - private final String sslClientSubjectPattern; + private final String sslSubjectPattern; private StandbyServerSync(Builder builder) { this.port = builder.port; @@ -202,10 +210,11 @@ public class StandbyServerSync implements StandbyStatusMBean, StateConsumer, Sto this.standbyHeadReader = builder.standbyHeadReader; this.standbyReferencesReader = builder.standbyReferencesReader; this.standbySegmentReader = builder.standbySegmentReader; - this.sslCertificate = builder.sslKeyFile; - this.sslChain = builder.sslChainFile; + this.sslKeyFile = builder.sslKeyFile; + this.sslKeyPassword = builder.sslKeyPassword; + this.sslChainFile = builder.sslChainFile; this.sslValidateClient = builder.sslValidateClient; - this.sslClientSubjectPattern = builder.sslClientSubjectPattern; + this.sslSubjectPattern = builder.sslSubjectPattern; this.observer = new CommunicationObserver("primary"); final MBeanServer jmxServer = ManagementFactory.getPlatformMBeanServer(); @@ -245,10 +254,11 @@ public class StandbyServerSync implements StandbyStatusMBean, StateConsumer, Sto .withStandbyHeadReader(standbyHeadReader) .withStandbyReferencesReader(standbyReferencesReader) .withStandbySegmentReader(standbySegmentReader) - .withSSLKeyFile(sslCertificate) - .withSSLChainFile(sslChain) + .withSSLKeyFile(sslKeyFile) + .withSSLKeyPassword(sslKeyPassword) + .withSSLChainFile(sslChainFile) .withSSLClientValidation(sslValidateClient) - .withSSLClientSubjectPattern(sslClientSubjectPattern); + .withSSLSubjectPattern(sslSubjectPattern); server = builder.build(); server.start(); diff --git a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/store/StandbyStoreService.java b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/store/StandbyStoreService.java index deeb6a1874..8efbb9ef8a 100644 --- a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/store/StandbyStoreService.java +++ b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/store/StandbyStoreService.java @@ -39,6 +39,7 @@ import org.osgi.service.component.annotations.ConfigurationPolicy; import org.osgi.service.component.annotations.Deactivate; import org.osgi.service.component.annotations.Reference; import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.AttributeType; import org.osgi.service.metatype.annotations.Designate; import org.osgi.service.metatype.annotations.ObjectClassDefinition; import org.osgi.service.metatype.annotations.Option; @@ -123,6 +124,12 @@ public class StandbyStoreService { ) String sslKeyFile(); + @AttributeDefinition( + name = "SSL Key Password", + description = "Password for the SSL key. If this is empty, an unencrypted key is expected.", + type = AttributeType.PASSWORD) + String sslKeyPassword() default ""; + @AttributeDefinition( name = "SSL Certificate Chain File", description = "The file name which contains the SSL certificate chain." @@ -136,16 +143,10 @@ public class StandbyStoreService { boolean sslValidateClient() default false; @AttributeDefinition( - name = "SSL Server Certificate Subject Pattern", - description = "The server certificate subject must match this pattern in order to be accepted by the client." - ) - String sslServerSubjectPattern(); - - @AttributeDefinition( - name = "SSL Client Certificate Subject Pattern", - description = "The client certificate subject must match this pattern in order to be accepted by the server." + name = "SSL Certificate Subject Pattern", + description = "The peer certificate's subject must match this pattern in order to be accepted." ) - String sslClientSubjectPattern(); + String sslSubjectPattern(); } @Reference(policy = STATIC, policyOption = GREEDY) @@ -190,7 +191,7 @@ public class StandbyStoreService { String sslKeyFile = config.sslKeyFile(); String sslChainFile = config.sslChainFile(); boolean sslValidateClient = config.sslValidateClient(); - String sslClientSubjectPattern = config.sslClientSubjectPattern(); + String sslSubjectPattern = config.sslSubjectPattern(); StandbyServerSync.Builder builder = StandbyServerSync.builder() .withPort(port) @@ -201,7 +202,11 @@ public class StandbyStoreService { .withSSLKeyFile(sslKeyFile) .withSSLChainFile(sslChainFile) .withSSLClientValidation(sslValidateClient) - .withSSLClientSubjectPattern(sslClientSubjectPattern); + .withSSLSubjectPattern(sslSubjectPattern); + + if (!"".equals(config.sslKeyPassword())) { + builder.withSSLKeyPassword(config.sslKeyPassword()); + } StandbyServerSync standbyServerSync = builder.build(); @@ -224,7 +229,11 @@ public class StandbyStoreService { .withSecureConnection(config.secure()) .withSSLKeyFile(config.sslKeyFile()) .withSSLChainFile(config.sslChainFile()) - .withSSLServerSubjectPattern(config.sslClientSubjectPattern()); + .withSSLSubjectPattern(config.sslSubjectPattern()); + + if (!"".equals(config.sslKeyPassword())) { + builder.withSSLKeyPassword(config.sslKeyPassword()); + } StandbyClientSync standbyClientSync = builder.build(); closer.register(standbyClientSync); diff --git a/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/standby/StandbyTestIT.java b/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/standby/StandbyTestIT.java index 8908891bfd..b437b984d9 100644 --- a/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/standby/StandbyTestIT.java +++ b/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/standby/StandbyTestIT.java @@ -341,6 +341,99 @@ public class StandbyTestIT extends TestBase { } } + /** + * This test syncs a few segments over an encrypted connection. + * The server has a configured certificate which can be validated with the truststore. + * The server validates the client certificate. + * The client has a configured certificate which can be validated with the truststore. + * All the keys are encrypted. + */ + @Test + @Ignore("This test takes ~2s and is therefore disabled by default") + public void testSyncSSLValidClientEncryptedKeys() throws Exception { + int blobSize = 5 * MB; + FileStore primary = serverFileStore.fileStore(); + FileStore secondary = clientFileStore.fileStore(); + + FileOutputStream fos; + + File serverKeyFile = folder.newFile(); + fos = new FileOutputStream(serverKeyFile); + IOUtils.writeString(fos, encryptedServerKey); + fos.close(); + + File clientKeyFile = folder.newFile(); + fos = new FileOutputStream(clientKeyFile); + IOUtils.writeString(fos, encryptedClientKey); + fos.close(); + + File serverCertFile = folder.newFile(); + fos = new FileOutputStream(serverCertFile); + IOUtils.writeString(fos, serverCert); + fos.close(); + + File clientCertFile = folder.newFile(); + fos = new FileOutputStream(clientCertFile); + IOUtils.writeString(fos, clientCert); + fos.close(); + + File keyStoreFile = folder.newFile(); + KeyStore keyStore = KeyStore.getInstance("JKS"); + keyStore.load(null, "changeit".toCharArray()); + Certificate c = CertificateFactory.getInstance("X.509").generateCertificate(new ByteArrayInputStream(caCert.getBytes())); + keyStore.setCertificateEntry("the-ca-cert", c); + keyStore.store(new FileOutputStream(keyStoreFile), "changeit".toCharArray()); + System.setProperty("javax.net.ssl.trustStore", keyStoreFile.getAbsolutePath()); + + NodeStore store = SegmentNodeStoreBuilders.builder(primary).build(); + try ( + StandbyServerSync serverSync = StandbyServerSync.builder() + .withPort(serverPort.getPort()) + .withFileStore(primary) + .withBlobChunkSize(MB) + .withSecureConnection(true) + .withSSLKeyFile(serverKeyFile.getAbsolutePath()) + .withSSLKeyPassword(secretPassword) + .withSSLChainFile(serverCertFile.getAbsolutePath()) + .withSSLClientValidation(true) + .build(); + StandbyClientSync clientSync = StandbyClientSync.builder() + .withHost(getServerHost()) + .withPort(serverPort.getPort()) + .withFileStore(secondary) + .withSecureConnection(true) + .withReadTimeoutMs(getClientTimeout()) + .withAutoClean(false) + .withSpoolFolder(folder.newFolder()) + .withSSLKeyFile(clientKeyFile.getAbsolutePath()) + .withSSLKeyPassword(secretPassword) + .withSSLChainFile(clientCertFile.getAbsolutePath()) + .build() + ) { + serverSync.start(); + byte[] data = addTestContent(store, "server", blobSize, 1); + primary.flush(); + + clientSync.run(); + + assertEquals(primary.getHead(), secondary.getHead()); + + assertTrue(primary.getStats().getApproximateSize() > blobSize); + assertTrue(secondary.getStats().getApproximateSize() > blobSize); + + PropertyState ps = secondary.getHead().getChildNode("root") + .getChildNode("server").getProperty("testBlob"); + assertNotNull(ps); + assertEquals(Type.BINARY.tag(), ps.getType().tag()); + Blob b = ps.getValue(Type.BINARY); + assertEquals(blobSize, b.length()); + + byte[] testData = new byte[blobSize]; + ByteStreams.readFully(b.getNewStream(), testData); + assertArrayEquals(data, testData); + } + } + /** * This test syncs a few segments over an encrypted connection. * The server has a configured certificate which can be validated with the truststore. @@ -550,7 +643,7 @@ public class StandbyTestIT extends TestBase { .withSSLKeyFile(serverKeyFile.getAbsolutePath()) .withSSLChainFile(serverCertFile.getAbsolutePath()) .withSSLClientValidation(true) - .withSSLClientSubjectPattern("foobar") + .withSSLSubjectPattern("foobar") .build(); StandbyClientSync clientSync = StandbyClientSync.builder() .withHost(getServerHost()) @@ -628,7 +721,7 @@ public class StandbyTestIT extends TestBase { .withSSLKeyFile(serverKeyFile.getAbsolutePath()) .withSSLChainFile(serverCertFile.getAbsolutePath()) .withSSLClientValidation(true) - .withSSLClientSubjectPattern(".*.esting.*") + .withSSLSubjectPattern(".*.esting.*") .build(); StandbyClientSync clientSync = StandbyClientSync.builder() .withHost(getServerHost()) @@ -718,7 +811,7 @@ public class StandbyTestIT extends TestBase { .withSpoolFolder(folder.newFolder()) .withSSLKeyFile(clientKeyFile.getAbsolutePath()) .withSSLChainFile(clientCertFile.getAbsolutePath()) - .withSSLServerSubjectPattern("foobar") + .withSSLSubjectPattern("foobar") .build() ) { serverSync.start(); @@ -796,7 +889,7 @@ public class StandbyTestIT extends TestBase { .withSpoolFolder(folder.newFolder()) .withSSLKeyFile(clientKeyFile.getAbsolutePath()) .withSSLChainFile(clientCertFile.getAbsolutePath()) - .withSSLServerSubjectPattern(".*.esting.*") + .withSSLSubjectPattern(".*.esting.*") .build() ) { serverSync.start(); diff --git a/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/standby/TestBase.java b/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/standby/TestBase.java index 7a8370945b..e89e3749ad 100644 --- a/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/standby/TestBase.java +++ b/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/standby/TestBase.java @@ -241,4 +241,99 @@ public class TestBase { "pKHE9hkL/dxsEBXkVdaRHzrfxCBxsP3b3EmOJ4xdl1phGhedUk/+RUWGY8VSnyaq\n" + "uVMy1feUqV+AebfUSPzPVubV\n" + "-----END PRIVATE KEY-----\n"; + + static final String encryptedClientKey = + "-----BEGIN ENCRYPTED PRIVATE KEY-----\n" + + "MIIE6TAbBgkqhkiG9w0BBQMwDgQIZuy9oMDzt8wCAggABIIEyH7Rbg5VcLV/ZDqp\n" + + "AJ6tzPqMlnLVtspB/qk5nZRz2/n42yaqgO2eO7DJ5qNbBGZ6KzLosC6DHd1aXA7E\n" + + "8l5RTWQj0u16ANeKsjJ86o5/MRJkeUMh2tPLdVcG0e5nifgbWzXYpS6LuwKQpGEL\n" + + "ufSAWhF9BY1hMe58qzCFBsFjrd0tB232sDOnhopaLiO5tQ6h3iMvwK/EPXJGPKHX\n" + + "5++DlV/QNaENb/EsCvPlrRgpSWn6dAJ1kemKcvLbnHzTwK88B1n3GUr1B3Z+0jSV\n" + + "9IGNeIRVz97KGxW0v33SD1Kw4QpPH+PHH/HhmJ48Vv/mf1rINwA/yRE0iS89glhW\n" + + "NPh5O7HD2l2qZZDq74RUfvSzaW738/108ppck/uo+nOvEHnl346XJ7Etbp+fRYj1\n" + + "y/irfT7yZ1ZMUkms39M+yBwCp/AqdhvJemOLCAgSJcWWWsNnNqlQlJJsuvkcRPBr\n" + + "foYAsPWnZRcowZLyQ80gG5ZKoTa8Kyf/V2CuULHwYv16MLf0koLpGAEjd4QDLrun\n" + + "ybsRisrAFupgxNBLovyh6I4b97n0Qeotf/iIfmBOH7azYqpmvgJxNB6hNVwz2LAM\n" + + "JgnirRgY+FEdAyTd44/qPQpwXoz4ac3wrdGEU0oLwKk/J2bX1Eqh3tfziPycCO6v\n" + + "2IC3WGP59/ty3T1xA/LI0TqInAkUD+0Rkp1HhmPL4xEL/bGLL5FViFkybjO6pgoK\n" + + "xjq/dqTbrnmjyhVIjfdCbl2MFEsqUgemH/5J5o75P6mS0HOBaK6ERI9tM6dHz5Wk\n" + + "2AbwUUvEebLA6zR5+57dFKSQXhOOekRCQ9w8gDhPHMxyYp3YAdiFitweY/5Xhokt\n" + + "l3OXtLPNiqONcYp/Xkz5/CgsjoIHDGgQGy4sWYUQYCdAFXP8/ogR4zVpsUBP0Hjv\n" + + "9isg5MlXEEj+YOFYQr/HbON9zxP4LhzuYUWynvVJDfPxY1x7JI+aequHZRPj9Qct\n" + + "X6Va5c+G8q87fj/qCJCplGslhJsxBidTQw88+wNeVAVPd+456bszwIE5ey7glvTb\n" + + "gwmU4mXDm75T+PW3Y7Gz1HZ9ZCMuUBelBEKxVSOOXCxkO4zzfI9PVxVzkqfurVOO\n" + + "9R9i3gV3J6rQj98XtbvBTSrq9nylnzRiFSP2T0aRNLVRmGBahm9YIK+kll/VM2uL\n" + + "VzUYPJv22Q/cXR2lkwNFbScOGNzJ3UXiuWOM1CkBgadoHpKhmD4IypvMpA/B0tTL\n" + + "l4kL0z7Cg50kXYY77pl6cxorRnPs9fTpPWTPymqWp8Se+pfn/Fxqz11xD0P45Rlo\n" + + "0CHLS3536c2zX3/1Uh4ZIGTAwoWeiCfizTnaS7GbIniqJ1/KVx9L5gIu/uWHGSnY\n" + + "sU/gOHQw+HxkYGXYI5AqWUp79CZUEnKsNVZDAexKWraG3TBJSydZcyl3OcEfez+f\n" + + "ISw//WpK5Wc+Zc+KabT8eWGwN1bIV/5HP1hSx6kggtQBs6BSkEDirzzzvQeIvdol\n" + + "ddjGSudEjO2EBE25utg+5omiR8uCQwwInNNOr2otMikmWRgQ3AuIuqxYAF0qH1+f\n" + + "n6ePw/b30oy4xIKWz8Kxrn8oPLYgs1Dl3lF6LjRwq1urC2leYb6ZPaX5QjdarMJp\n" + + "sxOT5nOmsaG0vinlsQ==\n" + + "-----END ENCRYPTED PRIVATE KEY-----"; + + static final String encryptedServerKey = + "-----BEGIN ENCRYPTED PRIVATE KEY-----\n" + + "MIIE6TAbBgkqhkiG9w0BBQMwDgQIto3hFjULIx0CAggABIIEyNWG0f8x6yY3XeE+\n" + + "WZjuFYe5WG4ftC8hvKgYCY1NhkFSH3R4FIkAdRanuskUI9rU6tzXEEVKpnsMNTf5\n" + + "AhQz/bI4fdu57vyz/ujwmdBMtP9m5hBjyfcJq6w/g1bECC6garbeTYvXgUljyV1n\n" + + "h8WQ4rClFhAZ1Qrujc6DTd63BGVoGxY+Jxe6FA2mZj2Z1bCsiWFGU0ShnU+QDF/O\n" + + "2SPcHHy37uckIdSrSFAuY8+iwQ5fL5mRH3Gw1CopQY07R8RKyRKpuZV56zJDXmGv\n" + + "j0NfJul26EmqXJSTLJyMlYdIP+xSPo50qTWqOl7w37fRcAw7duVP2jIlHJEJD9Y1\n" + + "UJe4ypihLp402Amw19wnsaxwk9PDDUd7kN1xFQMJ/eVF5k2hEL3m+2g6PbuFoSHt\n" + + "FVQEMDGqeAIPvrUr9FwO0qU7x0hJ1ce/v6IyYhJwbuVDzUFP0nHalTSVM/lXOshO\n" + + "dUqY97hOMh+q9drNUCQM08gq3XD/HQP/zA6LYH+X9Ts9Y0R+cocOXwbxc2jKAimo\n" + + "MwmP9bSD9MPabGGTv4ZeTVK9JTq4uetCk3ehqNEpS7d69bq0pJ3F6xvGaL7GjiQA\n" + + "8YyEUFtbyaBDgg4iwIiPsy/jo7h6Gj1Io/TjcDnp38h1YMTrER2nljB8lSm3t7DA\n" + + "5KOzLKHvvB8gUfMiM3OzbIcXtBJIWWidELToqEljAVHWt054yaI4oX1laHOa3zPG\n" + + "yriTUARkp5lA2llrm9E1AevlOxpUz3cr94ohvSI40QZgehcvraHJ7FCP7SUi54uY\n" + + "o7MRDe27zLsjYRoSLD6saSFL1XigjCa4dpOu3yN8q/R0NyjmBySxOlPbglyl/OmD\n" + + "czWFvUQcHcuSsPosbp30nsDD5SIGY6p+XR8tqJdKrCh+vgFlQPb1OkvGcXD7uzjI\n" + + "0jYVc23pUwrM3oynAjll2uEBlMfHsdYTB5ehv/sp7tqnc3/VbPhW9WOercbQvVnq\n" + + "Gb13aL4ra94glERJFH5LitvmjkylD6tjOttDONYg9ow1dA5g2q/A7WD0UV4TrW2w\n" + + "LRze30kKG2p94DE1if54VMA91QLhU3YwntDSk8jZ6bO7rG91d98npwHWZfMzJI6J\n" + + "blHM5gaAmHCTvwX6/Px/tS+8HmG5l8BBBqz70gh24uYjMgsTWsfRsjfypBmXzEFt\n" + + "JiFJIBwGQ0uHDM2JXqIdCf1em875eK3XR6qvrQDPiA5HVXFaGdRGbx0aK7lzDHrn\n" + + "7cn02kNLb4/kbZnpj04p7/j6dpfGLMnkSH7Pxx4f0cfirfDvcZQwjpl/n4bHnIxT\n" + + "Qv6XWq67dQObvbiCZF14CayEEqNU6Q9wq+EBji2739FhAAbZ0P1Uj792wk50tOgg\n" + + "+EqXzCGaqSRn7RrMEiQQTGBson9L6aBlNxyBRH6LMLAsvcKzlYB5zMQHwObd/eaU\n" + + "43WdwOly9CLeJbTpPNvZoeDGT7jdin3XiuauMnDa4W1wwKHKgpbD543ScZfIkNm1\n" + + "Wcibp27rE4/5eIsNyQnxkDRN7f3x0a9iwhlgrToXGabileLsonx3Jdf/YXgiqiQY\n" + + "4lLGr4EIVjKg8YbJvpnrEZQNeTHwPr8/N5N51VZvoVePBq/ZnBi9EK/aCL+f+0Dx\n" + + "yZio9eDGsuOXwR7iOg==\n" + + "-----END ENCRYPTED PRIVATE KEY-----"; + + static final String encryptedArbitraryKey = + "-----BEGIN ENCRYPTED PRIVATE KEY-----\n" + + "MIIE6TAbBgkqhkiG9w0BBQMwDgQIT+Z6cmw0caMCAggABIIEyCCZWzPzrAGr7nsi\n" + + "ifNxQbX0GO6wYb3ND7yinc/0Yw+d38l0S5LTLg+5GD7SbXfoMmC44rUxSGnBV5Bj\n" + + "/bUW30B/s0+I3Ya1pXXyVP98vjy71Pspw/sHH3tYU73fPdqzh538Jf9qEgqgaJej\n" + + "MRdiQfQmXexmkyeWAYQutbONrwfuH8NqLGxuPjrc21WjKkijnv9X8CuUk6M1MCPc\n" + + "jN2iPhTsYiOkgKkyjF817792jDBYJHtoOuG5OmhSAdw6I3Tm5TRqAO/6IGPuDqWb\n" + + "7ho3ZyLBxBaLHTOawQkGm842lhwn5fACCCYNGsQhVGdbZN4KVgSYzJwvGw8vaawE\n" + + "VhD+zcDzhAydlhMXwFxDMgoZD5qRZujuDoBLgBYrDFDDEUfDNoUJSmWPpHXVc2tq\n" + + "RBiP3xb152lWiqRcXLZVHfXfxT79qZAxvlRBUgYEA/u2ud3p2/7R9UBvRzE6P6IA\n" + + "9ZuO6CgJgGvHXY2u721/MvvhY/75X1c1t0VJsdU2H6+E34QDtSqmQD08zBlZw5TK\n" + + "qltQpxgjMO1jtdEuHWPbR5Aoa5smOL9qBleptSGsm0I5zET+hv4y3f5AHIx3X3xy\n" + + "UH6Nw30oQtSbbZzPX4sqZuzA66W9Z4yW3Pn1EYcpuacypty/gvRZrvnwb6gYNB+h\n" + + "XTTaikNiGebcAZhSukcKmL3mjlpbUZC3Bjbz5AstZJyd0tMSaw0E4C8VQQHYyX5X\n" + + "lteW1O2TvHyGdeb0LNwsXzIMqsqmgsuNsms12Xx7KurxhPGk3Za2SdXQUASSryWX\n" + + "XPlKxlQDDM9DvSQsRw6BCUoUKZ/2YiXnnL/zrY1+xegXumwolgT8Dsu6CFxvzT7E\n" + + "16/4FeaVDB0/A5nmR71gkwm/b/JJL/Qj0H+E0rhCyZJeW9ddg4IWolEFTvCrVmHG\n" + + "gZ8DQIHJHSPilG8gdjzJ8cs89pctswnjuLMI2wT2/jqtM76Ibr9d0eIB6CzT17dh\n" + + "ASchmnUUXgjY/djAO8M3LuMUgu6OTCpIwAjfz7DOaakI42Dvrz0sTCkBwjD3XY7v\n" + + "1EyxoxCPoxTlHE1BLNgT5OD0B9SPC9aQLt+DOcDXVh8vQvIGtqMbxthIoi61XTeo\n" + + "sm35wkdiC0wSCgqPKIiz/LcyaWcOwbK2F7Q1dKluBT29L6X35FLqbp8RNZLJSX18\n" + + "53gJJLH4Hd7XcAn2Sat+vyuY3Z3vNiFMmx+vbho3ZgGL5KTNdmpN1fM7EqpGOUfp\n" + + "easRPOw3P1KuVqTVCvm/osf4VniV3xCvgwffJ/kOlHChnIrHGZpeBFmiV4xk7ucb\n" + + "7PSVt8BLV2+krXSTijFepeuVckitj3Kf4o++WePE6wlPi0rPYG47IE10xHojSKgr\n" + + "xdEonxiGL07/MEdI9+9PHLg5+ZakymRmMnEcJdpd7+WxaFy8jhvCCZ+7ppZBpYQC\n" + + "azdkciNz9d/YZRQH5M6VGk1VqqkQbenasUuZpXAxDOraLPlq801JyYyPqeROAgb8\n" + + "hTQXseAe+7lHWpmUGKuN0Y9EcV/3fiAP+PeMt/QXeGF5jcRVGWLs6nDVOaBQ/SB3\n" + + "syFXwJR6WtajR5OC7dEGZPTxaNfiu4GFuE73i3cVEJH2MH7+c/yB/40RJQdJ4kd6\n" + + "7KJYwr8P4TrNulM60Q==\n" + + "-----END ENCRYPTED PRIVATE KEY-----\n"; + + static final String secretPassword = "secret"; } -- 2.17.1