001// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org> 002// 003// SPDX-License-Identifier: Apache-2.0 004 005package org.pgpainless.sop; 006 007import java.io.IOException; 008import java.io.InputStream; 009import java.util.ArrayList; 010import java.util.Date; 011import java.util.List; 012 013import org.bouncycastle.openpgp.PGPException; 014import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; 015import org.bouncycastle.openpgp.PGPSignature; 016import org.bouncycastle.util.io.Streams; 017import org.pgpainless.PGPainless; 018import org.pgpainless.decryption_verification.ConsumerOptions; 019import org.pgpainless.decryption_verification.DecryptionStream; 020import org.pgpainless.decryption_verification.OpenPgpMetadata; 021import org.pgpainless.key.SubkeyIdentifier; 022import sop.Verification; 023import sop.exception.SOPGPException; 024import sop.operation.Verify; 025 026public class VerifyImpl implements Verify { 027 028 private final ConsumerOptions options = new ConsumerOptions(); 029 030 @Override 031 public Verify notBefore(Date timestamp) throws SOPGPException.UnsupportedOption { 032 options.verifyNotBefore(timestamp); 033 return this; 034 } 035 036 @Override 037 public Verify notAfter(Date timestamp) throws SOPGPException.UnsupportedOption { 038 options.verifyNotAfter(timestamp); 039 return this; 040 } 041 042 @Override 043 public Verify cert(InputStream cert) throws SOPGPException.BadData { 044 PGPPublicKeyRingCollection certificates; 045 try { 046 certificates = PGPainless.readKeyRing().publicKeyRingCollection(cert); 047 } catch (IOException | PGPException e) { 048 throw new SOPGPException.BadData(e); 049 } 050 options.addVerificationCerts(certificates); 051 return this; 052 } 053 054 @Override 055 public VerifyImpl signatures(InputStream signatures) throws SOPGPException.BadData { 056 try { 057 options.addVerificationOfDetachedSignatures(signatures); 058 } catch (IOException | PGPException e) { 059 throw new SOPGPException.BadData(e); 060 } 061 return this; 062 } 063 064 @Override 065 public List<Verification> data(InputStream data) throws IOException, SOPGPException.NoSignature, SOPGPException.BadData { 066 DecryptionStream decryptionStream; 067 try { 068 decryptionStream = PGPainless.decryptAndOrVerify() 069 .onInputStream(data) 070 .withOptions(options); 071 072 Streams.drain(decryptionStream); 073 decryptionStream.close(); 074 075 OpenPgpMetadata metadata = decryptionStream.getResult(); 076 List<Verification> verificationList = new ArrayList<>(); 077 078 for (SubkeyIdentifier verifiedSigningKey : metadata.getVerifiedSignatures().keySet()) { 079 PGPSignature signature = metadata.getVerifiedSignatures().get(verifiedSigningKey); 080 verificationList.add(new Verification( 081 signature.getCreationTime(), 082 verifiedSigningKey.getSubkeyFingerprint().toString(), 083 verifiedSigningKey.getPrimaryKeyFingerprint().toString())); 084 } 085 086 if (!options.getCertificates().isEmpty()) { 087 if (verificationList.isEmpty()) { 088 throw new SOPGPException.NoSignature(); 089 } 090 } 091 092 return verificationList; 093 } catch (PGPException e) { 094 throw new SOPGPException.BadData(e); 095 } 096 } 097}