Skip to content

Commit b75b030

Browse files
authored
don't use endianness reverse util for writing KeyStore file (#78304)
The different endianness of different versions is handled when reading files.
1 parent 421b3e8 commit b75b030

File tree

4 files changed

+113
-59
lines changed

4 files changed

+113
-59
lines changed

distribution/tools/keystore-cli/src/test/java/org/elasticsearch/cli/keystore/KeyStoreWrapperTests.java

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
import org.apache.lucene.backward_codecs.store.EndiannessReverserUtil;
1212
import org.apache.lucene.codecs.CodecUtil;
13-
import org.apache.lucene.store.DataOutput;
1413
import org.apache.lucene.store.Directory;
1514
import org.apache.lucene.store.IOContext;
1615
import org.apache.lucene.store.IndexOutput;
@@ -204,9 +203,9 @@ public void testFailWhenCannotConsumeSecretStream() throws Exception {
204203
Path configDir = env.configFile();
205204
try (
206205
Directory directory = newFSDirectory(configDir);
207-
IndexOutput indexOutput = directory.createOutput("elasticsearch.keystore", IOContext.DEFAULT)
206+
IndexOutput indexOutput = EndiannessReverserUtil.createOutput(directory, "elasticsearch.keystore", IOContext.DEFAULT)
208207
) {
209-
CodecUtil.writeHeader(indexOutput, "elasticsearch.keystore", 3);
208+
CodecUtil.writeHeader(indexOutput, "elasticsearch.keystore", KeyStoreWrapper.V3_VERSION);
210209
indexOutput.writeByte((byte) 0); // No password
211210
SecureRandom random = Randomness.createSecure();
212211
byte[] salt = new byte[64];
@@ -235,19 +234,19 @@ public void testFailWhenCannotConsumeEncryptedBytesStream() throws Exception {
235234
Path configDir = env.configFile();
236235
try (
237236
Directory directory = newFSDirectory(configDir);
238-
IndexOutput indexOutput = directory.createOutput("elasticsearch.keystore", IOContext.DEFAULT)
237+
IndexOutput indexOutput = EndiannessReverserUtil.createOutput(directory, "elasticsearch.keystore", IOContext.DEFAULT)
239238
) {
240-
CodecUtil.writeHeader(indexOutput, "elasticsearch.keystore", 3);
239+
CodecUtil.writeHeader(indexOutput, "elasticsearch.keystore", KeyStoreWrapper.V3_VERSION);
241240
indexOutput.writeByte((byte) 0); // No password
242241
SecureRandom random = Randomness.createSecure();
243242
byte[] salt = new byte[64];
244243
random.nextBytes(salt);
245244
byte[] iv = new byte[12];
246245
random.nextBytes(iv);
246+
247247
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
248248
CipherOutputStream cipherStream = getCipherStream(bytes, salt, iv);
249249
DataOutputStream output = new DataOutputStream(cipherStream);
250-
251250
possiblyAlterSecretString(output, 0);
252251
cipherStream.close();
253252
final byte[] encryptedBytes = bytes.toByteArray();
@@ -259,17 +258,17 @@ public void testFailWhenCannotConsumeEncryptedBytesStream() throws Exception {
259258
KeyStoreWrapper keystore = KeyStoreWrapper.load(configDir);
260259
SecurityException e = expectThrows(SecurityException.class, () -> keystore.decrypt(new char[0]));
261260
assertThat(e.getMessage(), containsString("Keystore has been corrupted or tampered with"));
262-
assertThat(e.getCause(), instanceOf(EOFException.class));
261+
assertThat(e.getCause(), instanceOf(ArrayIndexOutOfBoundsException.class));
263262
}
264263

265264
public void testFailWhenSecretStreamNotConsumed() throws Exception {
266265
assumeFalse("Cannot open unprotected keystore on FIPS JVM", inFipsJvm());
267266
Path configDir = env.configFile();
268267
try (
269268
Directory directory = newFSDirectory(configDir);
270-
IndexOutput indexOutput = directory.createOutput("elasticsearch.keystore", IOContext.DEFAULT)
269+
IndexOutput indexOutput = EndiannessReverserUtil.createOutput(directory, "elasticsearch.keystore", IOContext.DEFAULT)
271270
) {
272-
CodecUtil.writeHeader(indexOutput, "elasticsearch.keystore", 3);
271+
CodecUtil.writeHeader(indexOutput, "elasticsearch.keystore", KeyStoreWrapper.V3_VERSION);
273272
indexOutput.writeByte((byte) 0); // No password
274273
SecureRandom random = Randomness.createSecure();
275274
byte[] salt = new byte[64];
@@ -297,9 +296,9 @@ public void testFailWhenEncryptedBytesStreamIsNotConsumed() throws Exception {
297296
Path configDir = env.configFile();
298297
try (
299298
Directory directory = newFSDirectory(configDir);
300-
IndexOutput indexOutput = directory.createOutput("elasticsearch.keystore", IOContext.DEFAULT)
299+
IndexOutput indexOutput = EndiannessReverserUtil.createOutput(directory, "elasticsearch.keystore", IOContext.DEFAULT)
301300
) {
302-
CodecUtil.writeHeader(indexOutput, "elasticsearch.keystore", 3);
301+
CodecUtil.writeHeader(indexOutput, "elasticsearch.keystore", KeyStoreWrapper.V3_VERSION);
303302
indexOutput.writeByte((byte) 0); // No password
304303
SecureRandom random = Randomness.createSecure();
305304
byte[] salt = new byte[64];
@@ -342,14 +341,8 @@ private void possiblyAlterSecretString(DataOutputStream output, int truncLength)
342341
output.write(secret_value);
343342
}
344343

345-
private void possiblyAlterEncryptedBytes(
346-
IndexOutput indexOutput,
347-
byte[] salt,
348-
byte[] iv,
349-
byte[] encryptedBytes,
350-
int truncEncryptedDataLength
351-
) throws Exception {
352-
DataOutput out = EndiannessReverserUtil.wrapDataOutput(indexOutput);
344+
private void possiblyAlterEncryptedBytes(IndexOutput out, byte[] salt, byte[] iv, byte[] encryptedBytes, int truncEncryptedDataLength)
345+
throws Exception {
353346
out.writeInt(4 + salt.length + 4 + iv.length + 4 + encryptedBytes.length);
354347
out.writeInt(salt.length);
355348
out.writeBytes(salt, salt.length);
@@ -424,7 +417,7 @@ public void testBackcompatV2() throws Exception {
424417
Directory directory = newFSDirectory(configDir);
425418
IndexOutput output = EndiannessReverserUtil.createOutput(directory, "elasticsearch.keystore", IOContext.DEFAULT);
426419
) {
427-
CodecUtil.writeHeader(output, "elasticsearch.keystore", 2);
420+
CodecUtil.writeHeader(output, "elasticsearch.keystore", KeyStoreWrapper.V2_VERSION);
428421
output.writeByte((byte) 0); // hasPassword = false
429422
output.writeString("PKCS12");
430423
output.writeString("PBE"); // string algo
@@ -474,6 +467,42 @@ public void testBackcompatV2() throws Exception {
474467
}
475468
}
476469

470+
public void testBackcompatV4() throws Exception {
471+
assumeFalse("Can't run in a FIPS JVM as PBE is not available", inFipsJvm());
472+
Path configDir = env.configFile();
473+
try (
474+
Directory directory = newFSDirectory(configDir);
475+
IndexOutput indexOutput = EndiannessReverserUtil.createOutput(directory, "elasticsearch.keystore", IOContext.DEFAULT)
476+
) {
477+
CodecUtil.writeHeader(indexOutput, "elasticsearch.keystore", KeyStoreWrapper.V4_VERSION);
478+
indexOutput.writeByte((byte) 0); // No password
479+
SecureRandom random = Randomness.createSecure();
480+
byte[] salt = new byte[64];
481+
random.nextBytes(salt);
482+
byte[] iv = new byte[12];
483+
random.nextBytes(iv);
484+
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
485+
CipherOutputStream cipherStream = getCipherStream(bytes, salt, iv);
486+
DataOutputStream output = new DataOutputStream(cipherStream);
487+
{
488+
byte[] secret_value = "super_secret_value".getBytes(StandardCharsets.UTF_8);
489+
output.writeInt(1); // One entry
490+
output.writeUTF("string_setting");
491+
output.writeInt(secret_value.length);
492+
output.write(secret_value);
493+
}
494+
cipherStream.close();
495+
final byte[] encryptedBytes = bytes.toByteArray();
496+
possiblyAlterEncryptedBytes(indexOutput, salt, iv, encryptedBytes, 0);
497+
CodecUtil.writeFooter(indexOutput);
498+
}
499+
500+
KeyStoreWrapper keystore = KeyStoreWrapper.load(configDir);
501+
keystore.decrypt(new char[0]);
502+
SecureString testValue = keystore.getString("string_setting");
503+
assertThat(testValue.toString(), equalTo("super_secret_value"));
504+
}
505+
477506
public void testStringAndFileDistinction() throws Exception {
478507
final char[] password = getPossibleKeystorePassword();
479508
final KeyStoreWrapper wrapper = KeyStoreWrapper.create();

distribution/tools/keystore-cli/src/test/java/org/elasticsearch/cli/keystore/UpgradeKeyStoreCommandTests.java

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,23 +38,28 @@ protected Environment createEnv(final Map<String, String> settings) {
3838
};
3939
}
4040

41-
public void testKeystoreUpgrade() throws Exception {
41+
public void testKeystoreUpgradeV3() throws Exception {
42+
assertKeystoreUpgrade("/format-v3-elasticsearch.keystore", KeyStoreWrapper.V3_VERSION);
43+
}
44+
45+
public void testKeystoreUpgradeV4() throws Exception {
46+
assertKeystoreUpgrade("/format-v4-elasticsearch.keystore", KeyStoreWrapper.V4_VERSION);
47+
}
48+
49+
private void assertKeystoreUpgrade(String file, int version) throws Exception {
4250
assumeFalse("Cannot open unprotected keystore on FIPS JVM", inFipsJvm());
4351
final Path keystore = KeyStoreWrapper.keystorePath(env.configFile());
44-
try (
45-
InputStream is = KeyStoreWrapperTests.class.getResourceAsStream("/format-v3-elasticsearch.keystore");
46-
OutputStream os = Files.newOutputStream(keystore)
47-
) {
52+
try (InputStream is = KeyStoreWrapperTests.class.getResourceAsStream(file); OutputStream os = Files.newOutputStream(keystore)) {
4853
is.transferTo(os);
4954
}
5055
try (KeyStoreWrapper beforeUpgrade = KeyStoreWrapper.load(env.configFile())) {
5156
assertNotNull(beforeUpgrade);
52-
assertThat(beforeUpgrade.getFormatVersion(), equalTo(3));
57+
assertThat(beforeUpgrade.getFormatVersion(), equalTo(version));
5358
}
5459
execute();
5560
try (KeyStoreWrapper afterUpgrade = KeyStoreWrapper.load(env.configFile())) {
5661
assertNotNull(afterUpgrade);
57-
assertThat(afterUpgrade.getFormatVersion(), equalTo(KeyStoreWrapper.FORMAT_VERSION));
62+
assertThat(afterUpgrade.getFormatVersion(), equalTo(KeyStoreWrapper.CURRENT_VERSION));
5863
afterUpgrade.decrypt(new char[0]);
5964
assertThat(afterUpgrade.getSettingNames(), hasItem(KeyStoreWrapper.SEED_SETTING.getKey()));
6065
}
Binary file not shown.

0 commit comments

Comments
 (0)