aboutsummaryrefslogtreecommitdiffstats
path: root/vespaclient-java
diff options
context:
space:
mode:
authorTor Brede Vekterli <vekterli@yahooinc.com>2022-11-01 13:44:42 +0100
committerTor Brede Vekterli <vekterli@yahooinc.com>2022-11-01 14:43:54 +0100
commitf59b56ae4b8fafc67ec1828f03ce3178afaf037d (patch)
tree37be6e743672efbd4816ad39cb05ab46cad66e0a /vespaclient-java
parent43803ae25a68b4708f5846b7021e1dc3b68a82c6 (diff)
Let token key IDs be UTF-8 byte strings instead of just an integer
This makes key IDs vastly more expressive. Max size is 255 bytes, and UTF-8 form is enforced by checking that the byte sequence can be identity-transformed to and from a string with UTF-8 encoding. In addition, we now protect the integrity of the key ID by supplying it as the AAD parameter to the key sealing and opening operations. Reduce v1 token max length of `enc` part to 255, since this is always an X25519 public key, which is never bigger than 32 bytes (but may be _less_ if the random `BigInteger` is small enough, so we still have to encode the length).
Diffstat (limited to 'vespaclient-java')
-rw-r--r--vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/DecryptTool.java16
-rw-r--r--vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/EncryptTool.java4
-rw-r--r--vespaclient-java/src/test/java/com/yahoo/vespa/security/tool/CryptoToolsTest.java18
3 files changed, 23 insertions, 15 deletions
diff --git a/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/DecryptTool.java b/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/DecryptTool.java
index 23543486e1b..af59784bfe0 100644
--- a/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/DecryptTool.java
+++ b/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/DecryptTool.java
@@ -13,9 +13,12 @@ import org.apache.commons.cli.Option;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
+import java.util.Arrays;
import java.util.List;
import java.util.Optional;
+import static com.yahoo.security.ArrayUtils.toUtf8Bytes;
+
/**
* Tooling for decrypting a file using a private key that corresponds to the public key used
* to originally encrypt the file.
@@ -85,16 +88,19 @@ public class DecryptTool implements Tool {
}
var inputArg = leftoverArgs[0];
var maybeKeyId = Optional.ofNullable(arguments.hasOption(KEY_ID_OPTION)
- ? Integer.parseInt(arguments.getOptionValue(KEY_ID_OPTION))
+ ? arguments.getOptionValue(KEY_ID_OPTION)
: null);
var outputArg = CliUtils.optionOrThrow(arguments, OUTPUT_FILE_OPTION);
var privKeyPath = Paths.get(CliUtils.optionOrThrow(arguments, RECIPIENT_PRIVATE_KEY_FILE_OPTION));
var tokenString = CliUtils.optionOrThrow(arguments, TOKEN_OPTION);
var sealedSharedKey = SealedSharedKey.fromTokenString(tokenString.strip());
- if (maybeKeyId.isPresent() && (maybeKeyId.get() != sealedSharedKey.keyId())) {
- throw new IllegalArgumentException(("Key ID specified with --key-id (%d) does not match key ID " +
- "used when generating the supplied token (%d)")
- .formatted(maybeKeyId.get(), sealedSharedKey.keyId()));
+ if (maybeKeyId.isPresent()) {
+ byte[] myKeyIdBytes = toUtf8Bytes(maybeKeyId.get());
+ if (!Arrays.equals(myKeyIdBytes, sealedSharedKey.keyId())) {
+ // Don't include raw key bytes array verbatim in message (may contain control chars etc).
+ throw new IllegalArgumentException("Key ID specified with --key-id does not match key ID " +
+ "used when generating the supplied token");
+ }
}
var privateKey = KeyUtils.fromBase64EncodedX25519PrivateKey(Files.readString(privKeyPath).strip());
var secretShared = SharedKeyGenerator.fromSealedKey(sealedSharedKey, privateKey);
diff --git a/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/EncryptTool.java b/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/EncryptTool.java
index 5437e8cf9fe..cb16151c9b6 100644
--- a/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/EncryptTool.java
+++ b/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/EncryptTool.java
@@ -14,6 +14,8 @@ import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
+import static com.yahoo.security.ArrayUtils.toUtf8Bytes;
+
/**
* Tooling to encrypt a file using a public key, emitting a non-secret token that can be
* passed on to a recipient holding the corresponding private key.
@@ -77,7 +79,7 @@ public class EncryptTool implements Tool {
var outputPath = Paths.get(CliUtils.optionOrThrow(arguments, OUTPUT_FILE_OPTION));
var recipientPubKey = KeyUtils.fromBase64EncodedX25519PublicKey(CliUtils.optionOrThrow(arguments, RECIPIENT_PUBLIC_KEY_OPTION).strip());
- int keyId = Integer.parseInt(CliUtils.optionOrThrow(arguments, KEY_ID_OPTION));
+ var keyId = toUtf8Bytes(CliUtils.optionOrThrow(arguments, KEY_ID_OPTION));
var shared = SharedKeyGenerator.generateForReceiverPublicKey(recipientPubKey, keyId);
var cipher = SharedKeyGenerator.makeAesGcmEncryptionCipher(shared);
diff --git a/vespaclient-java/src/test/java/com/yahoo/vespa/security/tool/CryptoToolsTest.java b/vespaclient-java/src/test/java/com/yahoo/vespa/security/tool/CryptoToolsTest.java
index 55d0a10e660..a3651888441 100644
--- a/vespaclient-java/src/test/java/com/yahoo/vespa/security/tool/CryptoToolsTest.java
+++ b/vespaclient-java/src/test/java/com/yahoo/vespa/security/tool/CryptoToolsTest.java
@@ -144,10 +144,10 @@ public class CryptoToolsTest {
private static final String TEST_PRIV_KEY = "4qGcntygFn_a3uqeBa1PbDlygQ-cpOuNznTPIz9ftWE";
private static final String TEST_PUB_KEY = "ROAH_S862tNMpbJ49lu1dPXFCPHFIXZK30pSrMZEmEg";
- // Token created for the above public key (matching the above private key), using key id 1
- private static final String TEST_TOKEN = "AQAAAQAgwyxd7bFNQB_2LdL3bw-xFlvrxXhs7WWNVCKZ4" +
- "EFeNVtu42JMwM74bMN4E46v6mYcfQNPzcMGaP22Wl2cTnji0A";
- private static final int TEST_TOKEN_KEY_ID = 1;
+ // Token created for the above public key (matching the above private key), using key id "my key ID"
+ private static final String TEST_TOKEN = "AQlteSBrZXkgSUQgAtTxJJdmv3eUoW5Z3NJSdZ3poKPEkW0SJOG" +
+ "QXP6CaC5XfyAVoUlK_NyYIMsJKyNYKU6WmagZpVG2zQGFJoqiFA";
+ private static final String TEST_TOKEN_KEY_ID = "my key ID";
@Test
void encrypt_fails_with_error_message_if_no_input_file_is_given() throws IOException {
@@ -177,7 +177,7 @@ public class CryptoToolsTest {
"--output-file", "foo",
"--recipient-private-key-file", absPathOf(privKeyFile),
"--token", TEST_TOKEN,
- "--key-id", Integer.toString(TEST_TOKEN_KEY_ID)),
+ "--key-id", TEST_TOKEN_KEY_ID),
"Invalid command line arguments: Expected exactly 1 file argument to decrypt\n");
}
@@ -191,7 +191,7 @@ public class CryptoToolsTest {
"--output-file", "foo",
"--recipient-private-key-file", absPathOf(privKeyFile),
"--token", TEST_TOKEN,
- "--key-id", Integer.toString(TEST_TOKEN_KEY_ID)),
+ "--key-id", TEST_TOKEN_KEY_ID),
"Invalid command line arguments: Input file 'no-such-file' does not exist\n");
}
@@ -208,9 +208,9 @@ public class CryptoToolsTest {
"--output-file", "foo",
"--recipient-private-key-file", absPathOf(privKeyFile),
"--token", TEST_TOKEN,
- "--key-id", Integer.toString(TEST_TOKEN_KEY_ID + 1)),
- "Invalid command line arguments: Key ID specified with --key-id (2) does not match " +
- "key ID used when generating the supplied token (1)\n");
+ "--key-id", TEST_TOKEN_KEY_ID + "-wrong"),
+ "Invalid command line arguments: Key ID specified with --key-id does not " +
+ "match key ID used when generating the supplied token\n");
}
@Test