Handle UTF-8 values in the keystore (#39496)

* Handle UTF8 values in the keystore

Our current implementation uses CharBuffer#array to get the chars
that were decoded from the UTF-8 bytes. The backing array of
CharBuffer is created in CharsetDecoder#decode and gets an initial
length that is the same as the length of the ByteBuffer it decodes,
hence the number of UTF-8 bytes.
This works fine for the first 128 characters where each one needs
one bytes, but for the next UTF-8 characters (other latin alphabets
Greek, Cyrillic etc.) where we need 2 to 4 bytes per character, this
backing char array has a larger size than the number of the actual
chars this CharBuffer contains. Calling `array()` on it will return
a char array that can potentially have extra null chars so the
SecureString we get from the KeystoreWrapper, is not the same as the
one we entered.

This commit changes the behavior to use Arrays#copyOfRange to get
the necessary chars from the CharBuffer and adds a test with
random ( maybe not printable ) UTF-8 strings
This commit is contained in:
Ioannis Kakavas 2019-03-14 18:02:28 +02:00 committed by Ioannis Kakavas
parent e9fa7767ec
commit 8dc8fc507d
2 changed files with 15 additions and 1 deletions

View File

@ -532,7 +532,7 @@ public class KeyStoreWrapper implements SecureSettings {
}
ByteBuffer byteBuffer = ByteBuffer.wrap(entry.bytes);
CharBuffer charBuffer = StandardCharsets.UTF_8.decode(byteBuffer);
return new SecureString(charBuffer.array());
return new SecureString(Arrays.copyOfRange(charBuffer.array(), charBuffer.position(), charBuffer.limit()));
}
@Override

View File

@ -20,6 +20,7 @@
package org.elasticsearch.common.settings;
import java.io.ByteArrayInputStream;
import java.io.CharArrayWriter;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
@ -133,6 +134,19 @@ public class AddStringKeyStoreCommandTests extends KeyStoreCommandTestCase {
assertSecureString("foo", "secret value 2");
}
public void testAddUtf8String() throws Exception {
KeyStoreWrapper.create().save(env.configFile(), new char[0]);
final int stringSize = randomIntBetween(8, 16);
try (CharArrayWriter secretChars = new CharArrayWriter(stringSize)) {
for (int i = 0; i < stringSize; i++) {
secretChars.write((char) randomIntBetween(129, 2048));
}
setInput(secretChars.toString());
execute("-x", "foo");
assertSecureString("foo", secretChars.toString());
}
}
public void testMissingSettingName() throws Exception {
createKeystore("");
terminal.addTextInput("");