mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-11-16 17:32:06 +01:00
SOP: Implement basic signature verification
This commit is contained in:
parent
e07998f99d
commit
eb9587163d
2 changed files with 93 additions and 5 deletions
|
@ -1,9 +1,6 @@
|
||||||
package org.pgpainless.sop;
|
package org.pgpainless.sop;
|
||||||
|
|
||||||
import org.pgpainless.sop.commands.ExtractCert;
|
import org.pgpainless.sop.commands.*;
|
||||||
import org.pgpainless.sop.commands.GenerateKey;
|
|
||||||
import org.pgpainless.sop.commands.Sign;
|
|
||||||
import org.pgpainless.sop.commands.Version;
|
|
||||||
import picocli.CommandLine;
|
import picocli.CommandLine;
|
||||||
|
|
||||||
@CommandLine.Command(
|
@CommandLine.Command(
|
||||||
|
@ -11,7 +8,8 @@ import picocli.CommandLine;
|
||||||
Version.class,
|
Version.class,
|
||||||
GenerateKey.class,
|
GenerateKey.class,
|
||||||
ExtractCert.class,
|
ExtractCert.class,
|
||||||
Sign.class
|
Sign.class,
|
||||||
|
Verify.class
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
public class PGPainlessCLI implements Runnable {
|
public class PGPainlessCLI implements Runnable {
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
package org.pgpainless.sop.commands;
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||||
|
import org.bouncycastle.openpgp.PGPSignature;
|
||||||
|
import org.bouncycastle.util.io.Streams;
|
||||||
|
import org.pgpainless.PGPainless;
|
||||||
|
import org.pgpainless.decryption_verification.DecryptionStream;
|
||||||
|
import org.pgpainless.decryption_verification.OpenPgpMetadata;
|
||||||
|
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
||||||
|
import picocli.CommandLine;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@CommandLine.Command(name = "verify")
|
||||||
|
public class Verify implements Runnable {
|
||||||
|
|
||||||
|
@CommandLine.Parameters(index = "0", description = "The detached signature")
|
||||||
|
File signature;
|
||||||
|
|
||||||
|
@CommandLine.Parameters(index = "1..*")
|
||||||
|
File[] certs;
|
||||||
|
|
||||||
|
TimeZone tz = TimeZone.getTimeZone("UTC");
|
||||||
|
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
df.setTimeZone(tz);
|
||||||
|
|
||||||
|
if (certs.length == 0) {
|
||||||
|
System.out.println("No certificates supplied.");
|
||||||
|
System.exit(19);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<File, PGPPublicKeyRing> publicKeys = new HashMap<>();
|
||||||
|
for (File cert : certs) {
|
||||||
|
try(FileInputStream in = new FileInputStream(cert)) {
|
||||||
|
publicKeys.put(cert, PGPainless.readKeyRing().publicKeyRing(in));
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try(FileInputStream sigIn = new FileInputStream(signature)) {
|
||||||
|
DecryptionStream verifier = PGPainless.decryptAndOrVerify()
|
||||||
|
.onInputStream(System.in)
|
||||||
|
.doNotDecrypt()
|
||||||
|
.verifyDetachedSignature(sigIn)
|
||||||
|
.verifyWith(new HashSet<>(publicKeys.values()))
|
||||||
|
.ignoreMissingPublicKeys()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
Streams.pipeAll(verifier, out);
|
||||||
|
verifier.close();
|
||||||
|
|
||||||
|
OpenPgpMetadata metadata = verifier.getResult();
|
||||||
|
|
||||||
|
for (OpenPgpV4Fingerprint sigKeyFp : metadata.getVerifiedSignatures().keySet()) {
|
||||||
|
PGPSignature signature = metadata.getVerifiedSignatures().get(sigKeyFp);
|
||||||
|
for (File file : certs) {
|
||||||
|
// Search signing key ring
|
||||||
|
PGPPublicKeyRing publicKeyRing = publicKeys.get(file);
|
||||||
|
if (publicKeyRing.getPublicKey(sigKeyFp.getKeyId()) == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String utcSigDate = df.format(signature.getCreationTime());
|
||||||
|
OpenPgpV4Fingerprint primaryKeyFp = new OpenPgpV4Fingerprint(publicKeyRing);
|
||||||
|
System.out.println(utcSigDate + " " + sigKeyFp.toString() + " " + primaryKeyFp.toString() +
|
||||||
|
" signed by " + file.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (metadata.getVerifiedSignatures().isEmpty()) {
|
||||||
|
System.out.println("Signature validation failed.");
|
||||||
|
System.exit(3);
|
||||||
|
}
|
||||||
|
} catch (IOException | PGPException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue