// SPDX-FileCopyrightText: 2024 Paul Schaub // // SPDX-License-Identifier: Apache-2.0 package org.pgpainless.sop import java.io.InputStream import java.io.OutputStream import java.util.* import org.bouncycastle.openpgp.PGPException import org.bouncycastle.util.io.Streams import org.pgpainless.PGPainless import org.pgpainless.decryption_verification.ConsumerOptions import org.pgpainless.exception.MalformedOpenPgpMessageException import org.pgpainless.exception.MissingDecryptionMethodException import sop.ReadyWithResult import sop.Verification import sop.exception.SOPGPException import sop.operation.InlineVerify /** Implementation of the `inline-verify` operation using PGPainless. */ class InlineVerifyImpl : InlineVerify { private val options = ConsumerOptions.get() override fun cert(cert: InputStream): InlineVerify = apply { options.addVerificationCerts(KeyReader.readPublicKeys(cert, true)) } override fun data(data: InputStream): ReadyWithResult> { return object : ReadyWithResult>() { override fun writeTo(outputStream: OutputStream): List { try { val verificationStream = PGPainless.decryptAndOrVerify().onInputStream(data).withOptions(options) Streams.pipeAll(verificationStream, outputStream) verificationStream.close() val result = verificationStream.metadata val verifications = if (result.isUsingCleartextSignatureFramework) { result.verifiedDetachedSignatures } else { result.verifiedInlineSignatures } .map { VerificationHelper.mapVerification(it) } if (options.getCertificateSource().getExplicitCertificates().isNotEmpty() && verifications.isEmpty()) { throw SOPGPException.NoSignature() } return verifications } catch (e: MissingDecryptionMethodException) { throw SOPGPException.BadData("Cannot verify encrypted message.", e) } catch (e: MalformedOpenPgpMessageException) { throw SOPGPException.BadData(e) } catch (e: PGPException) { throw SOPGPException.BadData(e) } } } } override fun notAfter(timestamp: Date): InlineVerify = apply { options.verifyNotAfter(timestamp) } override fun notBefore(timestamp: Date): InlineVerify = apply { options.verifyNotBefore(timestamp) } }