mirror of
https://github.com/elastic/elasticsearch.git
synced 2025-06-28 09:28:55 -04:00
Fix parsing of PBES2 encrypted PKCS#8 keys (#78904)
This commit adds support for decrypting PKCS#8 encoded private keys that have been encrypted using a PBES2 based scheme (AES only). Unfortunately `java.crypto.EncryptedPrivateKeyInfo` doesn't make this easy as the underlying encryption algorithm is hidden within the `AlgorithmParameters`, and can only be extracted by calling `toString()` on the parameters object. See: https://datatracker.ietf.org/doc/html/rfc8018#appendix-A.4 See: AlgorithmParameters#toString() See: com.sun.crypto.provider.PBES2Parameters#toString() Resolves: #78901, #32021
This commit is contained in:
parent
42fb4fb475
commit
7cc9edbf1b
8 changed files with 313 additions and 70 deletions
|
@ -36,21 +36,22 @@ public final class DerParser {
|
||||||
private static final int CONSTRUCTED = 0x20;
|
private static final int CONSTRUCTED = 0x20;
|
||||||
|
|
||||||
// Tag and data types
|
// Tag and data types
|
||||||
private static final int INTEGER = 0x02;
|
static final class Type {
|
||||||
private static final int OCTET_STRING = 0x04;
|
static final int INTEGER = 0x02;
|
||||||
private static final int OBJECT_OID = 0x06;
|
static final int OCTET_STRING = 0x04;
|
||||||
private static final int NUMERIC_STRING = 0x12;
|
static final int OBJECT_OID = 0x06;
|
||||||
private static final int PRINTABLE_STRING = 0x13;
|
static final int SEQUENCE = 0x10;
|
||||||
private static final int VIDEOTEX_STRING = 0x15;
|
static final int NUMERIC_STRING = 0x12;
|
||||||
private static final int IA5_STRING = 0x16;
|
static final int PRINTABLE_STRING = 0x13;
|
||||||
private static final int GRAPHIC_STRING = 0x19;
|
static final int VIDEOTEX_STRING = 0x15;
|
||||||
private static final int ISO646_STRING = 0x1A;
|
static final int IA5_STRING = 0x16;
|
||||||
private static final int GENERAL_STRING = 0x1B;
|
static final int GRAPHIC_STRING = 0x19;
|
||||||
|
static final int ISO646_STRING = 0x1A;
|
||||||
private static final int UTF8_STRING = 0x0C;
|
static final int GENERAL_STRING = 0x1B;
|
||||||
private static final int UNIVERSAL_STRING = 0x1C;
|
static final int UTF8_STRING = 0x0C;
|
||||||
private static final int BMP_STRING = 0x1E;
|
static final int UNIVERSAL_STRING = 0x1C;
|
||||||
|
static final int BMP_STRING = 0x1E;
|
||||||
|
}
|
||||||
|
|
||||||
private InputStream derInputStream;
|
private InputStream derInputStream;
|
||||||
private int maxAsnObjectLength;
|
private int maxAsnObjectLength;
|
||||||
|
@ -60,6 +61,22 @@ public final class DerParser {
|
||||||
this.maxAsnObjectLength = bytes.length;
|
this.maxAsnObjectLength = bytes.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read an object and verify its type
|
||||||
|
* @param requiredType The expected type code
|
||||||
|
* @throws IOException if data can not be parsed
|
||||||
|
* @throws IllegalStateException if the parsed object is of the wrong type
|
||||||
|
*/
|
||||||
|
public Asn1Object readAsn1Object(int requiredType) throws IOException {
|
||||||
|
final Asn1Object obj = readAsn1Object();
|
||||||
|
if (obj.type != requiredType) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Expected ASN.1 object of type 0x" + Integer.toHexString(requiredType) + " but was 0x" + Integer.toHexString(obj.type)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
public Asn1Object readAsn1Object() throws IOException {
|
public Asn1Object readAsn1Object() throws IOException {
|
||||||
int tag = derInputStream.read();
|
int tag = derInputStream.read();
|
||||||
if (tag == -1) {
|
if (tag == -1) {
|
||||||
|
@ -207,7 +224,7 @@ public final class DerParser {
|
||||||
* @return BigInteger
|
* @return BigInteger
|
||||||
*/
|
*/
|
||||||
public BigInteger getInteger() throws IOException {
|
public BigInteger getInteger() throws IOException {
|
||||||
if (type != DerParser.INTEGER)
|
if (type != Type.INTEGER)
|
||||||
throw new IOException("Invalid DER: object is not integer"); //$NON-NLS-1$
|
throw new IOException("Invalid DER: object is not integer"); //$NON-NLS-1$
|
||||||
|
|
||||||
return new BigInteger(value);
|
return new BigInteger(value);
|
||||||
|
@ -218,28 +235,28 @@ public final class DerParser {
|
||||||
String encoding;
|
String encoding;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case DerParser.OCTET_STRING:
|
case Type.OCTET_STRING:
|
||||||
// octet string is basically a byte array
|
// octet string is basically a byte array
|
||||||
return toHexString(value);
|
return toHexString(value);
|
||||||
case DerParser.NUMERIC_STRING:
|
case Type.NUMERIC_STRING:
|
||||||
case DerParser.PRINTABLE_STRING:
|
case Type.PRINTABLE_STRING:
|
||||||
case DerParser.VIDEOTEX_STRING:
|
case Type.VIDEOTEX_STRING:
|
||||||
case DerParser.IA5_STRING:
|
case Type.IA5_STRING:
|
||||||
case DerParser.GRAPHIC_STRING:
|
case Type.GRAPHIC_STRING:
|
||||||
case DerParser.ISO646_STRING:
|
case Type.ISO646_STRING:
|
||||||
case DerParser.GENERAL_STRING:
|
case Type.GENERAL_STRING:
|
||||||
encoding = "ISO-8859-1"; //$NON-NLS-1$
|
encoding = "ISO-8859-1"; //$NON-NLS-1$
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DerParser.BMP_STRING:
|
case Type.BMP_STRING:
|
||||||
encoding = "UTF-16BE"; //$NON-NLS-1$
|
encoding = "UTF-16BE"; //$NON-NLS-1$
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DerParser.UTF8_STRING:
|
case Type.UTF8_STRING:
|
||||||
encoding = "UTF-8"; //$NON-NLS-1$
|
encoding = "UTF-8"; //$NON-NLS-1$
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DerParser.UNIVERSAL_STRING:
|
case Type.UNIVERSAL_STRING:
|
||||||
throw new IOException("Invalid DER: can't handle UCS-4 string"); //$NON-NLS-1$
|
throw new IOException("Invalid DER: can't handle UCS-4 string"); //$NON-NLS-1$
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -251,7 +268,7 @@ public final class DerParser {
|
||||||
|
|
||||||
public String getOid() throws IOException {
|
public String getOid() throws IOException {
|
||||||
|
|
||||||
if (type != DerParser.OBJECT_OID) {
|
if (type != Type.OBJECT_OID) {
|
||||||
throw new IOException("Ivalid DER: object is not object OID");
|
throw new IOException("Ivalid DER: object is not object OID");
|
||||||
}
|
}
|
||||||
StringBuilder sb = new StringBuilder(64);
|
StringBuilder sb = new StringBuilder(64);
|
||||||
|
|
|
@ -25,6 +25,7 @@ import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.security.AccessControlException;
|
import java.security.AccessControlException;
|
||||||
|
import java.security.AlgorithmParameters;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.KeyFactory;
|
import java.security.KeyFactory;
|
||||||
import java.security.KeyPairGenerator;
|
import java.security.KeyPairGenerator;
|
||||||
|
@ -68,6 +69,9 @@ public final class PemUtils {
|
||||||
private static final String OPENSSL_EC_PARAMS_FOOTER = "-----END EC PARAMETERS-----";
|
private static final String OPENSSL_EC_PARAMS_FOOTER = "-----END EC PARAMETERS-----";
|
||||||
private static final String HEADER = "-----BEGIN";
|
private static final String HEADER = "-----BEGIN";
|
||||||
|
|
||||||
|
private static final String PBES2_OID = "1.2.840.113549.1.5.13";
|
||||||
|
private static final String AES_OID = "2.16.840.1.101.3.4.1";
|
||||||
|
|
||||||
private PemUtils() {
|
private PemUtils() {
|
||||||
throw new IllegalStateException("Utility class should not be instantiated");
|
throw new IllegalStateException("Utility class should not be instantiated");
|
||||||
}
|
}
|
||||||
|
@ -365,10 +369,14 @@ public final class PemUtils {
|
||||||
}
|
}
|
||||||
byte[] keyBytes = Base64.getDecoder().decode(sb.toString());
|
byte[] keyBytes = Base64.getDecoder().decode(sb.toString());
|
||||||
|
|
||||||
EncryptedPrivateKeyInfo encryptedPrivateKeyInfo = new EncryptedPrivateKeyInfo(keyBytes);
|
final EncryptedPrivateKeyInfo encryptedPrivateKeyInfo = getEncryptedPrivateKeyInfo(keyBytes);
|
||||||
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(encryptedPrivateKeyInfo.getAlgName());
|
String algorithm = encryptedPrivateKeyInfo.getAlgName();
|
||||||
|
if (algorithm.equals("PBES2") || algorithm.equals("1.2.840.113549.1.5.13")) {
|
||||||
|
algorithm = getPBES2Algorithm(encryptedPrivateKeyInfo);
|
||||||
|
}
|
||||||
|
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(algorithm);
|
||||||
SecretKey secretKey = secretKeyFactory.generateSecret(new PBEKeySpec(keyPassword));
|
SecretKey secretKey = secretKeyFactory.generateSecret(new PBEKeySpec(keyPassword));
|
||||||
Cipher cipher = Cipher.getInstance(encryptedPrivateKeyInfo.getAlgName());
|
Cipher cipher = Cipher.getInstance(algorithm);
|
||||||
cipher.init(Cipher.DECRYPT_MODE, secretKey, encryptedPrivateKeyInfo.getAlgParameters());
|
cipher.init(Cipher.DECRYPT_MODE, secretKey, encryptedPrivateKeyInfo.getAlgParameters());
|
||||||
PKCS8EncodedKeySpec keySpec = encryptedPrivateKeyInfo.getKeySpec(cipher);
|
PKCS8EncodedKeySpec keySpec = encryptedPrivateKeyInfo.getKeySpec(cipher);
|
||||||
String keyAlgo = getKeyAlgorithmIdentifier(keySpec.getEncoded());
|
String keyAlgo = getKeyAlgorithmIdentifier(keySpec.getEncoded());
|
||||||
|
@ -376,6 +384,55 @@ public final class PemUtils {
|
||||||
return keyFactory.generatePrivate(keySpec);
|
return keyFactory.generatePrivate(keySpec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static EncryptedPrivateKeyInfo getEncryptedPrivateKeyInfo(byte[] keyBytes) throws IOException, GeneralSecurityException {
|
||||||
|
try {
|
||||||
|
return new EncryptedPrivateKeyInfo(keyBytes);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// The Sun JCE provider can't handle non-AES PBES2 data (but it can handle PBES1 DES data - go figure)
|
||||||
|
// It's not worth our effort to try and decrypt it ourselves, but we can detect it and give a good error message
|
||||||
|
DerParser parser = new DerParser(keyBytes);
|
||||||
|
final DerParser.Asn1Object rootSeq = parser.readAsn1Object(DerParser.Type.SEQUENCE);
|
||||||
|
parser = rootSeq.getParser();
|
||||||
|
final DerParser.Asn1Object algSeq = parser.readAsn1Object(DerParser.Type.SEQUENCE);
|
||||||
|
parser = algSeq.getParser();
|
||||||
|
final String algId = parser.readAsn1Object(DerParser.Type.OBJECT_OID).getOid();
|
||||||
|
if (PBES2_OID.equals(algId)) {
|
||||||
|
final DerParser.Asn1Object algData = parser.readAsn1Object(DerParser.Type.SEQUENCE);
|
||||||
|
parser = algData.getParser();
|
||||||
|
final DerParser.Asn1Object ignoreKdf = parser.readAsn1Object(DerParser.Type.SEQUENCE);
|
||||||
|
final DerParser.Asn1Object cryptSeq = parser.readAsn1Object(DerParser.Type.SEQUENCE);
|
||||||
|
parser = cryptSeq.getParser();
|
||||||
|
final String encryptionId = parser.readAsn1Object(DerParser.Type.OBJECT_OID).getOid();
|
||||||
|
if (encryptionId.startsWith(AES_OID) == false) {
|
||||||
|
final String name = getAlgorithmNameFromOid(encryptionId);
|
||||||
|
throw new GeneralSecurityException(
|
||||||
|
"PKCS#8 Private Key is encrypted with unsupported PBES2 algorithm ["
|
||||||
|
+ encryptionId
|
||||||
|
+ "]"
|
||||||
|
+ (name == null ? "" : " (" + name + ")"),
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is horrible, but it's the only option other than to parse the encoded ASN.1 value ourselves
|
||||||
|
* @see AlgorithmParameters#toString() and com.sun.crypto.provider.PBES2Parameters#toString()
|
||||||
|
*/
|
||||||
|
private static String getPBES2Algorithm(EncryptedPrivateKeyInfo encryptedPrivateKeyInfo) {
|
||||||
|
final AlgorithmParameters algParameters = encryptedPrivateKeyInfo.getAlgParameters();
|
||||||
|
if (algParameters != null) {
|
||||||
|
return algParameters.toString();
|
||||||
|
} else {
|
||||||
|
// AlgorithmParameters can be null when running on BCFIPS.
|
||||||
|
// However, since BCFIPS doesn't support any PBE specs, nothing we do here would work, so we just do enough to avoid an NPE
|
||||||
|
return encryptedPrivateKeyInfo.getAlgName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decrypts the password protected contents using the algorithm and IV that is specified in the PEM Headers of the file
|
* Decrypts the password protected contents using the algorithm and IV that is specified in the PEM Headers of the file
|
||||||
*
|
*
|
||||||
|
@ -604,7 +661,7 @@ public final class PemUtils {
|
||||||
return "EC";
|
return "EC";
|
||||||
}
|
}
|
||||||
throw new GeneralSecurityException("Error parsing key algorithm identifier. Algorithm with OID [" + oidString +
|
throw new GeneralSecurityException("Error parsing key algorithm identifier. Algorithm with OID [" + oidString +
|
||||||
"] is not żsupported");
|
"] is not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Certificate> readCertificates(Collection<Path> certPaths) throws CertificateException, IOException {
|
public static List<Certificate> readCertificates(Collection<Path> certPaths) throws CertificateException, IOException {
|
||||||
|
@ -622,6 +679,56 @@ public final class PemUtils {
|
||||||
return certificates;
|
return certificates;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String getAlgorithmNameFromOid(String oidString) throws GeneralSecurityException {
|
||||||
|
switch (oidString) {
|
||||||
|
case "1.2.840.10040.4.1":
|
||||||
|
return "DSA";
|
||||||
|
case "1.2.840.113549.1.1.1":
|
||||||
|
return "RSA";
|
||||||
|
case "1.2.840.10045.2.1":
|
||||||
|
return "EC";
|
||||||
|
case "1.3.14.3.2.7":
|
||||||
|
return "DES-CBC";
|
||||||
|
case "2.16.840.1.101.3.4.1.1":
|
||||||
|
return "AES-128_ECB";
|
||||||
|
case "2.16.840.1.101.3.4.1.2":
|
||||||
|
return "AES-128_CBC";
|
||||||
|
case "2.16.840.1.101.3.4.1.3":
|
||||||
|
return "AES-128_OFB";
|
||||||
|
case "2.16.840.1.101.3.4.1.4":
|
||||||
|
return "AES-128_CFB";
|
||||||
|
case "2.16.840.1.101.3.4.1.6":
|
||||||
|
return "AES-128_GCM";
|
||||||
|
case "2.16.840.1.101.3.4.1.21":
|
||||||
|
return "AES-192_ECB";
|
||||||
|
case "2.16.840.1.101.3.4.1.22":
|
||||||
|
return "AES-192_CBC";
|
||||||
|
case "2.16.840.1.101.3.4.1.23":
|
||||||
|
return "AES-192_OFB";
|
||||||
|
case "2.16.840.1.101.3.4.1.24":
|
||||||
|
return "AES-192_CFB";
|
||||||
|
case "2.16.840.1.101.3.4.1.26":
|
||||||
|
return "AES-192_GCM";
|
||||||
|
case "2.16.840.1.101.3.4.1.41":
|
||||||
|
return "AES-256_ECB";
|
||||||
|
case "2.16.840.1.101.3.4.1.42":
|
||||||
|
return "AES-256_CBC";
|
||||||
|
case "2.16.840.1.101.3.4.1.43":
|
||||||
|
return "AES-256_OFB";
|
||||||
|
case "2.16.840.1.101.3.4.1.44":
|
||||||
|
return "AES-256_CFB";
|
||||||
|
case "2.16.840.1.101.3.4.1.46":
|
||||||
|
return "AES-256_GCM";
|
||||||
|
case "2.16.840.1.101.3.4.1.5":
|
||||||
|
return "AESWrap-128";
|
||||||
|
case "2.16.840.1.101.3.4.1.25":
|
||||||
|
return "AESWrap-192";
|
||||||
|
case "2.16.840.1.101.3.4.1.45":
|
||||||
|
return "AESWrap-256";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private static String getEcCurveNameFromOid(String oidString) throws GeneralSecurityException {
|
private static String getEcCurveNameFromOid(String oidString) throws GeneralSecurityException {
|
||||||
switch (oidString) {
|
switch (oidString) {
|
||||||
// see https://tools.ietf.org/html/rfc5480#section-2.1.1.1
|
// see https://tools.ietf.org/html/rfc5480#section-2.1.1.1
|
||||||
|
|
|
@ -15,6 +15,7 @@ import java.io.InputStream;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.security.AlgorithmParameters;
|
import java.security.AlgorithmParameters;
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.Key;
|
import java.security.Key;
|
||||||
import java.security.KeyStore;
|
import java.security.KeyStore;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
|
@ -26,6 +27,7 @@ import java.util.function.Supplier;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.hamcrest.Matchers.instanceOf;
|
import static org.hamcrest.Matchers.instanceOf;
|
||||||
import static org.hamcrest.Matchers.notNullValue;
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
|
import static org.hamcrest.Matchers.startsWith;
|
||||||
import static org.hamcrest.core.StringContains.containsString;
|
import static org.hamcrest.core.StringContains.containsString;
|
||||||
|
|
||||||
public class PemUtilsTests extends ESTestCase {
|
public class PemUtilsTests extends ESTestCase {
|
||||||
|
@ -79,17 +81,49 @@ public class PemUtilsTests extends ESTestCase {
|
||||||
assertThat(privateKey, equalTo(key));
|
assertThat(privateKey, equalTo(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testReadEncryptedPKCS8Key() throws Exception {
|
public void testReadEncryptedPKCS8PBES1Key() throws Exception {
|
||||||
assumeFalse("Can't run in a FIPS JVM, PBE KeySpec is not available", inFipsJvm());
|
assumeFalse("Can't run in a FIPS JVM, PBE KeySpec is not available", inFipsJvm());
|
||||||
Key key = getKeyFromKeystore("RSA");
|
Key key = getKeyFromKeystore("RSA");
|
||||||
assertThat(key, notNullValue());
|
assertThat(key, notNullValue());
|
||||||
assertThat(key, instanceOf(PrivateKey.class));
|
assertThat(key, instanceOf(PrivateKey.class));
|
||||||
PrivateKey privateKey = PemUtils.parsePrivateKey(getDataPath
|
PrivateKey privateKey = PemUtils.parsePrivateKey(
|
||||||
("/certs/pem-utils/key_pkcs8_encrypted.pem"), TESTNODE_PASSWORD);
|
getDataPath("/certs/pem-utils/key_pkcs8_encrypted_pbes1_des.pem"),
|
||||||
|
TESTNODE_PASSWORD
|
||||||
|
);
|
||||||
assertThat(privateKey, notNullValue());
|
assertThat(privateKey, notNullValue());
|
||||||
assertThat(privateKey, equalTo(key));
|
assertThat(privateKey, equalTo(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testReadEncryptedPKCS8PBES2AESKey() throws Exception {
|
||||||
|
assumeFalse("Can't run in a FIPS JVM, PBE KeySpec is not available", inFipsJvm());
|
||||||
|
Key key = getKeyFromKeystore("RSA");
|
||||||
|
assertThat(key, notNullValue());
|
||||||
|
assertThat(key, instanceOf(PrivateKey.class));
|
||||||
|
PrivateKey privateKey = PemUtils.parsePrivateKey(
|
||||||
|
getDataPath("/certs/pem-utils/key_pkcs8_encrypted_pbes2_aes.pem"),
|
||||||
|
TESTNODE_PASSWORD
|
||||||
|
);
|
||||||
|
assertThat(privateKey, notNullValue());
|
||||||
|
assertThat(privateKey, equalTo(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testReadEncryptedPKCS8PBES2DESKey() throws Exception {
|
||||||
|
assumeFalse("Can't run in a FIPS JVM, PBE KeySpec is not available", inFipsJvm());
|
||||||
|
|
||||||
|
// Sun JSE cannot read keys encrypted with PBES2 DES (but does support AES with PBES2 and DES with PBES1)
|
||||||
|
// Rather than add our own support for this we just detect that our error message is clear and meaningful
|
||||||
|
final GeneralSecurityException exception = expectThrows(
|
||||||
|
GeneralSecurityException.class,
|
||||||
|
() -> PemUtils.parsePrivateKey(getDataPath("/certs/pem-utils/key_pkcs8_encrypted_pbes2_des.pem"), TESTNODE_PASSWORD)
|
||||||
|
);
|
||||||
|
assertThat(
|
||||||
|
exception.getMessage(),
|
||||||
|
equalTo("PKCS#8 Private Key is encrypted with unsupported PBES2 algorithm [1.3.14.3.2.7] (DES-CBC)")
|
||||||
|
);
|
||||||
|
assertThat(exception.getCause(), instanceOf(IOException.class));
|
||||||
|
assertThat(exception.getCause().getMessage(), startsWith("PBE parameter parsing error"));
|
||||||
|
}
|
||||||
|
|
||||||
public void testReadDESEncryptedPKCS1Key() throws Exception {
|
public void testReadDESEncryptedPKCS1Key() throws Exception {
|
||||||
Key key = getKeyFromKeystore("RSA");
|
Key key = getKeyFromKeystore("RSA");
|
||||||
assertThat(key, notNullValue());
|
assertThat(key, notNullValue());
|
||||||
|
@ -134,8 +168,10 @@ public class PemUtilsTests extends ESTestCase {
|
||||||
Key key = getKeyFromKeystore("DSA");
|
Key key = getKeyFromKeystore("DSA");
|
||||||
assertThat(key, notNullValue());
|
assertThat(key, notNullValue());
|
||||||
assertThat(key, instanceOf(PrivateKey.class));
|
assertThat(key, instanceOf(PrivateKey.class));
|
||||||
PrivateKey privateKey = PemUtils.parsePrivateKey(getDataPath("/certs/pem-utils/dsa_key_openssl_plain_with_params.pem"),
|
PrivateKey privateKey = PemUtils.parsePrivateKey(
|
||||||
EMPTY_PASSWORD);
|
getDataPath("/certs/pem-utils/dsa_key_openssl_plain_with_params.pem"),
|
||||||
|
EMPTY_PASSWORD
|
||||||
|
);
|
||||||
|
|
||||||
assertThat(privateKey, notNullValue());
|
assertThat(privateKey, notNullValue());
|
||||||
assertThat(privateKey, equalTo(key));
|
assertThat(privateKey, equalTo(key));
|
||||||
|
@ -165,8 +201,10 @@ public class PemUtilsTests extends ESTestCase {
|
||||||
Key key = getKeyFromKeystore("EC");
|
Key key = getKeyFromKeystore("EC");
|
||||||
assertThat(key, notNullValue());
|
assertThat(key, notNullValue());
|
||||||
assertThat(key, instanceOf(PrivateKey.class));
|
assertThat(key, instanceOf(PrivateKey.class));
|
||||||
PrivateKey privateKey = PemUtils.parsePrivateKey(getDataPath("/certs/pem-utils/ec_key_openssl_plain_with_params.pem"),
|
PrivateKey privateKey = PemUtils.parsePrivateKey(
|
||||||
EMPTY_PASSWORD);
|
getDataPath("/certs/pem-utils/ec_key_openssl_plain_with_params.pem"),
|
||||||
|
EMPTY_PASSWORD
|
||||||
|
);
|
||||||
|
|
||||||
assertThat(privateKey, notNullValue());
|
assertThat(privateKey, notNullValue());
|
||||||
assertThat(privateKey, equalTo(key));
|
assertThat(privateKey, equalTo(key));
|
||||||
|
|
|
@ -101,12 +101,34 @@ openssl pkcs12 -in ec.p12 -nodes -nocerts | openssl pkcs8 -topk8 -nocrypt -outfo
|
||||||
----
|
----
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Create `PKCS#8` encrypted key from the encrypted `PKCS#1` encoded `testnode.pem`
|
Create `PKCS#8` encrypted key from the encrypted `PKCS#1` encoded `testnode.pem`
|
||||||
|
The `-v1 PBE-MD5-DES` parameter forces pbeWithMD5AndDES-CBC as the encryption scheme (which is also the default, but that could change with diffent OpenSSL versions)
|
||||||
|
See: http://oid-info.com/get/1.2.840.113549.1.5.3
|
||||||
|
See: https://datatracker.ietf.org/doc/html/rfc8018#appendix-A.3
|
||||||
[source,shell]
|
[source,shell]
|
||||||
-----
|
-----
|
||||||
openssl pkcs8 -topk8 -inform PEM -outform PEM -in testnode.pem -out key_pkcs8_encrypted.pem
|
openssl pkcs8 -topk8 -v1 PBE-MD5-DES -inform PEM -outform PEM -in testnode.pem -passin "pass:testnode" -out key_pkcs8_encrypted_pbes1_des.pem -passout "pass:testnode"
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
Create `PKCS#8` `PBES2` `AES` encrypted key from the encrypted `PKCS#1` encoded `testnode.pem`
|
||||||
|
The `-v2 aes256` parameter forces PBES2 with AES256
|
||||||
|
See: http://oid-info.com/get/1.2.840.113549.1.5.13
|
||||||
|
See: https://datatracker.ietf.org/doc/html/rfc8018#appendix-A.4
|
||||||
|
[source,shell]
|
||||||
|
-----
|
||||||
|
openssl pkcs8 -topk8 -v2 aes256 -inform PEM -outform PEM -in testnode.pem -passin "pass:testnode" -out key_pkcs8_encrypted_pbes2_aes.pem -passout "pass:testnode"
|
||||||
|
-----
|
||||||
|
|
||||||
|
Create `PKCS#8` `PBES2` `DES` encrypted key from the encrypted `PKCS#1` encoded `testnode.pem`
|
||||||
|
The `-v2 des` parameter forces PBES2 with DES
|
||||||
|
See: http://oid-info.com/get/1.2.840.113549.1.5.13
|
||||||
|
See: https://datatracker.ietf.org/doc/html/rfc8018#appendix-A.4
|
||||||
|
[source,shell]
|
||||||
|
-----
|
||||||
|
openssl pkcs8 -topk8 -v2 des -inform PEM -outform PEM -in testnode.pem -passin "pass:testnode" -out key_pkcs8_encrypted_pbes2_des.pem -passout "pass:testnode"
|
||||||
|
-----
|
||||||
|
|
||||||
|
|
||||||
[source,shell]
|
[source,shell]
|
||||||
-----
|
-----
|
||||||
ssh-keygen -t ed25519 -f key_unsupported.pem
|
ssh-keygen -t ed25519 -f key_unsupported.pem
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
|
||||||
MIIE6TAbBgkqhkiG9w0BBQMwDgQI2jwlFL0XId0CAggABIIEyMujZbpG6zKb2pVu
|
|
||||||
soamTaoLcZwNofS9ncGIEH1nbI8UpPY81VeOIBm4mneDt8RU5bIOXP4IZEZY9uU+
|
|
||||||
pugKQ3hT8vBQjJujjuctUPaFxB0kGEeITOInY2jn2BFDbUgy5Z7EVD4G2K06SDDK
|
|
||||||
oD+twbzZo9x34VizwpHHb8wE+DFyYc+sp+Re2Qk3FReKgjdJezfcRHbKrrlx2rJ+
|
|
||||||
k/YAPmzcFYVbuUiB6HY6BGzSJO1JxT8iNJE+Hmk3ZLXG590hp0vuGSkY/ihbeix4
|
|
||||||
1rQs7u4riqXJ+DJBmXt/wXUij0/k6s4igACNsT2MkZkGEDkzqzE+kj2VYOHSX+Wd
|
|
||||||
5W0WCfftcsIQ8eow4ACec/Ns9ionLjx1xnbTjRMkpGgbVsreupU9AQ4MhLNNgwyl
|
|
||||||
six/cxUxTvH8Modd0/4KQFkeo352A6+DKCaPZ87SoF2Rge1otcJaZVcX1gBvIztB
|
|
||||||
/xzYwyUydQEwblU0kCYWRgxlKP9jxFoke2RX1BodRfAMNDxS0XyYrA/JzB7ZRsS7
|
|
||||||
QGYPy/PPb014U3KhpJdjwbNu2VaCVdGryYA9+BTP+Vzwcp8MZoMPnnjnBh1YyVAj
|
|
||||||
c7oyzKU5e5SVsYni1Kt/536YxQgFCAUHv/g+zQqqGEvyiMXhsCwVpoy7UcFYgmlw
|
|
||||||
40g3+ejwvlO3YA67gQQKebEv6/Laz1hVNiXT0m3okAXWxXgF/g2eBO5NTRdtaWn3
|
|
||||||
VNH5ub+LOr6cMhk9BAtKgRG+xeh8/2SqH12UbwtlmxqnBAfHtqlE6yJ1ViMDHxF9
|
|
||||||
101xJlEONmC3fcEAjShK6LEbFwPJns3WbGc0ds36CzXWtO29XGssr+YoiF9e3Eus
|
|
||||||
/XQjmjOJxRoWkNEYsxlJ3IRH2vUcdCoAp8IlD7JYxx8UBCSJDBo7/0QKU6INeWjo
|
|
||||||
5+aNbaLAJULSKo1LTZjjANm+G+KcSnbn5Ed8fmY+D61A5/7WMIVxq/uDLFvxCnRG
|
|
||||||
QcLbtqbPztiWwWZOuTwNTA3bfAhEG0ZzNr+0z33jW5T9ChvdutgxJMf3Khazx9cx
|
|
||||||
mWyCpJwtSv7hSbp4nCS2fmHCum2yIrOnou8TSOlQFERZ3UEZMgLpWeupH/W5C3Ad
|
|
||||||
rOspFrK6K8a/iNSs5OdYUIK2iHddTs5u7AEZ9I5MTuYnccuGuXfQTTA06TJvJTax
|
|
||||||
c2oDbXMnXs4pHLiiSRp34IHIYubdrj8X5vTODC5djl8h1167ToXo5zGdXqT1om+u
|
|
||||||
4ndNLbbI1vld5G7KAL6TlTETg+N7S8v3KYoBEWzykwgqqppWnWTqPWQxM8Iph5ly
|
|
||||||
AQlzz7feERi/h/s57RZ5ksoVAdbtk2U6wgHnLrWhKZ7+ZOAfpNAjGHwWyXTzylXo
|
|
||||||
zQ9A8Kmd0jBMsru4fsGpldf4lTsqO/abUSWrAAREGnlz/ZjEb944Yox7JUhWC15C
|
|
||||||
WxXK2rFbiF3S0HtEvU17rdn4HCsZBilnY+hTpHj1MA6O451/A3ghxGXFKz/9LUcS
|
|
||||||
YBRQJaSM3hTqC3WoTVBeVc5nCFOpu4F89JqhEgXOLKweueMbTMRSNm93tXWT13s3
|
|
||||||
Q/o0pNJv/K6+bIQwsX/oDafMXcW7STxQJObbAleRbcn8/rGS2eEnVZ6907faUR/L
|
|
||||||
7eu9vgAa/jh9FHpZ0Q==
|
|
||||||
-----END ENCRYPTED PRIVATE KEY-----
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||||
|
MIIE6TAbBgkqhkiG9w0BBQMwDgQIzMStkKSpOt0CAggABIIEyNdtzS+2uzAtCF35
|
||||||
|
SEDSWBbtxkUAyQHxEjMxkzH8xE/60slG4yE3oPomRoE4hXOs1EUzwvKOJ7ykPXzc
|
||||||
|
zBuRTFns/b/A2ycfUOyTyblH0y2rXVcSN7Q/qVktcOoeg6mIuGHfXyJA4J9/neyy
|
||||||
|
SVGFNEWSa3kS6VtbS330deCrM6XXZmhusHMWmdmH+8jjEFrRksl/53P64VXO/THs
|
||||||
|
RtvtVJ8kGb49e38diMLuEpWbB9Pd1Nkqa4rgpcoYv2AuXXkBkDvs2iTsiSpCRuuQ
|
||||||
|
WpsKTNijVzv59LjLKki6JH7NxUef0C+MiYq+4Okbxk9apJXd5HsOEtGbVfTEOojT
|
||||||
|
bW03BHX4q/6BocdQLzMKILjkBs9XGIckRSFVId/+a1shAtAHISdIy0jq6tTCpScM
|
||||||
|
JIv8h3GhopF0EeVcij2KAEHTG3ky7RqpLZ6gTEUHDNhiNTZlMVNYo6vFk6agDzUx
|
||||||
|
Oh59UciG1t+LewpoLQy6n7PGcwoE9mTxXCWQt15RKVK+LKsWgShI4uBDhg4GMQfy
|
||||||
|
9CQT0YMXBpJQXPtf2cnpTCBFJptp1JtapnKBiHJzPmNPa0NK55dXPL6v89fFrCKp
|
||||||
|
3wurCYdNmLrS/qlhjva3/TXCfTZNQmCfl9DK+5q7nG1HTZYDfyPoAppITKbrUV9J
|
||||||
|
BSlFbBeIxqoN7bOpVhBXWYTSJBBokJED4mjwtFFMI5XE/4VTsqZ83ASjfv13xAsA
|
||||||
|
AJ+2kfjzFL2DXSXGiiPzipCeaZHFayJp6v5+81+76bXBwvrTLJ+/vvzXSOCBma2y
|
||||||
|
51qDxMhBwNewUdWsGUorcQ2lQzeRdeyFjeLNMgm3p8BXvTweae+raT9AJbtA1PvL
|
||||||
|
j7k312+DvFqg5VZkwM03kvTJeR2YBMQZub0e5biqIe8l8308Q8pZo9HTN4exGDfm
|
||||||
|
R67yLryCUPHcDfVdZoKmYeDv5h6e0cvnu3b+6ML2SVfMJ+yFqJFcWjQsr8furG0I
|
||||||
|
+3bACz9ykf5TcjjUV4ewQQp0uC0ryFBXxho1g3V4hJf86luEIqayoPLXkOCEhcy1
|
||||||
|
oyY6h6tKXSlcYUHJagGqMyucRrs/mGcx4/YURyfxVNWQkCcUqA//+fEhWOBzFMiY
|
||||||
|
vkVWERW8KjlUtI+/kylUsgiJAIJpNJPXnltRDhdE/OT8kcxGYtl+CEIl/VN0N5nW
|
||||||
|
dNNoFN4E+zeR/KrEjhnRby/MpXHtNHVNVJbXARAkHsfCtWQ148ewuOx4IPMMiQ/C
|
||||||
|
z0DVv5GDP9+ObdW6kge/t9+fexcMH/DzfLDqO/qmP5xni4xP0JYU6wkzZ6k/F/Bz
|
||||||
|
s80PwJ/Y7LmT+1srqASm/Fetidb/shVh4VqKa5H8dYhnXfWKHghVR590qahAZtsm
|
||||||
|
1M7iqyYRW1nIplqtCPFCHSm/KDRb4Qwe/U+wjB5cYDFRfpoiZgfL+s7CWM0NU2Yp
|
||||||
|
RDW7ozCjf+w6XoCdlVZI2JppJA+zGWtUzznaTIe2RL9ioVxsREbnL/I+n0tzuLP3
|
||||||
|
vqeyT4EfEGbcooEIPgJsARp0w20PqpqTgCMc42n4QWi6QDwdgAEP3Lob9mbYSrvp
|
||||||
|
OQWE3MxFEVfAyuaoBYJgP+aDY+UU55VwAfZeiW1+jfsvq7Uqcd9gVxwJdVA2zdlH
|
||||||
|
LXxWg4lHo5gLDVXHtQ==
|
||||||
|
-----END ENCRYPTED PRIVATE KEY-----
|
|
@ -0,0 +1,30 @@
|
||||||
|
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||||
|
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
|
||||||
|
JhwAbR1VXQOHLlzJ5xqroNvDuw==
|
||||||
|
-----END ENCRYPTED PRIVATE KEY-----
|
|
@ -0,0 +1,29 @@
|
||||||
|
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||||
|
MIIFCzA9BgkqhkiG9w0BBQ0wMDAbBgkqhkiG9w0BBQwwDgQISYrz2l4tmYACAggA
|
||||||
|
MBEGBSsOAwIHBAgqwuBynTK44ASCBMir0L/8IbtAjZCpBkHJ8ytKSP2KEivv+PsW
|
||||||
|
Xe+kwmKIIbvTgiVM7LVppTSpb6B0So0vOirm0asbKmEBj/KKmnzkbTRx/nbkPQGc
|
||||||
|
TnI1bseqo8JgjH8TglA3ozkpwNFZf4CMx8oV6yXvl66eKn6BMFbdLgVorqROhm6a
|
||||||
|
ONo2YbfvBZFHapwkBfS62nOAHs8KIqGQEwANimAwMQYpEHPTuDOpHGnNMM4AY2bu
|
||||||
|
84RqWfhMXgJtwJxjHCtSYCx05cNDpfiXjjKhr9YJwf+8fjooSmMPdZba2TeGiUWn
|
||||||
|
tUi4BL/fljk28gRUhLgcktmyoF+l2eYXNmdgJob6wKJSOhbONqxiGIGpiB527h8B
|
||||||
|
IF3unyJq/rZ44Af73i6GtNxZo5I+rXPa9uC0+159zhdGkToSLIlwUnQ9xTzgxNuc
|
||||||
|
gQhMKBlJoK1vOalfWtUHz+27JMmMYIzfdLdBA4mYb4YTwjebB7KIwEPJO6ufIXq/
|
||||||
|
4t+TIbSSqCxkrqMIdBslB6ciOcYomLg6vK0xVnVgJA+XhzAgVmohuBZUmpSGbplE
|
||||||
|
2JXx2pKAjdiZ2X0xTJ3zbybNC3GdsbUskd4kUciJfSqSXLsm7crgJdSc1REhEI+k
|
||||||
|
mIpBU9yaEFN8S43TcQI6eB5rOVW0Tm8cPkH86S/XP1zYlgNh1zkqcO7Z0lYMTqur
|
||||||
|
3KEm2zqMUMwsOiRtwFXNirC7St73GTMFzmtdgLGywzxPas0gksSqOt1v/Gq9G7FQ
|
||||||
|
QJK4T3sOJeSMSIYzt/GIdB+Ha4wzKhaSWqdZnmskhTiXgIeLu0BRXgdY3lhg5Q+2
|
||||||
|
xtR0TLVt26d+N03kj5HZ4Jl+DNWM3JY01ycZ/lk/CHERfpRLRGXXhXt01UloNNL2
|
||||||
|
KmPdfbJhaCmsYnIXs02fHC6UdD5kXDRCNx9U4W9F0BAHU9brNNowtOgl4FzlTXYD
|
||||||
|
UEZk1zBPojOBfegaUiwOs60u8SMdHjgpz3AcG5YWp3idiLo9VhizYCDgv8XurSZD
|
||||||
|
KH+bCNgE9VMhsLZkyoOtZ5EmVTf2ZmTOIaTU2ddakhfLsAXQt30rAAU2DYAreDT0
|
||||||
|
G2ZotpdxfIh98J0kVLrPKcOKxfshH55N6EWJK0YaXgvllBSzvR/l7EJU33A/FMPZ
|
||||||
|
bXWHfeRsyApXsefroMfqAuuyFAUYKFt7dPAyNpbmPw3hS9ZcKn7GSGrMKRisDuDM
|
||||||
|
bdrI2hCV/ylYIWUkj2GA/B1NGZ+iuYUKzlB37cjDeoqZhmVAY5Ns+U3+7FMAedGn
|
||||||
|
UmvM0U+nYWLx78EvzhxUZeSAgmct8NFlPLaxp964zogoMZq5Ah7RQ7fl5nr+NSBj
|
||||||
|
lPTcajhFBkwm1yEFpxzpL2LtMPEDbbInlEhKx+OEtxLTL3rlV0aZoRy4TYaToZvA
|
||||||
|
AukDSMg89XAKTSP/CtiKzO7b+iXficoFKSrUHLtyBqd5Wdv79SMfK8Jq0S9Tn5Nl
|
||||||
|
J4tI92uy/LIbR+MjWm8ViiCiRDThqGtbE+RHLY2JNsB7pSV0JLn13n1OQXi4SxF5
|
||||||
|
s92J7C4fHX3pxziUNdMxYvXk6KYQrSBZe/Mrr0444Pmo94Sz1gwbRI4p+7r/A3h4
|
||||||
|
5iVFoKf75q/fxww76gS0jMAoAnSEtYikKe/3c3PQWzdyh+uN/KqaliycRvyGf9s=
|
||||||
|
-----END ENCRYPTED PRIVATE KEY-----
|
Loading…
Add table
Add a link
Reference in a new issue