diff --git a/common/util/pom.xml b/common/util/pom.xml index 14ae1748b2..bce6a6fc80 100644 --- a/common/util/pom.xml +++ b/common/util/pom.xml @@ -36,6 +36,14 @@ + + org.bouncycastle + bcprov-jdk15on + + + org.bouncycastle + bcpkix-jdk15on + org.springframework spring-core diff --git a/common/util/src/main/java/org/thingsboard/common/util/SslUtil.java b/common/util/src/main/java/org/thingsboard/common/util/SslUtil.java new file mode 100644 index 0000000000..889436671a --- /dev/null +++ b/common/util/src/main/java/org/thingsboard/common/util/SslUtil.java @@ -0,0 +1,105 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.common.util; + +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openssl.PEMDecryptorProvider; +import org.bouncycastle.openssl.PEMEncryptedKeyPair; +import org.bouncycastle.openssl.PEMKeyPair; +import org.bouncycastle.openssl.PEMParser; +import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; +import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder; +import org.bouncycastle.operator.InputDecryptorProvider; +import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo; +import org.bouncycastle.pkcs.jcajce.JcePKCSPBEInputDecryptorProviderBuilder; +import org.thingsboard.server.common.data.StringUtils; + +import java.io.StringReader; +import java.security.PrivateKey; +import java.security.Security; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; + +@Slf4j +public class SslUtil { + + public static final char[] EMPTY_PASS = {}; + + public static final BouncyCastleProvider DEFAULT_PROVIDER = new BouncyCastleProvider(); + + static { + if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) { + Security.addProvider(DEFAULT_PROVIDER); + } + } + + private SslUtil() { + } + + @SneakyThrows + public static List readCertFile(String fileContent) { + List certificates = new ArrayList<>(); + JcaX509CertificateConverter certConverter = new JcaX509CertificateConverter(); + try (PEMParser pemParser = new PEMParser(new StringReader(fileContent))) { + Object object; + while ((object = pemParser.readObject()) != null) { + if (object instanceof X509CertificateHolder) { + X509Certificate x509Cert = certConverter.getCertificate((X509CertificateHolder) object); + certificates.add(x509Cert); + } + } + } + return certificates; + } + + @SneakyThrows + public static PrivateKey readPrivateKey(String fileContent, String passStr) { + char[] password = StringUtils.isEmpty(passStr) ? EMPTY_PASS : passStr.toCharArray(); + + PrivateKey privateKey = null; + JcaPEMKeyConverter keyConverter = new JcaPEMKeyConverter(); + if (StringUtils.isNotEmpty(fileContent)) { + try (PEMParser pemParser = new PEMParser(new StringReader(fileContent))) { + Object object; + while ((object = pemParser.readObject()) != null) { + if (object instanceof PEMEncryptedKeyPair) { + PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(password); + privateKey = keyConverter.getKeyPair(((PEMEncryptedKeyPair) object).decryptKeyPair(decProv)).getPrivate(); + break; + } else if (object instanceof PKCS8EncryptedPrivateKeyInfo) { + InputDecryptorProvider decProv = + new JcePKCSPBEInputDecryptorProviderBuilder().setProvider(DEFAULT_PROVIDER).build(password); + privateKey = keyConverter.getPrivateKey(((PKCS8EncryptedPrivateKeyInfo) object).decryptPrivateKeyInfo(decProv)); + break; + } else if (object instanceof PEMKeyPair) { + privateKey = keyConverter.getKeyPair((PEMKeyPair) object).getPrivate(); + break; + } else if (object instanceof PrivateKeyInfo) { + privateKey = keyConverter.getPrivateKey((PrivateKeyInfo) object); + } + } + } + } + return privateKey; + } + +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java index 0137887aaf..3824e71459 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java @@ -20,68 +20,34 @@ import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContextBuilder; import lombok.Data; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.codec.binary.Base64; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.bouncycastle.openssl.PEMDecryptorProvider; -import org.bouncycastle.openssl.PEMEncryptedKeyPair; -import org.bouncycastle.openssl.PEMKeyPair; -import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; -import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder; -import org.bouncycastle.util.encoders.Hex; +import org.thingsboard.common.util.SslUtil; import org.thingsboard.server.common.data.StringUtils; -import javax.crypto.Cipher; -import javax.crypto.EncryptedPrivateKeyInfo; -import javax.crypto.SecretKey; -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.PBEKeySpec; -import javax.crypto.spec.SecretKeySpec; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.TrustManagerFactory; -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.math.BigInteger; -import java.nio.ByteBuffer; -import java.security.AlgorithmParameters; -import java.security.Key; -import java.security.KeyFactory; -import java.security.KeyPair; import java.security.KeyStore; -import java.security.MessageDigest; import java.security.PrivateKey; -import java.security.Security; +import java.security.cert.CertPath; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; -import java.security.spec.KeySpec; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.RSAPrivateCrtKeySpec; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import java.util.stream.Collectors; @Data @Slf4j @JsonIgnoreProperties(ignoreUnknown = true) public class CertPemCredentials implements ClientCredentials { - private static final String TLS_VERSION = "TLSv1.2"; + + public static final String PRIVATE_KEY_ALIAS = "private-key"; + public static final String X_509 = "X.509"; + public static final String CERT_ALIAS_PREFIX = "cert-"; + public static final String CA_CERT_CERT_ALIAS_PREFIX = "caCert-cert-"; protected String caCert; private String cert; private String privateKey; - private String password; - - static final String OPENSSL_ENCRYPTED_RSA_PRIVATEKEY_REGEX = "\\s*" - + "-----BEGIN RSA PRIVATE KEY-----" + "\\s*" - + "Proc-Type: 4,ENCRYPTED" + "\\s*" - + "DEK-Info:" + "\\s*([^\\s]+)" + "\\s+" - + "([\\s\\S]*)" - + "-----END RSA PRIVATE KEY-----" + "\\s*"; - - static final Pattern OPENSSL_ENCRYPTED_RSA_PRIVATEKEY_PATTERN = Pattern.compile(OPENSSL_ENCRYPTED_RSA_PRIVATEKEY_REGEX); + private String password = ""; @Override public CredentialsType getType() { @@ -91,7 +57,6 @@ public class CertPemCredentials implements ClientCredentials { @Override public SslContext initSslContext() { try { - Security.addProvider(new BouncyCastleProvider()); SslContextBuilder builder = SslContextBuilder.forClient(); if (StringUtils.hasLength(caCert)) { builder.trustManager(createAndInitTrustManagerFactory()); @@ -106,51 +71,13 @@ public class CertPemCredentials implements ClientCredentials { } } - private KeyManagerFactory createAndInitKeyManagerFactory() throws Exception { - List certHolders = readCertFile(cert); - Object keyObject = readPrivateKeyFile(privateKey); - char[] passwordCharArray = "".toCharArray(); - if (!StringUtils.isEmpty(password)) { - passwordCharArray = password.toCharArray(); - } - - JcaPEMKeyConverter keyConverter = new JcaPEMKeyConverter().setProvider("BC"); - - PrivateKey privateKey; - if (keyObject instanceof PEMEncryptedKeyPair) { - PEMDecryptorProvider provider = new JcePEMDecryptorProviderBuilder().build(passwordCharArray); - KeyPair key = keyConverter.getKeyPair(((PEMEncryptedKeyPair) keyObject).decryptKeyPair(provider)); - privateKey = key.getPrivate(); - } else if (keyObject instanceof PEMKeyPair) { - KeyPair key = keyConverter.getKeyPair((PEMKeyPair) keyObject); - privateKey = key.getPrivate(); - } else if (keyObject instanceof PrivateKey) { - privateKey = (PrivateKey) keyObject; - } else { - throw new RuntimeException("Unable to get private key from object: " + keyObject.getClass()); - } - - KeyStore clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - clientKeyStore.load(null, null); - for (X509Certificate certHolder : certHolders) { - clientKeyStore.setCertificateEntry("cert-" + certHolder.getSubjectDN().getName(), certHolder); - } - clientKeyStore.setKeyEntry("private-key", - privateKey, - passwordCharArray, - certHolders.toArray(new Certificate[]{})); - KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - keyManagerFactory.init(clientKeyStore, passwordCharArray); - return keyManagerFactory; - } - protected TrustManagerFactory createAndInitTrustManagerFactory() throws Exception { - List caCertHolders = readCertFile(caCert); + List caCerts = SslUtil.readCertFile(caCert); KeyStore caKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); caKeyStore.load(null, null); - for (X509Certificate caCertHolder : caCertHolders) { - caKeyStore.setCertificateEntry("caCert-cert-" + caCertHolder.getSubjectDN().getName(), caCertHolder); + for (X509Certificate caCert : caCerts) { + caKeyStore.setCertificateEntry(CA_CERT_CERT_ALIAS_PREFIX + caCert.getSubjectDN().getName(), caCert); } TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); @@ -158,170 +85,31 @@ public class CertPemCredentials implements ClientCredentials { return trustManagerFactory; } - List readCertFile(String fileContent) throws Exception { - if (fileContent == null || fileContent.trim().isEmpty()) { - return Collections.emptyList(); - } - - List certificates = new ArrayList<>(); - String[] pems = fileContent.trim().split("-----END CERTIFICATE-----"); - for (String pem : pems) { - if (pem.trim().isEmpty()) { - continue; - } - pem = pem.replace("-----BEGIN CERTIFICATE-----", "") - .replace("-----END CERTIFICATE-----", "") - .replaceAll("\\s", ""); - byte[] decoded = Base64.decodeBase64(pem); - CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); - try (InputStream inStream = new ByteArrayInputStream(decoded)) { - certificates.add((X509Certificate) certFactory.generateCertificate(inStream)); - } - } - return certificates; - } - - private PrivateKey readPrivateKeyFile(String fileContent) throws Exception { - PrivateKey privateKey = null; - if (fileContent != null && !fileContent.isEmpty()) { - KeyFactory keyFactory = KeyFactory.getInstance("RSA"); - KeySpec keySpec = getKeySpec(fileContent); - privateKey = keyFactory.generatePrivate(keySpec); - } - return privateKey; + private KeyManagerFactory createAndInitKeyManagerFactory() throws Exception { + KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + kmf.init(loadKeyStore(), password.toCharArray()); + return kmf; } - private KeySpec getKeySpec(String encodedKey) throws Exception { - KeySpec keySpec = null; - Matcher matcher = OPENSSL_ENCRYPTED_RSA_PRIVATEKEY_PATTERN.matcher(encodedKey); - if (matcher.matches()) { - String encryptionDetails = matcher.group(1).trim(); - String encryptedKey = matcher.group(2).replaceAll("\\s", ""); - byte[] encryptedBinaryKey = java.util.Base64.getDecoder().decode(encryptedKey); - String[] encryptionDetailsParts = encryptionDetails.split(","); - if (encryptionDetailsParts.length == 2) { - String encryptionAlgorithm = encryptionDetailsParts[0]; - String encryptedAlgorithmParams = encryptionDetailsParts[1]; - byte[] pw = password.getBytes(); - byte[] iv = Hex.decode(encryptedAlgorithmParams); - - MessageDigest digest = MessageDigest.getInstance("MD5"); - digest.update(pw); - digest.update(iv, 0, 8); - - byte[] round1Digest = digest.digest(); - digest.update(round1Digest); - digest.update(pw); - digest.update(iv, 0, 8); - - byte[] round2Digest = digest.digest(); - Cipher cipher = null; - SecretKey secretKey = null; - byte[] key = null; + protected KeyStore loadKeyStore() throws Exception { + List certificates = SslUtil.readCertFile(this.cert); + PrivateKey privateKey = SslUtil.readPrivateKey(this.privateKey, password); - switch(encryptionAlgorithm) { - case "AES-256-CBC": - cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - key = new byte[32]; - System.arraycopy(round1Digest, 0, key, 0, 16); - System.arraycopy(round2Digest, 0, key, 16, 16); - secretKey = new SecretKeySpec(key, "AES"); - break; - case "AES-192-CBC": - cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - key = new byte[24]; - System.arraycopy(round1Digest, 0, key, 0, 16); - System.arraycopy(round2Digest, 0, key, 16, 8); - secretKey = new SecretKeySpec(key, "AES"); - break; - case "AES-128-CBC": - cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - key = new byte[16]; - System.arraycopy(round1Digest, 0, key, 0, 16); - secretKey = new SecretKeySpec(key, "AES"); - break; - case "DES-EDE3-CBC": - cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding"); - key = new byte[24]; - System.arraycopy(round1Digest, 0, key, 0, 16); - System.arraycopy(round2Digest, 0, key, 16, 8); - secretKey = new SecretKeySpec(key, "DESede"); - break; - case "DES-CBC": - cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); - key = new byte[8]; - System.arraycopy(round1Digest, 0, key, 0, 8); - secretKey = new SecretKeySpec(key, "DES"); - break; - } - if (cipher != null) { - cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv)); - byte[] pkcs1 = cipher.doFinal(encryptedBinaryKey); - keySpec = decodeRSAPrivatePKCS1(pkcs1); - } else { - throw new RuntimeException("Unknown Encryption algorithm!"); - } - } else { - throw new RuntimeException("Wrong encryption details!"); - } - } else { - encodedKey = encodedKey.replaceAll(".*BEGIN.*PRIVATE KEY.*", "") - .replaceAll(".*END.*PRIVATE KEY.*", "") - .replaceAll("\\s", ""); - byte[] decoded = Base64.decodeBase64(encodedKey); - if (password == null || password.isEmpty()) { - keySpec = new PKCS8EncodedKeySpec(decoded); - } else { - PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray()); - - EncryptedPrivateKeyInfo privateKeyInfo = new EncryptedPrivateKeyInfo(decoded); - String algorithmName = privateKeyInfo.getAlgName(); - Cipher cipher = Cipher.getInstance(algorithmName); - SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(algorithmName); - - Key pbeKey = secretKeyFactory.generateSecret(pbeKeySpec); - AlgorithmParameters algParams = privateKeyInfo.getAlgParameters(); - cipher.init(Cipher.DECRYPT_MODE, pbeKey, algParams); - keySpec = privateKeyInfo.getKeySpec(cipher); - } + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + keyStore.load(null); + List unique = certificates.stream().distinct().collect(Collectors.toList()); + for (X509Certificate cert : unique) { + keyStore.setCertificateEntry(CERT_ALIAS_PREFIX + cert.getSubjectDN().getName(), cert); } - return keySpec; - } - - private static BigInteger derint(ByteBuffer input) { - int len = der(input, 0x02); - byte[] value = new byte[len]; - input.get(value); - return new BigInteger(+1, value); - } - private static int der(ByteBuffer input, int exp) { - int tag = input.get() & 0xFF; - if (tag != exp) throw new IllegalArgumentException("Unexpected tag"); - int n = input.get() & 0xFF; - if (n < 128) return n; - n &= 0x7F; - if ((n < 1) || (n > 2)) throw new IllegalArgumentException("Invalid length"); - int len = 0; - while (n-- > 0) { - len <<= 8; - len |= input.get() & 0xFF; + if (privateKey != null) { + CertificateFactory factory = CertificateFactory.getInstance(X_509); + CertPath certPath = factory.generateCertPath(certificates); + List path = certPath.getCertificates(); + Certificate[] x509Certificates = path.toArray(new Certificate[0]); + keyStore.setKeyEntry(PRIVATE_KEY_ALIAS, privateKey, password.toCharArray(), x509Certificates); } - return len; + return keyStore; } - static RSAPrivateCrtKeySpec decodeRSAPrivatePKCS1(byte[] encoded) { - ByteBuffer input = ByteBuffer.wrap(encoded); - if (der(input, 0x30) != input.remaining()) throw new IllegalArgumentException("Excess data"); - if (!BigInteger.ZERO.equals(derint(input))) throw new IllegalArgumentException("Unsupported version"); - BigInteger n = derint(input); - BigInteger e = derint(input); - BigInteger d = derint(input); - BigInteger p = derint(input); - BigInteger q = derint(input); - BigInteger ep = derint(input); - BigInteger eq = derint(input); - BigInteger c = derint(input); - return new RSAPrivateCrtKeySpec(n, e, d, p, q, ep, eq, c); - } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/credentials/CertPemCredentialsTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/credentials/CertPemCredentialsTest.java index 904f470001..2cecd1490d 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/credentials/CertPemCredentialsTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/credentials/CertPemCredentialsTest.java @@ -18,21 +18,36 @@ package org.thingsboard.rule.engine.credentials; import org.apache.commons.io.FileUtils; import org.junit.Assert; import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.thingsboard.common.util.SslUtil; import java.io.File; import java.io.IOException; +import java.security.Key; +import java.security.KeyStore; +import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.util.List; +import java.util.stream.Stream; + +import static org.thingsboard.rule.engine.credentials.CertPemCredentials.CERT_ALIAS_PREFIX; +import static org.thingsboard.rule.engine.credentials.CertPemCredentials.PRIVATE_KEY_ALIAS; public class CertPemCredentialsTest { - private final CertPemCredentials credentials = new CertPemCredentials(); + private static final String PASS = "test"; + private static final String EMPTY_PASS = ""; + private static final String RSA = "RSA"; + private static final String EC = "EC"; @Test public void testChainOfCertificates() throws Exception { String fileContent = fileContent("pem/tb-cloud-chain.pem"); - List x509Certificates = credentials.readCertFile(fileContent); + List x509Certificates = SslUtil.readCertFile(fileContent); Assert.assertEquals(4, x509Certificates.size()); Assert.assertEquals("CN=*.thingsboard.cloud, O=\"ThingsBoard, Inc.\", ST=New York, C=US", @@ -49,7 +64,7 @@ public class CertPemCredentialsTest { public void testSingleCertificate() throws Exception { String fileContent = fileContent("pem/tb-cloud.pem"); - List x509Certificates = credentials.readCertFile(fileContent); + List x509Certificates = SslUtil.readCertFile(fileContent); Assert.assertEquals(1, x509Certificates.size()); Assert.assertEquals("CN=*.thingsboard.cloud, O=\"ThingsBoard, Inc.\", ST=New York, C=US", @@ -60,11 +75,43 @@ public class CertPemCredentialsTest { public void testEmptyFileContent() throws Exception { String fileContent = fileContent("pem/empty.pem"); - List x509Certificates = credentials.readCertFile(fileContent); + List x509Certificates = SslUtil.readCertFile(fileContent); Assert.assertEquals(0, x509Certificates.size()); } + private static Stream testLoadKeyStore() { + return Stream.of( + Arguments.of("pem/rsa_cert.pem", "pem/rsa_key.pem", EMPTY_PASS, RSA), + Arguments.of("pem/rsa_encrypted_cert.pem", "pem/rsa_encrypted_key.pem", PASS, RSA), + Arguments.of("pem/rsa_encrypted_traditional_cert.pem", "pem/rsa_encrypted_traditional_key.pem", PASS, RSA), + Arguments.of("pem/ec_cert.pem", "pem/ec_key.pem", EMPTY_PASS, EC) + ); + } + + @ParameterizedTest + @MethodSource + public void testLoadKeyStore(String certPath, String keyPath, String password, String algorithm) throws Exception { + CertPemCredentials certPemCredentials = new CertPemCredentials(); + String certContent = fileContent(certPath); + certPemCredentials.setCert(certContent); + certPemCredentials.setPrivateKey(fileContent(keyPath)); + certPemCredentials.setPassword(password); + KeyStore keyStore = certPemCredentials.loadKeyStore(); + Assertions.assertNotNull(keyStore); + Key key = keyStore.getKey(PRIVATE_KEY_ALIAS, password.toCharArray()); + Assertions.assertNotNull(key); + Assertions.assertEquals(algorithm, key.getAlgorithm()); + + List certs = SslUtil.readCertFile(certContent); + for (X509Certificate cert : certs) { + String alias = CERT_ALIAS_PREFIX + cert.getIssuerDN().getName(); + Certificate certificate = keyStore.getCertificate(alias); + Assertions.assertNotNull(certificate); + Assertions.assertEquals(new String(cert.getEncoded()), new String(certificate.getEncoded())); + } + } + private String fileContent(String fileName) throws IOException { ClassLoader classLoader = getClass().getClassLoader(); File file = new File(classLoader.getResource(fileName).getFile()); diff --git a/rule-engine/rule-engine-components/src/test/resources/pem/ec_cert.pem b/rule-engine/rule-engine-components/src/test/resources/pem/ec_cert.pem new file mode 100644 index 0000000000..f22f61d3a1 --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/resources/pem/ec_cert.pem @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIICCDCCAa2gAwIBAgIUGx/SZqIWza/i/gaKFUVIyTEu2oMwCgYIKoZIzj0EAwIw +WTELMAkGA1UEBhMCVUExDTALBgNVBAgMBEtZSVYxDTALBgNVBAcMBEtZSVYxCzAJ +BgNVBAoMAlRCMQswCQYDVQQLDAJUQjESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIz +MTAxNjEyMjMyMVoXDTI0MTAxNTEyMjMyMVowWTELMAkGA1UEBhMCVUExDTALBgNV +BAgMBEtZSVYxDTALBgNVBAcMBEtZSVYxCzAJBgNVBAoMAlRCMQswCQYDVQQLDAJU +QjESMBAGA1UEAwwJbG9jYWxob3N0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE +z4MgawieJfVc5zUOPiw5WFxfHGJf7dOMsHvudDxdOs27PXPbJfi09BVJ3+JjNxA2 +wQz9KUk877oWRYrN/e+MbKNTMFEwHQYDVR0OBBYEFDTV8VD3m+8IBQOBJ+V/bcbl +4preMB8GA1UdIwQYMBaAFDTV8VD3m+8IBQOBJ+V/bcbl4preMA8GA1UdEwEB/wQF +MAMBAf8wCgYIKoZIzj0EAwIDSQAwRgIhAOgIkl8j8m51W7pWlNUAuUnHnOVhVjGr +h8Rc6cbwTapKAiEA2CLrduTweXEF5fBRtWyOsG8c9af6+MWHKmwHL1IDw9Q= +-----END CERTIFICATE----- diff --git a/rule-engine/rule-engine-components/src/test/resources/pem/ec_key.pem b/rule-engine/rule-engine-components/src/test/resources/pem/ec_key.pem new file mode 100644 index 0000000000..74e0716259 --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/resources/pem/ec_key.pem @@ -0,0 +1,8 @@ +-----BEGIN EC PARAMETERS----- +BggqhkjOPQMBBw== +-----END EC PARAMETERS----- +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIIEd0mMh0EEy3fMbOpbUY6kW0oAYcaYoTvoVpZxDr5qZoAoGCCqGSM49 +AwEHoUQDQgAEz4MgawieJfVc5zUOPiw5WFxfHGJf7dOMsHvudDxdOs27PXPbJfi0 +9BVJ3+JjNxA2wQz9KUk877oWRYrN/e+MbA== +-----END EC PRIVATE KEY----- \ No newline at end of file diff --git a/rule-engine/rule-engine-components/src/test/resources/pem/rsa_cert.pem b/rule-engine/rule-engine-components/src/test/resources/pem/rsa_cert.pem new file mode 100644 index 0000000000..f89fce7444 --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/resources/pem/rsa_cert.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFkzCCA3ugAwIBAgIUUQa3cWUVoF58dzg8ycb/y7SdCj8wDQYJKoZIhvcNAQEL +BQAwWTELMAkGA1UEBhMCVUExDTALBgNVBAgMBEtZSVYxDTALBgNVBAcMBEtZSVYx +CzAJBgNVBAoMAlRCMQswCQYDVQQLDAJUQjESMBAGA1UEAwwJbG9jYWxob3N0MB4X +DTIzMTAxMzEyMzcwMVoXDTI0MTAxMjEyMzcwMVowWTELMAkGA1UEBhMCVUExDTAL +BgNVBAgMBEtZSVYxDTALBgNVBAcMBEtZSVYxCzAJBgNVBAoMAlRCMQswCQYDVQQL +DAJUQjESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAsHn27cH+pYFI0eJYer8ww29g/xlKgr9aarYlkILeXnBhPPHBCXG+ +FegeMpHa8FUPANIqYJiwM13altO6hMLPa0J7+nQhwF5NCbxzAdi/kU8ofhIwJH+K +gOsD3BKdR7Ua7KMDQFnGTFRR9ZxsuYZ/0AHuzPHwxSLUvvMbiWbu5P2FYMrEyyLo +uVVihZPkeBhcnI6SJRyCdMdMy282nWQ+47gAUI3cFa7dXxUcXvRbbToMNPTIDUy4 +VhxJYhL4T6ED0Ds7tZRsG71LcMfw2RQUgiS1FuYh+O7N8lUMukMy2/umQluM0+qB +CYWa2p1UCbVzlrW1qgKQm1Q8E91XSR9KL/zdO8m9/uNeI1jyJu6i1cibWR7gnh6J +ChLxouQlrBzuLzSz7PG8q1MOWi+oHYJWSvmsckbQDhwEsfhFrYVgndJdxnmlkzvS +1OP7RGSYXLfMF+ZxC2YEJiU65QACCl2IHknyNiL8Jg5ahXgZMNshyfvOv5RB5jnz +4vzRpGhUYCcyLzORT+5gY9ZYbX/51cOomQV1ryTTQs+zA8mfEVLjbbLqvYdI84LC +3chMdcOm8Z9U1xdb2FX/c724XDyPnQNy1PLggzqvOFZzLeey0nBVUWyVrcCydbS5 +PAvVoAucO8kqP6b7uB7QnDeGaCiAVF+9QaXxjyQEdLEu3z5JMM7uH4UCAwEAAaNT +MFEwHQYDVR0OBBYEFHXrT3L+O3kJ2xNZ4Lh1ThGG6M1vMB8GA1UdIwQYMBaAFHXr +T3L+O3kJ2xNZ4Lh1ThGG6M1vMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggIBABFDqkTdxsJyu5L2x3WSpw4jw4vgJYlgUvTSeU8i54DaSzncLZdpWsqb +37LFHkvlquIfvOi9f9EBT2KuZwaajPQBNE4m7kLchoAv8Mc8a2EXhN2caXamnN3F +vWAb4QW/VHKKz2vWprfARwqQO58TEPgzU4FcW1lPpX2ULBeoS5kZDDEgyfaFZETF +FnsSb9E3/YuH6sJCu880kbW8BIyQmbUytrbn+16J/iaZBwc+iD49t2VBLDOsr1x4 +5qzxknG3h9wiz9ob9v6hWFfMpdiK12S0P5FVsUkCpxoae8jc8rPS7W3HaYowFjVR +OHOjtWy5/SV2rypKShjg9manf6iwGdTGkD0qoqsRs9JQFabjNR23IQv+1OUbrEVC +DbS65IjwLJlIZBX8JuJaU3I8zqj/9q7TtRDp1NCiG5W0NgipERRCciWaLJ+Fz6Lu +QzhI2ZOJrl49hmr6e0bsyNUv9l89WcbKm3/IC+V7o80uADYCOaz2jDGfKbvcPHzN +mTma8qVsjpcedttsvNMyZOsM/Rpk+dbChgReRVvcmzQV0izEvJJBWFr4HrfcM6Ev +sZrnUiT8ENUZqiK40d+T3Q6JheHwm+ENI1aUDkYCpoWZ/PzKe+Bj8lR8dPvmeVrc +eiwS37nMFO/5X7aIkszTouScNO99cN0UqPldfJo+8ZTbai5VFxGD +-----END CERTIFICATE----- diff --git a/rule-engine/rule-engine-components/src/test/resources/pem/rsa_encrypted_cert.pem b/rule-engine/rule-engine-components/src/test/resources/pem/rsa_encrypted_cert.pem new file mode 100644 index 0000000000..2f4e55a612 --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/resources/pem/rsa_encrypted_cert.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIUKAylzm/K5OfbXSjm1zY9bX1a8HQwDQYJKoZIhvcNAQEL +BQAwWTELMAkGA1UEBhMCVUExDTALBgNVBAgMBEtZSVYxDTALBgNVBAcMBEtZSVYx +CzAJBgNVBAoMAlRCMQswCQYDVQQLDAJUQjESMBAGA1UEAwwJbG9jYWxob3N0MB4X +DTIzMTAxNjIxMDQwNVoXDTI0MTAxNTIxMDQwNVowWTELMAkGA1UEBhMCVUExDTAL +BgNVBAgMBEtZSVYxDTALBgNVBAcMBEtZSVYxCzAJBgNVBAoMAlRCMQswCQYDVQQL +DAJUQjESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEA87nLliszEWml8QvyAC+H80NZCxf4TcG826NBOp0AUPJ8xQBHCzc1 +t1ohVm2/fn2VJZAYXG2xSVcHyXjjjv3iGLE2AIDbXh06/yFg4TVjlbrWrAHFehyN +FwrK8ez36oGLa3ZVq+mx1fLfBQw5mStbh09NXmKTzqP6m9ggKtt63cUwoWdUTemT +qrjryJd69LiJi+MVqtbKO2j30/lgAZmaHtbojl9EcvWfeXLb20TnXRIctaIS1VGo +SluzjbNQErdN/VRW4RAOP6UFsK0xID2EuLODBmAWnI49fXO/OS+u3Kd3suABE0o9 +slfDXqNTp0r5N0OoSAFcc4EsV3+9Gf+mqwIDAQABo1MwUTAdBgNVHQ4EFgQUhS5K +XQDxGvaBCpKY1de+JZl8zjYwHwYDVR0jBBgwFoAUhS5KXQDxGvaBCpKY1de+JZl8 +zjYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAxez4vLtBCBNM +l6AQghViNAR9iiwYMxUwKwlU+uZftRGnT+6dXgfTR3PV6LCfMMmtuNs0JTGy0ff8 +erbzfZxExvHfIFXCwepwTWawQhvRRn9GHOJXIzESDRRhsXoJDzd0JVOx0wWxp1cz +EUts+ZbKLoC+kIhsOGY+0a+sopeV2rMO5bUMpA8P0mKZlGynEGMLzKxz65E/IA9h +EQKpJjpvYfN+7eUkF6ZRXNV2LI/8BCoG6mOVoOMEXnloPwwBtOevoCB43U3sT9Er +WQWgZdbeI4gEyEqgMTibNogZZF0KW+5as3iv7avDd8pCgONvD0iwKSlvi9RNjiw8 +p6bwNmBcuA== +-----END CERTIFICATE----- diff --git a/rule-engine/rule-engine-components/src/test/resources/pem/rsa_encrypted_key.pem b/rule-engine/rule-engine-components/src/test/resources/pem/rsa_encrypted_key.pem new file mode 100644 index 0000000000..045a44ce28 --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/resources/pem/rsa_encrypted_key.pem @@ -0,0 +1,30 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQILTHGLs8mGUkCAggA +MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBAUnb+mChJ9Wu9F7q6ingLYBIIE +0Mwe8Zl6fs5kiT1AL7gXrSSXmyOVvxDFt0V3TX1w399VIadcUUO0RQeEqXoMEUzl +5at99Xmoo7ByvZSPWCdV4d/j5Yw+Z15euxzclSZJnmBgvQx8cFPLCTTaqlgv5r/Y +lTzBrczbgruMFKtzkvHgvZYiagccOtFHDNC1fUBcUR8dkOOsgTiy4QCVo5kkXHt/ +rblE/uVWI8/E318WZBZaz68HcmGIG6ivdMEsKskSKrH6zA3eLjyGB+zSAIPRB/Mp +s7Rj+RK74zFSYyaq6fgdTG8lug2f3rHImSOtQThcfme5XL4P66rUgJsh/sml1vqH +e848VArGoVy3wfvkss6CyXIJevhFh2xVWRyVqG1nraw2QssEnVqIZvdAnaJJONX8 +r1trjHkZ1JD0nO9Mns1c/bw6hjK6W3UwGfgEMM9VQ7wNI2B6CFOXHKTHg6r3us4k +UqaQtfbpTv+d0YKF/rolDcK+mK/rkxP3rtJA7Ud8nQ4VjxyYX4jTs3/BzDkP7Tsj +5gKy9e1zuTF+MUWs3G5oKGQUKVcbgoYJ+iOqgVSd1JbecRo7Pl8XgDv3I9RWHzUr +EAMjVJjRU9tJuPvILFBkpl1/OPC9sGxJz9Hy9qLtEGhGLUhNz6XmIy/aWPCyA4ea +ZES/n7f+aYmXIxulcxS7MUejkwl1EtNqVyrKvLiRBXjBk2HPCb7Te8fRu/LpHZXN +D7wjymg1fGZPPFzdKh7wMdAKiK50KIMGXTxS6kHb6qW/755oSUjWRLPGcPCfdbjn +UiC5WC9FCog6jfRq1rMlz5b8yjyb+UbJ6N4qFSHeQf+7WLeS0Di8k3cLDSWl6T7M +z82ePof2V2TrADNpXvAcR78uiDfUpfa7DhkimvbBZpRVaaQVU7unxUPVc93WgCWV +a7kBuFJAGt+Wt1LPPD/5KOQ5pRINSoh4VhiZzmnY/m7RDPWEaL5gsMjF5bFoP2UZ +MuyAiTmvO299lJDrdQyQds7yafO9PrTE4msuqpuZSHW7ZZIdRO6EXlfZ1We3icWr ++jE47bUIEl04k1PvXyv9LeoqlHZJTagxZIerMOEwq976MaVR7RJbqUpRUV9FFNCL +gTouPCwUcVtLCaTYQjz/+12/YeVkiBHIWkI8Vv5Mn3Vkwy303ygGCQ+brht1e8x+ +BbgzSpiX8aHiEuDAKooewxnKrf3Dk9BcwbnftxajOZcZ3iphk07t5VLRy86zLKCq +ZOY+KymcDCGaOPnSHFrZK3lZOOT+BB9Vi6EYAkxZCZgoDsb/voMEdpPlxK7ultf6 +is5/JQeQbeP9wbNh4Ru2x3p5Ir4wffhh1KT3UsMobusosTo55ErhMHPvH5amppwq +IrxdM7heo7JMaNKmtol4y45IqSt58iluF5m2Ds4m85xjDteRgEOjtNBStFxPCMAB +KUEzRxEaplAcJfzYzpYtoHZuZ8W3Gi7yeXQ+BV8Q9DeaZc5DDDhIcIkOoHOAKhit +d7Gpr8hpwc60AgHRjua8OdbhM4ntT1xnyDEqZbP8mN+UBAohOHMrqo+f4DL1ibB9 +qSwfdLiVItsEBqlfANV3i9rEeKNH5tOFwFCmmH1yBCSDCtWPmPUJ5tZae6fIetK5 +uSstFXLaDpm6fcHgkeqrnyteWpnk5X5SQQ+fMHPjQ2vp +-----END ENCRYPTED PRIVATE KEY----- diff --git a/rule-engine/rule-engine-components/src/test/resources/pem/rsa_encrypted_traditional_cert.pem b/rule-engine/rule-engine-components/src/test/resources/pem/rsa_encrypted_traditional_cert.pem new file mode 100644 index 0000000000..38ab2e42fe --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/resources/pem/rsa_encrypted_traditional_cert.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIUIo+5l07ZrQR/LxEEmUbnn4yxCwIwDQYJKoZIhvcNAQEL +BQAwWTELMAkGA1UEBhMCVUExDTALBgNVBAgMBEtZSVYxDTALBgNVBAcMBEtZSVYx +CzAJBgNVBAoMAlRCMQswCQYDVQQLDAJUQjESMBAGA1UEAwwJbG9jYWxob3N0MB4X +DTIzMTAxNjIxMDMxNVoXDTI0MTAxNTIxMDMxNVowWTELMAkGA1UEBhMCVUExDTAL +BgNVBAgMBEtZSVYxDTALBgNVBAcMBEtZSVYxCzAJBgNVBAoMAlRCMQswCQYDVQQL +DAJUQjESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEA87nLliszEWml8QvyAC+H80NZCxf4TcG826NBOp0AUPJ8xQBHCzc1 +t1ohVm2/fn2VJZAYXG2xSVcHyXjjjv3iGLE2AIDbXh06/yFg4TVjlbrWrAHFehyN +FwrK8ez36oGLa3ZVq+mx1fLfBQw5mStbh09NXmKTzqP6m9ggKtt63cUwoWdUTemT +qrjryJd69LiJi+MVqtbKO2j30/lgAZmaHtbojl9EcvWfeXLb20TnXRIctaIS1VGo +SluzjbNQErdN/VRW4RAOP6UFsK0xID2EuLODBmAWnI49fXO/OS+u3Kd3suABE0o9 +slfDXqNTp0r5N0OoSAFcc4EsV3+9Gf+mqwIDAQABo1MwUTAdBgNVHQ4EFgQUhS5K +XQDxGvaBCpKY1de+JZl8zjYwHwYDVR0jBBgwFoAUhS5KXQDxGvaBCpKY1de+JZl8 +zjYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAiUTgjnsVIg90 +Dm+XSlscIPbZEj/mJanoFFfAfbVJz1DadygG9viVUMf3jVQBcsJGeBDckR2b3OHY +82cQVpdu3Heqld+gnfsyi8QBi7EdK4i0q8NVqFgpw83KxNm9xt7xrgHtxhE0kWfW +dpTgeIu0hFf0qLUObw/g8+0awBuxNY2crLtLXQM/dRgtv5Zt/DilW3jMLAE5wke+ +/HM4/emOJO6DSI9BC8iUsmNpIpq45267jcjpczNBo3ap7Bad+jM/paRDng9Uavvr +VCsaJFaL5HG6TtNXN60npBouOWnivPzUeuTI4PnjGRgdp3lgb0IuXbuwxIW6FVG/ +73RHc0gGOA== +-----END CERTIFICATE----- diff --git a/rule-engine/rule-engine-components/src/test/resources/pem/rsa_encrypted_traditional_key.pem b/rule-engine/rule-engine-components/src/test/resources/pem/rsa_encrypted_traditional_key.pem new file mode 100644 index 0000000000..0b0e128a25 --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/resources/pem/rsa_encrypted_traditional_key.pem @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,FB5DE36A7A8B25DA + +skR15rUvZmdLzGqU5/BF4Yc3E6dxtXTvlOhuGnqH/idItMKUMWIIlQ7ZfWYF/CrC +CkeAUqhF4y+y+2eR4ejUzZKs6bYjTtkXAXAqQvCsTrTBdQSCcLwbHWLWMro0UG24 +e23Rx8kD0YC7VHqyr08NlLh94wR7kanhEeRUbmKBonZT/I9AZ5ntiBxq9QVBtc8M +f7LKIsnQDcd39cVXSo3LOJ/x7YVB//Ln1R1dexwxE0sXOyLq2hhrxzfHGuGXXW41 +/3+CeTgmX9Rzpawrq9vbVabPUgFcJlrogNRSnUAm9kz4b2zadCxEaCejVmhBy4wx +z2AJGcmE+D4VkQK1AAj5+AQQrPOIIFQnyGjwHkJSTGVTcKmttRYZBvUjdfQfj1fK +NsKOSZLzZGknM8Pz5MHgHqk70C7f+nm0uVhVuAiykA4PY4JdCAuTWJxMM2LWM3/q +rYCEMwxCGa6U92dakfC+W+d9pAbeN+xYOWkDrqG7BdAYg1P70cuMRPdd5bsq3YPp +G4n5NVyQvLlocGhZgC7NVzUtc18+rGblV4D657+GZwJnBZJN4TYey4+r2D5fv9rO +kcRVwfR704BbUBkjIzVzD7nXtBbr3ni8HSqde3g4aVL4WyV9XNvjUsYyrZ0u9Mt1 +IccAsa1xBquUNMxwO1H1mFLtzPKmFzKtlzqiiDsRQoRylwUa1k03sHKUflZRa8Sf +g4MpTRzK+vo1opMemlonty5YbvWXKlH68ioo49L8N457Y0hIUJOQgywg80NxT33t +x8y66lawd1Iv+Q7pptVxJtA4JmcdPvGwBLJZY4DacMyp/JqchAQfSQfmQ0tC+RfJ +z2By/s5wOEuVDksgp8RF1gn+VmvLyOoLK7tq+zpMO1mhfYTCMgSiz2GkNdiW6i25 +gjNWN/F62YL+9VJo4+olrcsYDFiiJq+deQk3H1tQJzu6qECfDqKDyw7IunvTwFil +5/d43LvLbRj75Kf/++xwTjfHudeTgw02/yPyELnURkUazvkOFsn7n8tU46Qm5TWh +fPFXSYxRf3m9rkKZB98YOJo595RuZyiYg9dEQX8Gybl1/7H7l4Cvw6yp71kgLrrI +JRYEt9pmWbQX97UFC3WTVMdKWakFziYVGPvFKkIzrHgcutbQVNsZ7GbO+rdWMIxr +SfUe6jCEclzGQjI9Ep4PTLjZvbusUMkoUjGasAluXFXDC4RKtpuXd4RmbOLdVuyN +OnZ5KZHFjrv4ch5PakRTViWFWSddV5CJ4fMkCG9qUHKrUWGjOvzu5rbcUzq3xJZG +9loIvlA4ekEAhQPHwx69uBmUwnCgyB9CosQGmUlwmC3KALA/EiXklTA6w0fGiiPk +uLA9oBGrVcD8Peug9Owfmj4fWbxJGP7x1UR/nZWpynIfzME0AD8MK5uqoWmQTG8I +cLSjVAB1CO//AZe4LpYQulMPq4dipmE+YnKLi0WPXuZVARDciAGGV2BfH6Iv8j9k +o9IoklcpGg22zXLoGn4tu+7Y5GcoV/mx68Gun1E/QFuY59damAqoc82EEsxr+UX0 +4vGX+KZn283xSYiilE3qpCZOER0ZUFInphUwJzzYfW3mW/AWR78tFQIQiuVKV2/a +-----END RSA PRIVATE KEY----- diff --git a/rule-engine/rule-engine-components/src/test/resources/pem/rsa_key.pem b/rule-engine/rule-engine-components/src/test/resources/pem/rsa_key.pem new file mode 100644 index 0000000000..8a92a68908 --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/resources/pem/rsa_key.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +wOqb/axEbvcj5sV6/4p2zz6AzFPEmQ== +-----END PRIVATE KEY-----