aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java
diff options
context:
space:
mode:
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java161
1 files changed, 161 insertions, 0 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java
new file mode 100644
index 000000000..1b7a5e8ba
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java
@@ -0,0 +1,161 @@
+package org.sufficientlysecure.keychain.pgp;
+
+import org.spongycastle.bcpg.SignatureSubpacket;
+import org.spongycastle.bcpg.SignatureSubpacketTags;
+import org.spongycastle.bcpg.sig.RevocationReason;
+import org.spongycastle.openpgp.PGPException;
+import org.spongycastle.openpgp.PGPObjectFactory;
+import org.spongycastle.openpgp.PGPPublicKey;
+import org.spongycastle.openpgp.PGPSignature;
+import org.spongycastle.openpgp.PGPSignatureList;
+import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
+import org.sufficientlysecure.keychain.util.Log;
+
+import java.io.IOException;
+import java.security.SignatureException;
+import java.util.Date;
+
+/** OpenKeychain wrapper around PGPSignature objects.
+ *
+ * This is a mostly simple wrapper around a single bouncycastle PGPSignature
+ * object. It exposes high level getters for all relevant information, methods
+ * for verification of various signatures (uid binding, subkey binding, generic
+ * bytes), and a static method for construction from bytes.
+ *
+ */
+public class WrappedSignature {
+
+ public static final int DEFAULT_CERTIFICATION = PGPSignature.DEFAULT_CERTIFICATION;
+ public static final int NO_CERTIFICATION = PGPSignature.NO_CERTIFICATION;
+ public static final int CASUAL_CERTIFICATION = PGPSignature.CASUAL_CERTIFICATION;
+ public static final int POSITIVE_CERTIFICATION = PGPSignature.POSITIVE_CERTIFICATION;
+ public static final int CERTIFICATION_REVOCATION = PGPSignature.CERTIFICATION_REVOCATION;
+
+ final PGPSignature mSig;
+
+ protected WrappedSignature(PGPSignature sig) {
+ mSig = sig;
+ }
+
+ public long getKeyId() {
+ return mSig.getKeyID();
+ }
+
+ public int getSignatureType() {
+ return mSig.getSignatureType();
+ }
+
+ public int getKeyAlgorithm() {
+ return mSig.getKeyAlgorithm();
+ }
+
+ public Date getCreationTime() {
+ return mSig.getCreationTime();
+ }
+
+ public byte[] getEncoded() throws IOException {
+ return mSig.getEncoded();
+ }
+
+ public boolean isRevocation() {
+ return mSig.getHashedSubPackets().hasSubpacket(SignatureSubpacketTags.REVOCATION_REASON);
+ }
+
+ public boolean isPrimaryUserId() {
+ return mSig.getHashedSubPackets().isPrimaryUserID();
+ }
+
+ public String getRevocationReason() throws PgpGeneralException {
+ if(!isRevocation()) {
+ throw new PgpGeneralException("Not a revocation signature.");
+ }
+ SignatureSubpacket p = mSig.getHashedSubPackets().getSubpacket(
+ SignatureSubpacketTags.REVOCATION_REASON);
+ // For some reason, this is missing in SignatureSubpacketInputStream:146
+ if (!(p instanceof RevocationReason)) {
+ p = new RevocationReason(false, p.getData());
+ }
+ return ((RevocationReason) p).getRevocationDescription();
+ }
+
+ public void init(WrappedPublicKey key) throws PgpGeneralException {
+ init(key.getPublicKey());
+ }
+
+ public void init(UncachedPublicKey key) throws PgpGeneralException {
+ init(key.getPublicKey());
+ }
+
+ protected void init(PGPPublicKey key) throws PgpGeneralException {
+ try {
+ JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
+ new JcaPGPContentVerifierBuilderProvider()
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+ mSig.init(contentVerifierBuilderProvider, key);
+ } catch(PGPException e) {
+ throw new PgpGeneralException(e);
+ }
+ }
+
+ public void update(byte[] data, int offset, int length) throws PgpGeneralException {
+ try {
+ mSig.update(data, offset, length);
+ } catch(SignatureException e) {
+ throw new PgpGeneralException(e);
+ }
+ }
+
+ public void update(byte data) throws PgpGeneralException {
+ try {
+ mSig.update(data);
+ } catch(SignatureException e) {
+ throw new PgpGeneralException(e);
+ }
+ }
+
+ public boolean verify() throws PgpGeneralException {
+ try {
+ return mSig.verify();
+ } catch(SignatureException e) {
+ throw new PgpGeneralException(e);
+ } catch(PGPException e) {
+ throw new PgpGeneralException(e);
+ }
+ }
+
+ protected boolean verifySignature(PGPPublicKey key, String uid) throws PgpGeneralException {
+ try {
+ return mSig.verifyCertification(uid, key);
+ } catch (SignatureException e) {
+ throw new PgpGeneralException("Error!", e);
+ } catch (PGPException e) {
+ throw new PgpGeneralException("Error!", e);
+ }
+ }
+
+ public boolean verifySignature(UncachedPublicKey key, String uid) throws PgpGeneralException {
+ return verifySignature(key.getPublicKey(), uid);
+ }
+ public boolean verifySignature(WrappedPublicKey key, String uid) throws PgpGeneralException {
+ return verifySignature(key.getPublicKey(), uid);
+ }
+
+ public static WrappedSignature fromBytes(byte[] data) {
+ PGPObjectFactory factory = new PGPObjectFactory(data);
+ PGPSignatureList signatures = null;
+ try {
+ if ((signatures = (PGPSignatureList) factory.nextObject()) == null || signatures.isEmpty()) {
+ Log.e(Constants.TAG, "No signatures given!");
+ return null;
+ }
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "Error while converting to PGPSignature!", e);
+ return null;
+ }
+
+ return new WrappedSignature(signatures.get(0));
+ }
+
+}