// 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); } } }