From 4a405f6d394d95a5b343b5e42fc00334d0fceef3 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Wed, 15 Nov 2023 17:22:07 +0100 Subject: [PATCH] Kotlin conversion: DetachedVerifyExternal --- .../operation/DetachedVerifyExternal.java | 117 ------------------ .../operation/DetachedVerifyExternal.kt | 90 ++++++++++++++ 2 files changed, 90 insertions(+), 117 deletions(-) delete mode 100644 external-sop/src/main/java/sop/external/operation/DetachedVerifyExternal.java create mode 100644 external-sop/src/main/kotlin/sop/external/operation/DetachedVerifyExternal.kt diff --git a/external-sop/src/main/java/sop/external/operation/DetachedVerifyExternal.java b/external-sop/src/main/java/sop/external/operation/DetachedVerifyExternal.java deleted file mode 100644 index 866150d..0000000 --- a/external-sop/src/main/java/sop/external/operation/DetachedVerifyExternal.java +++ /dev/null @@ -1,117 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -package sop.external.operation; - -import sop.Verification; -import sop.exception.SOPGPException; -import sop.external.ExternalSOP; -import sop.operation.DetachedVerify; -import sop.operation.VerifySignatures; -import sop.util.UTCUtil; - -import javax.annotation.Nonnull; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashSet; -import java.util.List; -import java.util.Properties; -import java.util.Set; - -/** - * Implementation of the {@link DetachedVerify} operation using an external SOP binary. - */ -public class DetachedVerifyExternal implements DetachedVerify { - - private final List commandList = new ArrayList<>(); - private final List envList; - - private final Set certs = new HashSet<>(); - private InputStream signatures; - private int certCounter = 0; - - public DetachedVerifyExternal(String binary, Properties environment) { - commandList.add(binary); - commandList.add("verify"); - envList = ExternalSOP.propertiesToEnv(environment); - } - - @Override - @Nonnull - public DetachedVerify notBefore(@Nonnull Date timestamp) throws SOPGPException.UnsupportedOption { - commandList.add("--not-before=" + UTCUtil.formatUTCDate(timestamp)); - return this; - } - - @Override - @Nonnull - public DetachedVerify notAfter(@Nonnull Date timestamp) throws SOPGPException.UnsupportedOption { - commandList.add("--not-after=" + UTCUtil.formatUTCDate(timestamp)); - return this; - } - - @Override - @Nonnull - public DetachedVerify cert(@Nonnull InputStream cert) throws SOPGPException.BadData { - this.certs.add(cert); - return this; - } - - @Override - @Nonnull - public VerifySignatures signatures(@Nonnull InputStream signatures) throws SOPGPException.BadData { - this.signatures = signatures; - return this; - } - - @Override - @Nonnull - public List data(@Nonnull InputStream data) throws IOException, SOPGPException.NoSignature, SOPGPException.BadData { - commandList.add("@ENV:SIGNATURE"); - envList.add("SIGNATURE=" + ExternalSOP.readString(signatures)); - - for (InputStream cert : certs) { - String envVar = "CERT_" + certCounter++; - commandList.add("@ENV:" + envVar); - envList.add(envVar + "=" + ExternalSOP.readString(cert)); - } - - String[] command = commandList.toArray(new String[0]); - String[] env = envList.toArray(new String[0]); - - try { - Process process = Runtime.getRuntime().exec(command, env); - OutputStream processOut = process.getOutputStream(); - InputStream processIn = process.getInputStream(); - - byte[] buf = new byte[4096]; - int r; - while ((r = data.read(buf)) > 0) { - processOut.write(buf, 0, r); - } - - data.close(); - processOut.close(); - - BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(processIn)); - List verifications = new ArrayList<>(); - - String line = null; - while ((line = bufferedReader.readLine()) != null) { - verifications.add(Verification.fromString(line)); - } - - ExternalSOP.finish(process); - - return verifications; - } catch (IOException e) { - throw new RuntimeException(e); - } - } -} diff --git a/external-sop/src/main/kotlin/sop/external/operation/DetachedVerifyExternal.kt b/external-sop/src/main/kotlin/sop/external/operation/DetachedVerifyExternal.kt new file mode 100644 index 0000000..3340a33 --- /dev/null +++ b/external-sop/src/main/kotlin/sop/external/operation/DetachedVerifyExternal.kt @@ -0,0 +1,90 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package sop.external.operation + +import java.io.BufferedReader +import java.io.IOException +import java.io.InputStream +import java.io.InputStreamReader +import java.util.* +import sop.Verification +import sop.Verification.Companion.fromString +import sop.exception.SOPGPException +import sop.external.ExternalSOP +import sop.external.ExternalSOP.Companion.finish +import sop.operation.DetachedVerify +import sop.operation.VerifySignatures +import sop.util.UTCUtil + +/** Implementation of the [DetachedVerify] operation using an external SOP binary. */ +class DetachedVerifyExternal(binary: String, environment: Properties) : DetachedVerify { + + private val commandList = mutableListOf(binary, "verify") + private val envList = ExternalSOP.propertiesToEnv(environment).toMutableList() + + private var signatures: InputStream? = null + private val certs: MutableSet = mutableSetOf() + private var argCounter = 0 + + override fun signatures(signatures: InputStream): VerifySignatures = apply { + this.signatures = signatures + } + + override fun notBefore(timestamp: Date): DetachedVerify = apply { + commandList.add("--not-before=${UTCUtil.formatUTCDate(timestamp)}") + } + + override fun notAfter(timestamp: Date): DetachedVerify = apply { + commandList.add("--not-after=${UTCUtil.formatUTCDate(timestamp)}") + } + + override fun cert(cert: InputStream): DetachedVerify = apply { this.certs.add(cert) } + + override fun data(data: InputStream): List { + // Signature + if (signatures == null) { + throw SOPGPException.MissingArg("Missing argument: signatures cannot be null.") + } + commandList.add("@ENV:SIGNATURE") + envList.add("SIGNATURE=${ExternalSOP.readString(signatures!!)}") + + // Certs + for (cert in certs) { + commandList.add("@ENV:CERT_$argCounter") + envList.add("CERT_$argCounter=${ExternalSOP.readString(cert)}") + argCounter += 1 + } + + try { + val process = + Runtime.getRuntime().exec(commandList.toTypedArray(), envList.toTypedArray()) + val processOut = process.outputStream + val processIn = process.inputStream + + val buf = ByteArray(4096) + var r: Int + while (data.read(buf).also { r = it } > 0) { + processOut.write(buf, 0, r) + } + + data.close() + processOut.close() + + val bufferedReader = BufferedReader(InputStreamReader(processIn)) + val verifications: MutableList = ArrayList() + + var line: String? + while (bufferedReader.readLine().also { line = it } != null) { + verifications.add(fromString(line!!)) + } + + finish(process) + + return verifications + } catch (e: IOException) { + throw RuntimeException(e) + } + } +}