Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't use endianness reverse util for writing KeyStore file #78304

Merged
merged 1 commit into from
Sep 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

import org.apache.lucene.backward_codecs.store.EndiannessReverserUtil;
import org.apache.lucene.codecs.CodecUtil;
import org.apache.lucene.store.DataOutput;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.IOContext;
import org.apache.lucene.store.IndexOutput;
Expand Down Expand Up @@ -204,9 +203,9 @@ public void testFailWhenCannotConsumeSecretStream() throws Exception {
Path configDir = env.configFile();
try (
Directory directory = newFSDirectory(configDir);
IndexOutput indexOutput = directory.createOutput("elasticsearch.keystore", IOContext.DEFAULT)
IndexOutput indexOutput = EndiannessReverserUtil.createOutput(directory, "elasticsearch.keystore", IOContext.DEFAULT)
) {
CodecUtil.writeHeader(indexOutput, "elasticsearch.keystore", 3);
CodecUtil.writeHeader(indexOutput, "elasticsearch.keystore", KeyStoreWrapper.V3_VERSION);
indexOutput.writeByte((byte) 0); // No password
SecureRandom random = Randomness.createSecure();
byte[] salt = new byte[64];
Expand Down Expand Up @@ -235,19 +234,19 @@ public void testFailWhenCannotConsumeEncryptedBytesStream() throws Exception {
Path configDir = env.configFile();
try (
Directory directory = newFSDirectory(configDir);
IndexOutput indexOutput = directory.createOutput("elasticsearch.keystore", IOContext.DEFAULT)
IndexOutput indexOutput = EndiannessReverserUtil.createOutput(directory, "elasticsearch.keystore", IOContext.DEFAULT)
) {
CodecUtil.writeHeader(indexOutput, "elasticsearch.keystore", 3);
CodecUtil.writeHeader(indexOutput, "elasticsearch.keystore", KeyStoreWrapper.V3_VERSION);
indexOutput.writeByte((byte) 0); // No password
SecureRandom random = Randomness.createSecure();
byte[] salt = new byte[64];
random.nextBytes(salt);
byte[] iv = new byte[12];
random.nextBytes(iv);

ByteArrayOutputStream bytes = new ByteArrayOutputStream();
CipherOutputStream cipherStream = getCipherStream(bytes, salt, iv);
DataOutputStream output = new DataOutputStream(cipherStream);

possiblyAlterSecretString(output, 0);
cipherStream.close();
final byte[] encryptedBytes = bytes.toByteArray();
Expand All @@ -259,17 +258,17 @@ public void testFailWhenCannotConsumeEncryptedBytesStream() throws Exception {
KeyStoreWrapper keystore = KeyStoreWrapper.load(configDir);
SecurityException e = expectThrows(SecurityException.class, () -> keystore.decrypt(new char[0]));
assertThat(e.getMessage(), containsString("Keystore has been corrupted or tampered with"));
assertThat(e.getCause(), instanceOf(EOFException.class));
assertThat(e.getCause(), instanceOf(ArrayIndexOutOfBoundsException.class));
}

public void testFailWhenSecretStreamNotConsumed() throws Exception {
assumeFalse("Cannot open unprotected keystore on FIPS JVM", inFipsJvm());
Path configDir = env.configFile();
try (
Directory directory = newFSDirectory(configDir);
IndexOutput indexOutput = directory.createOutput("elasticsearch.keystore", IOContext.DEFAULT)
IndexOutput indexOutput = EndiannessReverserUtil.createOutput(directory, "elasticsearch.keystore", IOContext.DEFAULT)
) {
CodecUtil.writeHeader(indexOutput, "elasticsearch.keystore", 3);
CodecUtil.writeHeader(indexOutput, "elasticsearch.keystore", KeyStoreWrapper.V3_VERSION);
indexOutput.writeByte((byte) 0); // No password
SecureRandom random = Randomness.createSecure();
byte[] salt = new byte[64];
Expand Down Expand Up @@ -297,9 +296,9 @@ public void testFailWhenEncryptedBytesStreamIsNotConsumed() throws Exception {
Path configDir = env.configFile();
try (
Directory directory = newFSDirectory(configDir);
IndexOutput indexOutput = directory.createOutput("elasticsearch.keystore", IOContext.DEFAULT)
IndexOutput indexOutput = EndiannessReverserUtil.createOutput(directory, "elasticsearch.keystore", IOContext.DEFAULT)
) {
CodecUtil.writeHeader(indexOutput, "elasticsearch.keystore", 3);
CodecUtil.writeHeader(indexOutput, "elasticsearch.keystore", KeyStoreWrapper.V3_VERSION);
indexOutput.writeByte((byte) 0); // No password
SecureRandom random = Randomness.createSecure();
byte[] salt = new byte[64];
Expand Down Expand Up @@ -342,14 +341,8 @@ private void possiblyAlterSecretString(DataOutputStream output, int truncLength)
output.write(secret_value);
}

private void possiblyAlterEncryptedBytes(
IndexOutput indexOutput,
byte[] salt,
byte[] iv,
byte[] encryptedBytes,
int truncEncryptedDataLength
) throws Exception {
DataOutput out = EndiannessReverserUtil.wrapDataOutput(indexOutput);
private void possiblyAlterEncryptedBytes(IndexOutput out, byte[] salt, byte[] iv, byte[] encryptedBytes, int truncEncryptedDataLength)
throws Exception {
out.writeInt(4 + salt.length + 4 + iv.length + 4 + encryptedBytes.length);
out.writeInt(salt.length);
out.writeBytes(salt, salt.length);
Expand Down Expand Up @@ -424,7 +417,7 @@ public void testBackcompatV2() throws Exception {
Directory directory = newFSDirectory(configDir);
IndexOutput output = EndiannessReverserUtil.createOutput(directory, "elasticsearch.keystore", IOContext.DEFAULT);
) {
CodecUtil.writeHeader(output, "elasticsearch.keystore", 2);
CodecUtil.writeHeader(output, "elasticsearch.keystore", KeyStoreWrapper.V2_VERSION);
output.writeByte((byte) 0); // hasPassword = false
output.writeString("PKCS12");
output.writeString("PBE"); // string algo
Expand Down Expand Up @@ -474,6 +467,42 @@ public void testBackcompatV2() throws Exception {
}
}

public void testBackcompatV4() throws Exception {
assumeFalse("Can't run in a FIPS JVM as PBE is not available", inFipsJvm());
Path configDir = env.configFile();
try (
Directory directory = newFSDirectory(configDir);
IndexOutput indexOutput = EndiannessReverserUtil.createOutput(directory, "elasticsearch.keystore", IOContext.DEFAULT)
) {
CodecUtil.writeHeader(indexOutput, "elasticsearch.keystore", KeyStoreWrapper.V4_VERSION);
indexOutput.writeByte((byte) 0); // No password
SecureRandom random = Randomness.createSecure();
byte[] salt = new byte[64];
random.nextBytes(salt);
byte[] iv = new byte[12];
random.nextBytes(iv);
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
CipherOutputStream cipherStream = getCipherStream(bytes, salt, iv);
DataOutputStream output = new DataOutputStream(cipherStream);
{
byte[] secret_value = "super_secret_value".getBytes(StandardCharsets.UTF_8);
output.writeInt(1); // One entry
output.writeUTF("string_setting");
output.writeInt(secret_value.length);
output.write(secret_value);
}
cipherStream.close();
final byte[] encryptedBytes = bytes.toByteArray();
possiblyAlterEncryptedBytes(indexOutput, salt, iv, encryptedBytes, 0);
CodecUtil.writeFooter(indexOutput);
}

KeyStoreWrapper keystore = KeyStoreWrapper.load(configDir);
keystore.decrypt(new char[0]);
SecureString testValue = keystore.getString("string_setting");
assertThat(testValue.toString(), equalTo("super_secret_value"));
}

public void testStringAndFileDistinction() throws Exception {
final char[] password = getPossibleKeystorePassword();
final KeyStoreWrapper wrapper = KeyStoreWrapper.create();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,28 @@ protected Environment createEnv(final Map<String, String> settings) {
};
}

public void testKeystoreUpgrade() throws Exception {
public void testKeystoreUpgradeV3() throws Exception {
assertKeystoreUpgrade("/format-v3-elasticsearch.keystore", KeyStoreWrapper.V3_VERSION);
}

public void testKeystoreUpgradeV4() throws Exception {
assertKeystoreUpgrade("/format-v4-elasticsearch.keystore", KeyStoreWrapper.V4_VERSION);
}

private void assertKeystoreUpgrade(String file, int version) throws Exception {
assumeFalse("Cannot open unprotected keystore on FIPS JVM", inFipsJvm());
final Path keystore = KeyStoreWrapper.keystorePath(env.configFile());
try (
InputStream is = KeyStoreWrapperTests.class.getResourceAsStream("/format-v3-elasticsearch.keystore");
OutputStream os = Files.newOutputStream(keystore)
) {
try (InputStream is = KeyStoreWrapperTests.class.getResourceAsStream(file); OutputStream os = Files.newOutputStream(keystore)) {
is.transferTo(os);
}
try (KeyStoreWrapper beforeUpgrade = KeyStoreWrapper.load(env.configFile())) {
assertNotNull(beforeUpgrade);
assertThat(beforeUpgrade.getFormatVersion(), equalTo(3));
assertThat(beforeUpgrade.getFormatVersion(), equalTo(version));
}
execute();
try (KeyStoreWrapper afterUpgrade = KeyStoreWrapper.load(env.configFile())) {
assertNotNull(afterUpgrade);
assertThat(afterUpgrade.getFormatVersion(), equalTo(KeyStoreWrapper.FORMAT_VERSION));
assertThat(afterUpgrade.getFormatVersion(), equalTo(KeyStoreWrapper.CURRENT_VERSION));
afterUpgrade.decrypt(new char[0]);
assertThat(afterUpgrade.getSettingNames(), hasItem(KeyStoreWrapper.SEED_SETTING.getKey()));
}
Expand Down
Binary file not shown.
Loading