aboutsummaryrefslogtreecommitdiffstats
path: root/vespaclient-java/src/main/java/com/yahoo
diff options
context:
space:
mode:
Diffstat (limited to 'vespaclient-java/src/main/java/com/yahoo')
-rw-r--r--vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/DecryptTool.java49
-rw-r--r--vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/ResealTool.java55
2 files changed, 85 insertions, 19 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 4fbe89d4b03..4b3608fc3f7 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
@@ -2,14 +2,18 @@
package com.yahoo.vespa.security.tool.crypto;
import com.yahoo.security.SealedSharedKey;
+import com.yahoo.security.SecretSharedKey;
import com.yahoo.security.SharedKeyGenerator;
+import com.yahoo.security.SharedKeyResealingSession;
import com.yahoo.vespa.security.tool.CliUtils;
import com.yahoo.vespa.security.tool.Tool;
import com.yahoo.vespa.security.tool.ToolDescription;
import com.yahoo.vespa.security.tool.ToolInvocation;
import org.apache.commons.cli.Option;
+import java.io.BufferedReader;
import java.io.IOException;
+import java.io.InputStreamReader;
import java.util.List;
import java.util.Optional;
@@ -31,6 +35,7 @@ public class DecryptTool implements Tool {
static final String EXPECTED_KEY_ID_OPTION = "expected-key-id";
static final String ZSTD_DECOMPRESS_OPTION = "zstd-decompress";
static final String TOKEN_OPTION = "token";
+ static final String RESEAL_REQUEST = "reseal-request";
private static final List<Option> OPTIONS = List.of(
Option.builder("o")
@@ -77,6 +82,12 @@ public class DecryptTool implements Tool {
.hasArg(true)
.required(false)
.desc("Token generated when the input file was encrypted")
+ .build(),
+ Option.builder("r")
+ .longOpt(RESEAL_REQUEST)
+ .hasArg(false)
+ .required(false)
+ .desc("Delegate private key decryption via an interactive resealing session")
.build());
@Override
@@ -110,11 +121,12 @@ public class DecryptTool implements Tool {
var sealedSharedKey = SealedSharedKey.fromTokenString(tokenString.strip());
ToolUtils.verifyExpectedKeyId(sealedSharedKey, maybeKeyId);
- var privateKey = ToolUtils.resolvePrivateKeyFromInvocation(invocation, sealedSharedKey.keyId(),
- !CliUtils.useStdIo(inputArg) && !CliUtils.useStdIo(outputArg));
- var secretShared = SharedKeyGenerator.fromSealedKey(sealedSharedKey, privateKey);
- var cipher = secretShared.makeDecryptionCipher();
- boolean unZstd = arguments.hasOption(ZSTD_DECOMPRESS_OPTION);
+ var secret = arguments.hasOption(RESEAL_REQUEST)
+ ? secretFromInteractiveResealing(invocation, inputArg, outputArg, sealedSharedKey)
+ : secretFromPrivateKey(invocation, inputArg, outputArg, sealedSharedKey);
+
+ var cipher = secret.makeDecryptionCipher();
+ boolean unZstd = arguments.hasOption(ZSTD_DECOMPRESS_OPTION);
try (var inStream = CliUtils.inputStreamFromFileOrStream(inputArg, invocation.stdIn());
var outStream = CliUtils.outputStreamToFileOrStream(outputArg, invocation.stdOut())) {
@@ -125,4 +137,31 @@ public class DecryptTool implements Tool {
}
return 0;
}
+
+ private static SecretSharedKey secretFromPrivateKey(ToolInvocation invocation, String inputArg, String outputArg, SealedSharedKey sealedSharedKey) throws IOException {
+ var privateKey = ToolUtils.resolvePrivateKeyFromInvocation(invocation, sealedSharedKey.keyId(),
+ !CliUtils.useStdIo(inputArg) && !CliUtils.useStdIo(outputArg));
+ return SharedKeyGenerator.fromSealedKey(sealedSharedKey, privateKey);
+ }
+
+ private static SecretSharedKey secretFromInteractiveResealing(ToolInvocation invocation, String inputArg,
+ String outputArg, SealedSharedKey sealedSharedKey) throws IOException {
+ if (!CliUtils.useStdIo(outputArg) || !CliUtils.useStdIo(inputArg)) {
+ throw new IllegalArgumentException("Interactive token resealing not available with redirected I/O");
+ }
+ var session = SharedKeyResealingSession.newEphemeralSession();
+ var req = session.resealingRequestFor(sealedSharedKey);
+
+ invocation.stdOut().format("\nInteractive token resealing request:\n\n%s\n\n", req.toSerializedString());
+ invocation.stdOut().format("Paste response and hit return: ");
+
+ try (var reader = new BufferedReader(new InputStreamReader(invocation.stdIn()))) {
+ var serializedRes = reader.readLine().strip();
+ if (serializedRes.isEmpty()) {
+ throw new IllegalArgumentException("Empty response; aborting");
+ }
+ var res = SharedKeyResealingSession.ResealingResponse.fromSerializedString(serializedRes);
+ return session.openResealingResponse(res);
+ }
+ }
}
diff --git a/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/ResealTool.java b/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/ResealTool.java
index 19be3e9fa51..4fb8083b0f0 100644
--- a/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/ResealTool.java
+++ b/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/ResealTool.java
@@ -5,10 +5,12 @@ import com.yahoo.security.KeyId;
import com.yahoo.security.KeyUtils;
import com.yahoo.security.SealedSharedKey;
import com.yahoo.security.SharedKeyGenerator;
+import com.yahoo.security.SharedKeyResealingSession;
import com.yahoo.vespa.security.tool.CliUtils;
import com.yahoo.vespa.security.tool.Tool;
import com.yahoo.vespa.security.tool.ToolDescription;
import com.yahoo.vespa.security.tool.ToolInvocation;
+import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import java.io.IOException;
@@ -31,6 +33,7 @@ public class ResealTool implements Tool {
static final String EXPECTED_KEY_ID_OPTION = "expected-key-id";
static final String RECIPIENT_KEY_ID_OPTION = "key-id";
static final String RECIPIENT_PUBLIC_KEY_OPTION = "recipient-public-key";
+ static final String RESEAL_REQUEST_OPTION = "reseal-request";
private static final List<Option> OPTIONS = List.of(
Option.builder("k")
@@ -70,6 +73,12 @@ public class ResealTool implements Tool {
.hasArg(true)
.required(false)
.desc("ID of recipient key")
+ .build(),
+ Option.builder()
+ .longOpt(RESEAL_REQUEST_OPTION)
+ .hasArg(false)
+ .required(false)
+ .desc("Handle input as a resealing request instead of a token")
.build());
@Override
@@ -96,23 +105,41 @@ public class ResealTool implements Tool {
if (leftoverArgs.length != 1) {
throw new IllegalArgumentException("Expected exactly 1 token argument to re-seal");
}
- var tokenString = leftoverArgs[0];
- var maybeKeyId = Optional.ofNullable(arguments.hasOption(EXPECTED_KEY_ID_OPTION)
- ? arguments.getOptionValue(EXPECTED_KEY_ID_OPTION)
- : null);
- var sealedSharedKey = SealedSharedKey.fromTokenString(tokenString.strip());
- ToolUtils.verifyExpectedKeyId(sealedSharedKey, maybeKeyId);
-
- var recipientPubKey = KeyUtils.fromBase58EncodedX25519PublicKey(CliUtils.optionOrThrow(arguments, RECIPIENT_PUBLIC_KEY_OPTION).strip());
- var recipientKeyId = KeyId.ofString(CliUtils.optionOrThrow(arguments, RECIPIENT_KEY_ID_OPTION));
- var privateKey = ToolUtils.resolvePrivateKeyFromInvocation(invocation, sealedSharedKey.keyId(), true);
- var secretShared = SharedKeyGenerator.fromSealedKey(sealedSharedKey, privateKey);
- var resealedShared = SharedKeyGenerator.reseal(secretShared, recipientPubKey, recipientKeyId);
-
- invocation.stdOut().println(resealedShared.sealedSharedKey().toTokenString());
+ var inputArg = leftoverArgs[0].strip();
+ var maybeKeyId = Optional.ofNullable(arguments.hasOption(EXPECTED_KEY_ID_OPTION)
+ ? arguments.getOptionValue(EXPECTED_KEY_ID_OPTION)
+ : null);
+ if (arguments.hasOption(RESEAL_REQUEST_OPTION)) {
+ handleResealingRequest(invocation, inputArg, maybeKeyId);
+ } else {
+ handleTokenResealing(invocation, arguments, inputArg, maybeKeyId);
+ }
} catch (IOException e) {
throw new RuntimeException(e);
}
return 0;
}
+
+ private static void handleTokenResealing(ToolInvocation invocation, CommandLine arguments, String inputArg, Optional<String> maybeKeyId) throws IOException {
+ var sealedSharedKey = SealedSharedKey.fromTokenString(inputArg);
+ ToolUtils.verifyExpectedKeyId(sealedSharedKey, maybeKeyId);
+
+ var recipientPubKey = KeyUtils.fromBase58EncodedX25519PublicKey(CliUtils.optionOrThrow(arguments, RECIPIENT_PUBLIC_KEY_OPTION).strip());
+ var recipientKeyId = KeyId.ofString(CliUtils.optionOrThrow(arguments, RECIPIENT_KEY_ID_OPTION));
+ var privateKey = ToolUtils.resolvePrivateKeyFromInvocation(invocation, sealedSharedKey.keyId(), true);
+ var secretShared = SharedKeyGenerator.fromSealedKey(sealedSharedKey, privateKey);
+ var resealedShared = SharedKeyGenerator.reseal(secretShared, recipientPubKey, recipientKeyId);
+
+ invocation.stdOut().println(resealedShared.sealedSharedKey().toTokenString());
+ }
+
+ private static void handleResealingRequest(ToolInvocation invocation, String inputArg, Optional<String> maybeKeyId) throws IOException {
+ var request = SharedKeyResealingSession.ResealingRequest.fromSerializedString(inputArg);
+ ToolUtils.verifyExpectedKeyId(request.sealedKey(), maybeKeyId);
+
+ var privateKey = ToolUtils.resolvePrivateKeyFromInvocation(invocation, request.sealedKey().keyId(), true);
+ var resealed = SharedKeyResealingSession.reseal(request, (keyId) -> Optional.of(privateKey));
+
+ invocation.stdOut().println(resealed.toSerializedString());
+ }
}