Example usage for org.bouncycastle.openpgp PGPSignature SUBKEY_BINDING

List of usage examples for org.bouncycastle.openpgp PGPSignature SUBKEY_BINDING

Introduction

In this page you can find the example usage for org.bouncycastle.openpgp PGPSignature SUBKEY_BINDING.

Prototype

int SUBKEY_BINDING

To view the source code for org.bouncycastle.openpgp PGPSignature SUBKEY_BINDING.

Click Source Link

Usage

From source file:com.google.e2e.bcdriver.KeyChecker.java

License:Apache License

private static final void maybeAddSubkey(List<Subkey> subkeys, PGPPublicKey masterpk, PGPPublicKey subkey,
        StringBuilder errors) throws PGPException, SignatureException, IOException {

    Iterator<PGPSignature> sigit = Util.getTypedIterator(subkey.getSignatures(), PGPSignature.class);
    if (sigit == null) {
        errors.append("Reject subkey " + nicePk(subkey) + " because no binding signatures were found.\n");
        return;// w  ww  .j a  v a  2 s  . c o m
    }

    PGPSignature validSig = null;
    long validTs = -1L;

    while (sigit.hasNext()) {
        PGPSignature sig = sigit.next();
        switch (sig.getSignatureType()) {
        case PGPSignature.SUBKEY_BINDING:
        case PGPSignature.SUBKEY_REVOCATION:
            if (isGoodSubkeySignature(sig, masterpk, subkey, errors)) {
                if (sig.getSignatureType() == PGPSignature.SUBKEY_REVOCATION) {
                    // Reject this subkey permanently.
                    errors.append("Subkey " + nicePk(subkey) + " revoked by " + niceSig(sig) + "\n");
                    return;
                }
                // signing subkeys must have an embedded back signature.
                if (!Util.hasKeyFlag(sig, KeyFlags.SIGN_DATA)
                        || isGoodBackSignature(sig, masterpk, subkey, errors)) {
                    long ts = getSignatureTimestamp(sig, errors);
                    if (ts > validTs) {
                        validSig = sig;
                        validTs = ts;
                    }
                }
            }
            break;

        default:
            errors.append("Ignore " + niceSig(sig) + " for subkey " + nicePk(subkey) + "\n");
            break;
        }
    }
    // We need atleast one good binding.
    if (validSig == null) {
        errors.append(
                "Subkey " + nicePk(subkey) + " rejected because no valid binding signatures were found.\n");
        return;
    }
    subkeys.add(new Subkey(subkey, validSig));
}

From source file:org.sufficientlysecure.keychain.pgp.PgpKeyOperation.java

License:Open Source License

static PGPSignature generateSubkeyBindingSignature(PGPSignatureGenerator sGen, Date creationTime,
        PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey, PGPSignatureGenerator subSigGen,
        PGPPrivateKey subPrivateKey, PGPPublicKey pKey, int flags, long expiry)
        throws IOException, PGPException, SignatureException {

    PGPSignatureSubpacketGenerator unhashedPacketsGen = new PGPSignatureSubpacketGenerator();

    // If this key can sign, we need a primary key binding signature
    if ((flags & KeyFlags.SIGN_DATA) > 0) {
        // cross-certify signing keys
        PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
        subHashedPacketsGen.setSignatureCreationTime(false, creationTime);
        subSigGen.init(PGPSignature.PRIMARYKEY_BINDING, subPrivateKey);
        subSigGen.setHashedSubpackets(subHashedPacketsGen.generate());
        PGPSignature certification = subSigGen.generateCertification(masterPublicKey, pKey);
        unhashedPacketsGen.setEmbeddedSignature(true, certification);
    }//from   ww  w. j av  a  2 s. c o m

    PGPSignatureSubpacketGenerator hashedPacketsGen;
    {
        hashedPacketsGen = new PGPSignatureSubpacketGenerator();
        hashedPacketsGen.setSignatureCreationTime(true, creationTime);
        hashedPacketsGen.setKeyFlags(true, flags);
        if (expiry > 0) {
            hashedPacketsGen.setKeyExpirationTime(true, expiry - pKey.getCreationTime().getTime() / 1000);
        }
    }

    sGen.init(PGPSignature.SUBKEY_BINDING, masterPrivateKey);
    sGen.setHashedSubpackets(hashedPacketsGen.generate());
    sGen.setUnhashedSubpackets(unhashedPacketsGen.generate());

    return sGen.generateCertification(masterPublicKey, pKey);

}

From source file:org.sufficientlysecure.keychain.pgp.PgpKeyOperationTest.java

License:Open Source License

@Test
public void testSubkeyAdd() throws Exception {

    long expiry = new Date().getTime() / 1000 + 159;
    int flags = KeyFlags.SIGN_DATA;
    parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(Algorithm.ECDSA, 0,
            SaveKeyringParcel.Curve.NIST_P256, flags, expiry));

    UncachedKeyRing modified = applyModificationWithChecks(parcel, ring, onlyA, onlyB);

    Assert.assertEquals("no extra packets in original", 0, onlyA.size());
    Assert.assertEquals("exactly two extra packets in modified", 2, onlyB.size());

    Packet p;/*  w w  w .j a  va  2  s. co m*/

    p = new BCPGInputStream(new ByteArrayInputStream(onlyB.get(0).buf)).readPacket();
    Assert.assertTrue("first new packet must be secret subkey", p instanceof SecretSubkeyPacket);

    p = new BCPGInputStream(new ByteArrayInputStream(onlyB.get(1).buf)).readPacket();
    Assert.assertTrue("second new packet must be signature", p instanceof SignaturePacket);
    Assert.assertEquals("signature type must be subkey binding certificate", PGPSignature.SUBKEY_BINDING,
            ((SignaturePacket) p).getSignatureType());
    Assert.assertEquals("signature must have been created by master key", ring.getMasterKeyId(),
            ((SignaturePacket) p).getKeyID());

    // get new key from ring. it should be the last one (add a check to make sure?)
    UncachedPublicKey newKey = null;
    {
        Iterator<UncachedPublicKey> it = modified.getPublicKeys();
        while (it.hasNext()) {
            newKey = it.next();
        }
    }

    Assert.assertNotNull("new key is not null", newKey);
    Assert.assertNotNull("added key must have an expiry date", newKey.getUnsafeExpiryTimeForTesting());
    Assert.assertEquals("added key must have expected expiry date", expiry,
            newKey.getUnsafeExpiryTimeForTesting().getTime() / 1000);
    Assert.assertEquals("added key must have expected flags", flags, (long) newKey.getKeyUsage());

    { // bad keysize should fail
        parcel.reset();
        parcel.mAddSubKeys
                .add(new SubkeyAdd(Algorithm.RSA, new Random().nextInt(512), null, KeyFlags.SIGN_DATA, 0L));
        assertModifyFailure("creating a subkey with keysize < 2048 should fail", ring, parcel,
                LogType.MSG_CR_ERROR_KEYSIZE_2048);
    }

    { // null expiry should fail
        parcel.reset();
        parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(Algorithm.ECDSA, 0,
                SaveKeyringParcel.Curve.NIST_P256, KeyFlags.SIGN_DATA, null));
        assertModifyFailure("creating master key with null expiry should fail", ring, parcel,
                LogType.MSG_MF_ERROR_NULL_EXPIRY);
    }

    { // a past expiry should fail
        parcel.reset();
        parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(Algorithm.ECDSA, 0,
                SaveKeyringParcel.Curve.NIST_P256, KeyFlags.SIGN_DATA, new Date().getTime() / 1000 - 10));
        assertModifyFailure("creating subkey with past expiry date should fail", ring, parcel,
                LogType.MSG_MF_ERROR_PAST_EXPIRY);
    }

}

From source file:org.sufficientlysecure.keychain.pgp.PgpKeyOperationTest.java

License:Open Source License

@Test
public void testSubkeyModify() throws Exception {

    long expiry = new Date().getTime() / 1000 + 1024;
    long keyId = KeyringTestingHelper.getSubkeyId(ring, 1);

    UncachedKeyRing modified = ring;//from w w  w.  j a  v  a 2s . c o  m
    {
        parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, expiry));
        modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB);

        Assert.assertEquals("one extra packet in original", 1, onlyA.size());
        Assert.assertEquals("one extra packet in modified", 1, onlyB.size());

        Assert.assertEquals("old packet must be signature", PacketTags.SIGNATURE, onlyA.get(0).tag);

        Packet p = new BCPGInputStream(new ByteArrayInputStream(onlyB.get(0).buf)).readPacket();
        Assert.assertTrue("first new packet must be signature", p instanceof SignaturePacket);
        Assert.assertEquals("signature type must be subkey binding certificate", PGPSignature.SUBKEY_BINDING,
                ((SignaturePacket) p).getSignatureType());
        Assert.assertEquals("signature must have been created by master key", ring.getMasterKeyId(),
                ((SignaturePacket) p).getKeyID());

        Assert.assertNotNull("modified key must have an expiry date",
                modified.getPublicKey(keyId).getUnsafeExpiryTimeForTesting());
        Assert.assertEquals("modified key must have expected expiry date", expiry,
                modified.getPublicKey(keyId).getUnsafeExpiryTimeForTesting().getTime() / 1000);
        Assert.assertEquals("modified key must have same flags as before",
                ring.getPublicKey(keyId).getKeyUsage(), modified.getPublicKey(keyId).getKeyUsage());
    }

    { // change expiry
        expiry += 60 * 60 * 24;

        parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, expiry));
        modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB);

        Assert.assertNotNull("modified key must have an expiry date",
                modified.getPublicKey(keyId).getUnsafeExpiryTimeForTesting());
        Assert.assertEquals("modified key must have expected expiry date", expiry,
                modified.getPublicKey(keyId).getUnsafeExpiryTimeForTesting().getTime() / 1000);
        Assert.assertEquals("modified key must have same flags as before",
                ring.getPublicKey(keyId).getKeyUsage(), modified.getPublicKey(keyId).getKeyUsage());
    }

    {
        int flags = KeyFlags.SIGN_DATA | KeyFlags.ENCRYPT_COMMS;
        parcel.reset();
        parcel.mChangeSubKeys.add(new SubkeyChange(keyId, flags, null));
        modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB);

        Assert.assertEquals("old packet must be signature", PacketTags.SIGNATURE, onlyA.get(0).tag);

        Packet p = new BCPGInputStream(new ByteArrayInputStream(onlyB.get(0).buf)).readPacket();
        Assert.assertTrue("first new packet must be signature", p instanceof SignaturePacket);
        Assert.assertEquals("signature type must be subkey binding certificate", PGPSignature.SUBKEY_BINDING,
                ((SignaturePacket) p).getSignatureType());
        Assert.assertEquals("signature must have been created by master key", ring.getMasterKeyId(),
                ((SignaturePacket) p).getKeyID());

        Assert.assertEquals("modified key must have expected flags", flags,
                (long) modified.getPublicKey(keyId).getKeyUsage());
        Assert.assertNotNull("key must retain its expiry",
                modified.getPublicKey(keyId).getUnsafeExpiryTimeForTesting());
        Assert.assertEquals("key expiry must be unchanged", expiry,
                modified.getPublicKey(keyId).getUnsafeExpiryTimeForTesting().getTime() / 1000);
    }

    { // expiry of 0 should be "no expiry"
        parcel.reset();
        parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, 0L));
        modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB);

        Assert.assertEquals("old packet must be signature", PacketTags.SIGNATURE, onlyA.get(0).tag);

        Packet p = new BCPGInputStream(new ByteArrayInputStream(onlyB.get(0).buf)).readPacket();
        Assert.assertTrue("first new packet must be signature", p instanceof SignaturePacket);
        Assert.assertEquals("signature type must be subkey binding certificate", PGPSignature.SUBKEY_BINDING,
                ((SignaturePacket) p).getSignatureType());
        Assert.assertEquals("signature must have been created by master key", ring.getMasterKeyId(),
                ((SignaturePacket) p).getKeyID());

        Assert.assertNull("key must not expire anymore",
                modified.getPublicKey(keyId).getUnsafeExpiryTimeForTesting());
    }

    { // a past expiry should fail
        parcel.reset();
        parcel.mChangeSubKeys.add(new SubkeyChange(keyId, null, new Date().getTime() / 1000 - 10));

        assertModifyFailure("setting subkey expiry to a past date should fail", ring, parcel,
                LogType.MSG_MF_ERROR_PAST_EXPIRY);
    }

    { // modifying nonexistent subkey should fail
        parcel.reset();
        parcel.mChangeSubKeys.add(new SubkeyChange(123, null, null));

        assertModifyFailure("modifying non-existent subkey should fail", ring, parcel,
                LogType.MSG_MF_ERROR_SUBKEY_MISSING);
    }

}

From source file:org.sufficientlysecure.keychain.pgp.PgpKeyOperationTest.java

License:Open Source License

@Test
public void testSubkeyRevoke() throws Exception {

    long keyId = KeyringTestingHelper.getSubkeyId(ring, 1);
    int flags = ring.getPublicKey(keyId).getKeyUsage();

    UncachedKeyRing modified;//w w w  .j  a va2s .c  o m

    {

        parcel.reset();
        parcel.mRevokeSubKeys.add(123L);

        CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(ring.getEncoded(), false, 0);
        UncachedKeyRing otherModified = op.modifySecretKeyRing(secretRing, cryptoInput, parcel).getRing();

        Assert.assertNull("revoking a nonexistent subkey should fail", otherModified);

    }

    { // revoked second subkey

        parcel.reset();
        parcel.mRevokeSubKeys.add(keyId);

        modified = applyModificationWithChecks(parcel, ring, onlyA, onlyB,
                new CryptoInputParcel(new Date(), passphrase));

        Assert.assertEquals("no extra packets in original", 0, onlyA.size());
        Assert.assertEquals("exactly one extra packet in modified", 1, onlyB.size());

        Packet p;

        p = new BCPGInputStream(new ByteArrayInputStream(onlyB.get(0).buf)).readPacket();
        Assert.assertTrue("first new packet must be secret subkey", p instanceof SignaturePacket);
        Assert.assertEquals("signature type must be subkey binding certificate", PGPSignature.SUBKEY_REVOCATION,
                ((SignaturePacket) p).getSignatureType());
        Assert.assertEquals("signature must have been created by master key", ring.getMasterKeyId(),
                ((SignaturePacket) p).getKeyID());

        Assert.assertTrue("subkey must actually be revoked", modified.getPublicKey(keyId).isMaybeRevoked());
    }

    { // re-add second subkey

        parcel.reset();
        // re-certify the revoked subkey
        parcel.mChangeSubKeys.add(new SubkeyChange(keyId, true));

        modified = applyModificationWithChecks(parcel, modified, onlyA, onlyB);

        Assert.assertEquals("exactly two outdated packets in original", 2, onlyA.size());
        Assert.assertEquals("exactly one extra packet in modified", 1, onlyB.size());

        Packet p;

        p = new BCPGInputStream(new ByteArrayInputStream(onlyA.get(0).buf)).readPacket();
        Assert.assertTrue("first outdated packet must be signature", p instanceof SignaturePacket);
        Assert.assertEquals("first outdated signature type must be subkey binding certification",
                PGPSignature.SUBKEY_BINDING, ((SignaturePacket) p).getSignatureType());
        Assert.assertEquals("first outdated signature must have been created by master key",
                ring.getMasterKeyId(), ((SignaturePacket) p).getKeyID());

        p = new BCPGInputStream(new ByteArrayInputStream(onlyA.get(1).buf)).readPacket();
        Assert.assertTrue("second outdated packet must be signature", p instanceof SignaturePacket);
        Assert.assertEquals("second outdated signature type must be subkey revocation",
                PGPSignature.SUBKEY_REVOCATION, ((SignaturePacket) p).getSignatureType());
        Assert.assertEquals("second outdated signature must have been created by master key",
                ring.getMasterKeyId(), ((SignaturePacket) p).getKeyID());

        p = new BCPGInputStream(new ByteArrayInputStream(onlyB.get(0).buf)).readPacket();
        Assert.assertTrue("new packet must be signature ", p instanceof SignaturePacket);
        Assert.assertEquals("new signature type must be subkey binding certification",
                PGPSignature.SUBKEY_BINDING, ((SignaturePacket) p).getSignatureType());
        Assert.assertEquals("signature must have been created by master key", ring.getMasterKeyId(),
                ((SignaturePacket) p).getKeyID());

        Assert.assertFalse("subkey must no longer be revoked", modified.getPublicKey(keyId).isMaybeRevoked());
        Assert.assertEquals("subkey must have the same usage flags as before", flags,
                (long) modified.getPublicKey(keyId).getKeyUsage());

    }
}

From source file:org.sufficientlysecure.keychain.pgp.UncachedKeyRing.java

License:Open Source License

/** "Canonicalizes" a public key, removing inconsistencies in the process.
 *
 * More specifically://w w  w.j  av  a 2  s. c  o m
 *  - Remove all non-verifying self-certificates
 *  - Remove all "future" self-certificates
 *  - Remove all certificates flagged as "local"
 *  - For UID certificates, remove all certificates which are
 *      superseded by a newer one on the same target, including
 *      revocations with later re-certifications.
 *  - For subkey certifications, remove all certificates which
 *      are superseded by a newer one on the same target, unless
 *      it encounters a revocation certificate. The revocation
 *      certificate is considered to permanently revoke the key,
 *      even if contains later re-certifications.
 *  This is the "behavior in practice" used by (e.g.) GnuPG, and
 *  the rationale for both can be found as comments in the GnuPG
 *  source.
 *  UID signatures:
 *  https://github.com/mtigas/gnupg/blob/50c98c7ed6b542857ee2f902eca36cda37407737/g10/getkey.c#L1668-L1674
 *  Subkey signatures:
 *  https://github.com/mtigas/gnupg/blob/50c98c7ed6b542857ee2f902eca36cda37407737/g10/getkey.c#L1990-L1997
 *  - Remove all certificates in other positions if not of known type:
 *   - key revocation signatures on the master key
 *   - subkey binding signatures for subkeys
 *   - certifications and certification revocations for user ids
 *  - If a subkey retains no valid subkey binding certificate, remove it
 *  - If a user id retains no valid self certificate, remove it
 *  - If the key is a secret key, remove all certificates by foreign keys
 *  - If no valid user id remains, log an error and return null
 *
 * This operation writes an OperationLog which can be used as part of an OperationResultParcel.
 *
 * @param forExport if this is true, non-exportable signatures will be removed
 * @return A canonicalized key, or null on fatal error (log will include a message in this case)
 *
 */
@SuppressWarnings("ConstantConditions")
public CanonicalizedKeyRing canonicalize(OperationLog log, int indent, boolean forExport) {

    log.add(isSecret() ? LogType.MSG_KC_SECRET : LogType.MSG_KC_PUBLIC, indent,
            KeyFormattingUtils.convertKeyIdToHex(getMasterKeyId()));
    indent += 1;

    // do not accept v3 keys
    if (getVersion() <= 3) {
        log.add(LogType.MSG_KC_ERROR_V3, indent);
        return null;
    }

    Calendar nowCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
    // allow for diverging clocks up to one day when checking creation time
    nowCal.add(Calendar.DAY_OF_YEAR, 1);
    final Date nowPlusOneDay = nowCal.getTime();

    int redundantCerts = 0, badCerts = 0;

    PGPKeyRing ring = mRing;
    PGPPublicKey masterKey = mRing.getPublicKey();
    final long masterKeyId = masterKey.getKeyID();

    if (Arrays.binarySearch(KNOWN_ALGORITHMS, masterKey.getAlgorithm()) < 0) {
        log.add(LogType.MSG_KC_ERROR_MASTER_ALGO, indent, Integer.toString(masterKey.getAlgorithm()));
        return null;
    }

    {
        log.add(LogType.MSG_KC_MASTER, indent, KeyFormattingUtils.convertKeyIdToHex(masterKey.getKeyID()));
        indent += 1;

        PGPPublicKey modified = masterKey;
        PGPSignature revocation = null;
        PGPSignature notation = null;
        for (PGPSignature zert : new IterableIterator<PGPSignature>(masterKey.getKeySignatures())) {
            int type = zert.getSignatureType();

            // These should most definitely not be here...
            if (type == PGPSignature.NO_CERTIFICATION || type == PGPSignature.DEFAULT_CERTIFICATION
                    || type == PGPSignature.CASUAL_CERTIFICATION || type == PGPSignature.POSITIVE_CERTIFICATION
                    || type == PGPSignature.CERTIFICATION_REVOCATION) {
                log.add(LogType.MSG_KC_MASTER_BAD_TYPE_UID, indent);
                modified = PGPPublicKey.removeCertification(modified, zert);
                badCerts += 1;
                continue;
            }
            WrappedSignature cert = new WrappedSignature(zert);

            if (type != PGPSignature.KEY_REVOCATION && type != PGPSignature.DIRECT_KEY) {
                // Unknown type, just remove
                log.add(LogType.MSG_KC_MASTER_BAD_TYPE, indent, "0x" + Integer.toString(type, 16));
                modified = PGPPublicKey.removeCertification(modified, zert);
                badCerts += 1;
                continue;
            }

            if (cert.getCreationTime().after(nowPlusOneDay)) {
                // Creation date in the future? No way!
                log.add(LogType.MSG_KC_MASTER_BAD_TIME, indent);
                modified = PGPPublicKey.removeCertification(modified, zert);
                badCerts += 1;
                continue;
            }

            try {
                cert.init(masterKey);
                if (!cert.verifySignature(masterKey)) {
                    log.add(LogType.MSG_KC_MASTER_BAD, indent);
                    modified = PGPPublicKey.removeCertification(modified, zert);
                    badCerts += 1;
                    continue;
                }
            } catch (PgpGeneralException e) {
                log.add(LogType.MSG_KC_MASTER_BAD_ERR, indent);
                modified = PGPPublicKey.removeCertification(modified, zert);
                badCerts += 1;
                continue;
            }

            // if this is for export, we always remove any non-exportable certs
            if (forExport && cert.isLocal()) {
                // Remove revocation certs with "local" flag
                log.add(LogType.MSG_KC_MASTER_LOCAL, indent);
                modified = PGPPublicKey.removeCertification(modified, zert);
                continue;
            }

            // special case: non-exportable, direct key signatures for notations!
            if (cert.getSignatureType() == PGPSignature.DIRECT_KEY) {
                // must be local, otherwise strip!
                if (!cert.isLocal()) {
                    log.add(LogType.MSG_KC_MASTER_BAD_TYPE, indent);
                    modified = PGPPublicKey.removeCertification(modified, zert);
                    badCerts += 1;
                    continue;
                }

                // first notation? fine then.
                if (notation == null) {
                    notation = zert;
                    // more notations? at least one is superfluous, then.
                } else if (notation.getCreationTime().before(zert.getCreationTime())) {
                    log.add(LogType.MSG_KC_NOTATION_DUP, indent);
                    modified = PGPPublicKey.removeCertification(modified, notation);
                    redundantCerts += 1;
                    notation = zert;
                } else {
                    log.add(LogType.MSG_KC_NOTATION_DUP, indent);
                    modified = PGPPublicKey.removeCertification(modified, zert);
                    redundantCerts += 1;
                }
                continue;
            } else if (cert.isLocal()) {
                // Remove revocation certs with "local" flag
                log.add(LogType.MSG_KC_MASTER_BAD_LOCAL, indent);
                modified = PGPPublicKey.removeCertification(modified, zert);
                badCerts += 1;
                continue;
            }

            // first revocation? fine then.
            if (revocation == null) {
                revocation = zert;
                // more revocations? at least one is superfluous, then.
            } else if (revocation.getCreationTime().before(zert.getCreationTime())) {
                log.add(LogType.MSG_KC_REVOKE_DUP, indent);
                modified = PGPPublicKey.removeCertification(modified, revocation);
                redundantCerts += 1;
                revocation = zert;
            } else {
                log.add(LogType.MSG_KC_REVOKE_DUP, indent);
                modified = PGPPublicKey.removeCertification(modified, zert);
                redundantCerts += 1;
            }
        }

        // If we have a notation packet, check if there is even any data in it?
        if (notation != null) {
            // If there isn't, might as well strip it
            if (new WrappedSignature(notation).getNotation().isEmpty()) {
                log.add(LogType.MSG_KC_NOTATION_EMPTY, indent);
                modified = PGPPublicKey.removeCertification(modified, notation);
                redundantCerts += 1;
            }
        }

        ArrayList<String> processedUserIds = new ArrayList<>();
        for (byte[] rawUserId : new IterableIterator<byte[]>(masterKey.getRawUserIDs())) {
            String userId = Utf8Util.fromUTF8ByteArrayReplaceBadEncoding(rawUserId);

            // warn if user id was made with bad encoding
            if (!Utf8Util.isValidUTF8(rawUserId)) {
                log.add(LogType.MSG_KC_UID_WARN_ENCODING, indent);
            }

            // check for duplicate user ids
            if (processedUserIds.contains(userId)) {
                log.add(LogType.MSG_KC_UID_DUP, indent, userId);
                // strip out the first found user id with this name
                modified = PGPPublicKey.removeCertification(modified, rawUserId);
            }
            if (processedUserIds.size() > CANONICALIZE_MAX_USER_IDS) {
                log.add(LogType.MSG_KC_UID_TOO_MANY, indent, userId);
                // strip out the user id
                modified = PGPPublicKey.removeCertification(modified, rawUserId);
            }
            processedUserIds.add(userId);

            PGPSignature selfCert = null;
            revocation = null;

            // look through signatures for this specific user id
            @SuppressWarnings("unchecked")
            Iterator<PGPSignature> signaturesIt = masterKey.getSignaturesForID(rawUserId);
            if (signaturesIt != null) {
                for (PGPSignature zert : new IterableIterator<>(signaturesIt)) {
                    WrappedSignature cert = new WrappedSignature(zert);
                    long certId = cert.getKeyId();

                    int type = zert.getSignatureType();
                    if (type != PGPSignature.DEFAULT_CERTIFICATION && type != PGPSignature.NO_CERTIFICATION
                            && type != PGPSignature.CASUAL_CERTIFICATION
                            && type != PGPSignature.POSITIVE_CERTIFICATION
                            && type != PGPSignature.CERTIFICATION_REVOCATION) {
                        log.add(LogType.MSG_KC_UID_BAD_TYPE, indent,
                                "0x" + Integer.toString(zert.getSignatureType(), 16));
                        modified = PGPPublicKey.removeCertification(modified, rawUserId, zert);
                        badCerts += 1;
                        continue;
                    }

                    if (cert.getCreationTime().after(nowPlusOneDay)) {
                        // Creation date in the future? No way!
                        log.add(LogType.MSG_KC_UID_BAD_TIME, indent);
                        modified = PGPPublicKey.removeCertification(modified, rawUserId, zert);
                        badCerts += 1;
                        continue;
                    }

                    if (cert.isLocal()) {
                        // Creation date in the future? No way!
                        log.add(LogType.MSG_KC_UID_BAD_LOCAL, indent);
                        modified = PGPPublicKey.removeCertification(modified, rawUserId, zert);
                        badCerts += 1;
                        continue;
                    }

                    // If this is a foreign signature, ...
                    if (certId != masterKeyId) {
                        // never mind any further for public keys, but remove them from secret ones
                        if (isSecret()) {
                            log.add(LogType.MSG_KC_UID_FOREIGN, indent,
                                    KeyFormattingUtils.convertKeyIdToHex(certId));
                            modified = PGPPublicKey.removeCertification(modified, rawUserId, zert);
                            badCerts += 1;
                        }
                        continue;
                    }

                    // Otherwise, first make sure it checks out
                    try {
                        cert.init(masterKey);
                        if (!cert.verifySignature(masterKey, rawUserId)) {
                            log.add(LogType.MSG_KC_UID_BAD, indent, userId);
                            modified = PGPPublicKey.removeCertification(modified, rawUserId, zert);
                            badCerts += 1;
                            continue;
                        }
                    } catch (PgpGeneralException e) {
                        log.add(LogType.MSG_KC_UID_BAD_ERR, indent, userId);
                        modified = PGPPublicKey.removeCertification(modified, rawUserId, zert);
                        badCerts += 1;
                        continue;
                    }

                    switch (type) {
                    case PGPSignature.DEFAULT_CERTIFICATION:
                    case PGPSignature.NO_CERTIFICATION:
                    case PGPSignature.CASUAL_CERTIFICATION:
                    case PGPSignature.POSITIVE_CERTIFICATION:
                        if (selfCert == null) {
                            selfCert = zert;
                        } else if (selfCert.getCreationTime().before(cert.getCreationTime())) {
                            log.add(LogType.MSG_KC_UID_CERT_DUP, indent, userId);
                            modified = PGPPublicKey.removeCertification(modified, rawUserId, selfCert);
                            redundantCerts += 1;
                            selfCert = zert;
                        } else {
                            log.add(LogType.MSG_KC_UID_CERT_DUP, indent, userId);
                            modified = PGPPublicKey.removeCertification(modified, rawUserId, zert);
                            redundantCerts += 1;
                        }
                        // If there is a revocation certificate, and it's older than this, drop it
                        if (revocation != null
                                && revocation.getCreationTime().before(selfCert.getCreationTime())) {
                            log.add(LogType.MSG_KC_UID_REVOKE_OLD, indent, userId);
                            modified = PGPPublicKey.removeCertification(modified, rawUserId, revocation);
                            revocation = null;
                            redundantCerts += 1;
                        }
                        break;

                    case PGPSignature.CERTIFICATION_REVOCATION:
                        // If this is older than the (latest) self cert, drop it
                        if (selfCert != null && selfCert.getCreationTime().after(zert.getCreationTime())) {
                            log.add(LogType.MSG_KC_UID_REVOKE_OLD, indent, userId);
                            modified = PGPPublicKey.removeCertification(modified, rawUserId, zert);
                            redundantCerts += 1;
                            continue;
                        }
                        // first revocation? remember it.
                        if (revocation == null) {
                            revocation = zert;
                            // more revocations? at least one is superfluous, then.
                        } else if (revocation.getCreationTime().before(cert.getCreationTime())) {
                            log.add(LogType.MSG_KC_UID_REVOKE_DUP, indent, userId);
                            modified = PGPPublicKey.removeCertification(modified, rawUserId, revocation);
                            redundantCerts += 1;
                            revocation = zert;
                        } else {
                            log.add(LogType.MSG_KC_UID_REVOKE_DUP, indent, userId);
                            modified = PGPPublicKey.removeCertification(modified, rawUserId, zert);
                            redundantCerts += 1;
                        }
                        break;
                    }
                }
            }

            // If no valid certificate (if only a revocation) remains, drop it
            if (selfCert == null && revocation == null) {
                log.add(LogType.MSG_KC_UID_REMOVE, indent, userId);
                modified = PGPPublicKey.removeCertification(modified, rawUserId);
            }
        }

        // If NO user ids remain, error out!
        if (modified == null || !modified.getUserIDs().hasNext()) {
            log.add(LogType.MSG_KC_ERROR_NO_UID, indent);
            return null;
        }

        ArrayList<PGPUserAttributeSubpacketVector> processedUserAttributes = new ArrayList<>();
        for (PGPUserAttributeSubpacketVector userAttribute : new IterableIterator<PGPUserAttributeSubpacketVector>(
                masterKey.getUserAttributes())) {

            if (userAttribute.getSubpacket(UserAttributeSubpacketTags.IMAGE_ATTRIBUTE) != null) {
                log.add(LogType.MSG_KC_UAT_JPEG, indent);
            } else {
                log.add(LogType.MSG_KC_UAT_UNKNOWN, indent);
            }

            try {
                indent += 1;

                // check for duplicate user attributes
                if (processedUserAttributes.contains(userAttribute)) {
                    log.add(LogType.MSG_KC_UAT_DUP, indent);
                    // strip out the first found user id with this name
                    modified = PGPPublicKey.removeCertification(modified, userAttribute);
                }
                processedUserAttributes.add(userAttribute);

                PGPSignature selfCert = null;
                revocation = null;

                // look through signatures for this specific user id
                @SuppressWarnings("unchecked")
                Iterator<PGPSignature> signaturesIt = masterKey.getSignaturesForUserAttribute(userAttribute);
                if (signaturesIt != null) {
                    for (PGPSignature zert : new IterableIterator<>(signaturesIt)) {
                        WrappedSignature cert = new WrappedSignature(zert);
                        long certId = cert.getKeyId();

                        int type = zert.getSignatureType();
                        if (type != PGPSignature.DEFAULT_CERTIFICATION && type != PGPSignature.NO_CERTIFICATION
                                && type != PGPSignature.CASUAL_CERTIFICATION
                                && type != PGPSignature.POSITIVE_CERTIFICATION
                                && type != PGPSignature.CERTIFICATION_REVOCATION) {
                            log.add(LogType.MSG_KC_UAT_BAD_TYPE, indent,
                                    "0x" + Integer.toString(zert.getSignatureType(), 16));
                            modified = PGPPublicKey.removeCertification(modified, userAttribute, zert);
                            badCerts += 1;
                            continue;
                        }

                        if (cert.getCreationTime().after(nowPlusOneDay)) {
                            // Creation date in the future? No way!
                            log.add(LogType.MSG_KC_UAT_BAD_TIME, indent);
                            modified = PGPPublicKey.removeCertification(modified, userAttribute, zert);
                            badCerts += 1;
                            continue;
                        }

                        if (cert.isLocal()) {
                            // Creation date in the future? No way!
                            log.add(LogType.MSG_KC_UAT_BAD_LOCAL, indent);
                            modified = PGPPublicKey.removeCertification(modified, userAttribute, zert);
                            badCerts += 1;
                            continue;
                        }

                        // If this is a foreign signature, ...
                        if (certId != masterKeyId) {
                            // never mind any further for public keys, but remove them from secret ones
                            if (isSecret()) {
                                log.add(LogType.MSG_KC_UAT_FOREIGN, indent,
                                        KeyFormattingUtils.convertKeyIdToHex(certId));
                                modified = PGPPublicKey.removeCertification(modified, userAttribute, zert);
                                badCerts += 1;
                            }
                            continue;
                        }

                        // Otherwise, first make sure it checks out
                        try {
                            cert.init(masterKey);
                            if (!cert.verifySignature(masterKey, userAttribute)) {
                                log.add(LogType.MSG_KC_UAT_BAD, indent);
                                modified = PGPPublicKey.removeCertification(modified, userAttribute, zert);
                                badCerts += 1;
                                continue;
                            }
                        } catch (PgpGeneralException e) {
                            log.add(LogType.MSG_KC_UAT_BAD_ERR, indent);
                            modified = PGPPublicKey.removeCertification(modified, userAttribute, zert);
                            badCerts += 1;
                            continue;
                        }

                        switch (type) {
                        case PGPSignature.DEFAULT_CERTIFICATION:
                        case PGPSignature.NO_CERTIFICATION:
                        case PGPSignature.CASUAL_CERTIFICATION:
                        case PGPSignature.POSITIVE_CERTIFICATION:
                            if (selfCert == null) {
                                selfCert = zert;
                            } else if (selfCert.getCreationTime().before(cert.getCreationTime())) {
                                log.add(LogType.MSG_KC_UAT_CERT_DUP, indent);
                                modified = PGPPublicKey.removeCertification(modified, userAttribute, selfCert);
                                redundantCerts += 1;
                                selfCert = zert;
                            } else {
                                log.add(LogType.MSG_KC_UAT_CERT_DUP, indent);
                                modified = PGPPublicKey.removeCertification(modified, userAttribute, zert);
                                redundantCerts += 1;
                            }
                            // If there is a revocation certificate, and it's older than this, drop it
                            if (revocation != null
                                    && revocation.getCreationTime().before(selfCert.getCreationTime())) {
                                log.add(LogType.MSG_KC_UAT_REVOKE_OLD, indent);
                                modified = PGPPublicKey.removeCertification(modified, userAttribute,
                                        revocation);
                                revocation = null;
                                redundantCerts += 1;
                            }
                            break;

                        case PGPSignature.CERTIFICATION_REVOCATION:
                            // If this is older than the (latest) self cert, drop it
                            if (selfCert != null && selfCert.getCreationTime().after(zert.getCreationTime())) {
                                log.add(LogType.MSG_KC_UAT_REVOKE_OLD, indent);
                                modified = PGPPublicKey.removeCertification(modified, userAttribute, zert);
                                redundantCerts += 1;
                                continue;
                            }
                            // first revocation? remember it.
                            if (revocation == null) {
                                revocation = zert;
                                // more revocations? at least one is superfluous, then.
                            } else if (revocation.getCreationTime().before(cert.getCreationTime())) {
                                log.add(LogType.MSG_KC_UAT_REVOKE_DUP, indent);
                                modified = PGPPublicKey.removeCertification(modified, userAttribute,
                                        revocation);
                                redundantCerts += 1;
                                revocation = zert;
                            } else {
                                log.add(LogType.MSG_KC_UAT_REVOKE_DUP, indent);
                                modified = PGPPublicKey.removeCertification(modified, userAttribute, zert);
                                redundantCerts += 1;
                            }
                            break;
                        }
                    }
                }

                // If no valid certificate (if only a revocation) remains, drop it
                if (selfCert == null && revocation == null) {
                    log.add(LogType.MSG_KC_UAT_REMOVE, indent);
                    modified = PGPPublicKey.removeCertification(modified, userAttribute);
                }

            } finally {
                indent -= 1;
            }
        }

        // Replace modified key in the keyring
        ring = replacePublicKey(ring, modified);
        indent -= 1;

    }

    // Keep track of ids we encountered so far
    Set<Long> knownIds = new HashSet<>();

    // Process all keys
    for (PGPPublicKey key : new IterableIterator<PGPPublicKey>(ring.getPublicKeys())) {
        // Make sure this is not a duplicate, avoid undefined behavior!
        if (knownIds.contains(key.getKeyID())) {
            log.add(LogType.MSG_KC_ERROR_DUP_KEY, indent, KeyFormattingUtils.convertKeyIdToHex(key.getKeyID()));
            return null;
        }
        // Add the key id to known
        knownIds.add(key.getKeyID());

        // Don't care about the master key any further, that one gets special treatment above
        if (key.isMasterKey()) {
            continue;
        }

        log.add(LogType.MSG_KC_SUB, indent, KeyFormattingUtils.convertKeyIdToHex(key.getKeyID()));
        indent += 1;

        if (Arrays.binarySearch(KNOWN_ALGORITHMS, key.getAlgorithm()) < 0) {
            ring = removeSubKey(ring, key);

            log.add(LogType.MSG_KC_SUB_UNKNOWN_ALGO, indent, Integer.toString(key.getAlgorithm()));
            indent -= 1;
            continue;
        }

        Date keyCreationTime = key.getCreationTime(), keyCreationTimeLenient;
        {
            Calendar keyCreationCal = Calendar.getInstance();
            keyCreationCal.setTime(keyCreationTime);
            // allow for diverging clocks up to one day when checking creation time
            keyCreationCal.add(Calendar.MINUTE, -5);
            keyCreationTimeLenient = keyCreationCal.getTime();
        }

        // A subkey needs exactly one subkey binding certificate, and optionally one revocation
        // certificate.
        PGPPublicKey modified = key;
        PGPSignature selfCert = null, revocation = null;
        uids: for (PGPSignature zert : new IterableIterator<PGPSignature>(key.getSignatures())) {
            // remove from keyring (for now)
            modified = PGPPublicKey.removeCertification(modified, zert);

            WrappedSignature cert = new WrappedSignature(zert);
            int type = cert.getSignatureType();

            // filter out bad key types...
            if (cert.getKeyId() != masterKey.getKeyID()) {
                log.add(LogType.MSG_KC_SUB_BAD_KEYID, indent);
                badCerts += 1;
                continue;
            }

            if (type != PGPSignature.SUBKEY_BINDING && type != PGPSignature.SUBKEY_REVOCATION) {
                log.add(LogType.MSG_KC_SUB_BAD_TYPE, indent, "0x" + Integer.toString(type, 16));
                badCerts += 1;
                continue;
            }

            if (cert.getCreationTime().after(nowPlusOneDay)) {
                // Creation date in the future? No way!
                log.add(LogType.MSG_KC_SUB_BAD_TIME, indent);
                badCerts += 1;
                continue;
            }

            if (cert.getCreationTime().before(keyCreationTime)) {
                // Signature is earlier than key creation time
                log.add(LogType.MSG_KC_SUB_BAD_TIME_EARLY, indent);
                // due to an earlier accident, we generated keys which had creation timestamps
                // a few seconds after their signature timestamp. for compatibility, we only
                // error out with some margin of error
                if (cert.getCreationTime().before(keyCreationTimeLenient)) {
                    badCerts += 1;
                    continue;
                }
            }

            if (cert.isLocal()) {
                // Creation date in the future? No way!
                log.add(LogType.MSG_KC_SUB_BAD_LOCAL, indent);
                badCerts += 1;
                continue;
            }

            if (type == PGPSignature.SUBKEY_BINDING) {

                // make sure the certificate checks out
                try {
                    cert.init(masterKey);
                    if (!cert.verifySignature(masterKey, key)) {
                        log.add(LogType.MSG_KC_SUB_BAD, indent);
                        badCerts += 1;
                        continue;
                    }
                } catch (PgpGeneralException e) {
                    log.add(LogType.MSG_KC_SUB_BAD_ERR, indent);
                    badCerts += 1;
                    continue;
                }

                boolean needsPrimaryBinding = false;

                // If the algorithm is even suitable for signing
                if (isSigningAlgo(key.getAlgorithm())) {

                    // If this certificate says it allows signing for the key
                    if (zert.getHashedSubPackets() != null
                            && zert.getHashedSubPackets().hasSubpacket(SignatureSubpacketTags.KEY_FLAGS)) {
                        int flags = ((KeyFlags) zert.getHashedSubPackets()
                                .getSubpacket(SignatureSubpacketTags.KEY_FLAGS)).getFlags();
                        if ((flags & KeyFlags.SIGN_DATA) == KeyFlags.SIGN_DATA) {
                            needsPrimaryBinding = true;
                        }
                    } else {
                        // If there are no key flags, we STILL require this because the key can sign!
                        needsPrimaryBinding = true;
                    }

                }

                // If this key can sign, it MUST have a primary key binding certificate
                if (needsPrimaryBinding) {
                    boolean ok = false;
                    if (zert.getUnhashedSubPackets() != null)
                        try {
                            // Check all embedded signatures, if any of them fits
                            PGPSignatureList list = zert.getUnhashedSubPackets().getEmbeddedSignatures();
                            for (int i = 0; i < list.size(); i++) {
                                WrappedSignature subsig = new WrappedSignature(list.get(i));
                                if (subsig.getSignatureType() == PGPSignature.PRIMARYKEY_BINDING) {
                                    subsig.init(key);
                                    if (subsig.verifySignature(masterKey, key)) {
                                        ok = true;
                                    } else {
                                        log.add(LogType.MSG_KC_SUB_PRIMARY_BAD, indent);
                                        badCerts += 1;
                                        continue uids;
                                    }
                                }
                            }
                        } catch (Exception e) {
                            log.add(LogType.MSG_KC_SUB_PRIMARY_BAD_ERR, indent);
                            badCerts += 1;
                            continue;
                        }
                    // if it doesn't, get rid of this!
                    if (!ok) {
                        log.add(LogType.MSG_KC_SUB_PRIMARY_NONE, indent);
                        badCerts += 1;
                        continue;
                    }
                }

                // if we already have a cert, and this one is older: skip it
                if (selfCert != null && cert.getCreationTime().before(selfCert.getCreationTime())) {
                    log.add(LogType.MSG_KC_SUB_DUP, indent);
                    redundantCerts += 1;
                    continue;
                }

                selfCert = zert;

                // it must be a revocation, then (we made sure above)
            } else {

                // make sure the certificate checks out
                try {
                    cert.init(masterKey);
                    if (!cert.verifySignature(masterKey, key)) {
                        log.add(LogType.MSG_KC_SUB_REVOKE_BAD, indent);
                        badCerts += 1;
                        continue;
                    }
                } catch (PgpGeneralException e) {
                    log.add(LogType.MSG_KC_SUB_REVOKE_BAD_ERR, indent);
                    badCerts += 1;
                    continue;
                }

                // If we already have a newer revocation cert, skip this one.
                if (revocation != null && revocation.getCreationTime().after(cert.getCreationTime())) {
                    log.add(LogType.MSG_KC_SUB_REVOKE_DUP, indent);
                    redundantCerts += 1;
                    continue;
                }

                revocation = zert;
            }
        }

        // it is not properly bound? error!
        if (selfCert == null) {
            ring = removeSubKey(ring, key);

            log.add(LogType.MSG_KC_SUB_NO_CERT, indent, KeyFormattingUtils.convertKeyIdToHex(key.getKeyID()));
            indent -= 1;
            continue;
        }

        // If we have flags, check if the algorithm supports all of them
        if (selfCert.getHashedSubPackets() != null
                && selfCert.getHashedSubPackets().hasSubpacket(SignatureSubpacketTags.KEY_FLAGS)) {
            int flags = ((KeyFlags) selfCert.getHashedSubPackets()
                    .getSubpacket(SignatureSubpacketTags.KEY_FLAGS)).getFlags();
            int algo = key.getAlgorithm();
            // If this is a signing key, but not a signing algorithm, warn the user
            if (!isSigningAlgo(algo) && (flags & KeyFlags.SIGN_DATA) == KeyFlags.SIGN_DATA) {
                log.add(LogType.MSG_KC_SUB_ALGO_BAD_SIGN, indent);
            }
            // If this is an encryption key, but not an encryption algorithm, warn the user
            if (!isEncryptionAlgo(algo) && ((flags & KeyFlags.ENCRYPT_STORAGE) == KeyFlags.ENCRYPT_STORAGE
                    || (flags & KeyFlags.ENCRYPT_COMMS) == KeyFlags.ENCRYPT_COMMS)) {
                log.add(LogType.MSG_KC_SUB_ALGO_BAD_ENCRYPT, indent);
            }
        }

        // re-add certification
        modified = PGPPublicKey.addCertification(modified, selfCert);
        // add revocation, if any
        if (revocation != null) {
            modified = PGPPublicKey.addCertification(modified, revocation);
        }
        // replace pubkey in keyring
        ring = replacePublicKey(ring, modified);
        indent -= 1;
    }

    if (badCerts > 0 && redundantCerts > 0) {
        // multi plural would make this complex, just leaving this as is...
        log.add(LogType.MSG_KC_SUCCESS_BAD_AND_RED, indent, Integer.toString(badCerts),
                Integer.toString(redundantCerts));
    } else if (badCerts > 0) {
        log.add(LogType.MSG_KC_SUCCESS_BAD, indent, badCerts);
    } else if (redundantCerts > 0) {
        log.add(LogType.MSG_KC_SUCCESS_REDUNDANT, indent, redundantCerts);
    } else {
        log.add(LogType.MSG_KC_SUCCESS, indent);
    }

    return isSecret() ? new CanonicalizedSecretKeyRing((PGPSecretKeyRing) ring, 1)
            : new CanonicalizedPublicKeyRing((PGPPublicKeyRing) ring, 0);
}

From source file:org.sufficientlysecure.keychain.pgp.UncachedKeyringCanonicalizeTest.java

License:Open Source License

@Test
public void testSubkeyBindingNoPKB() throws Exception {

    UncachedPublicKey pKey = KeyringTestingHelper.getNth(ring.getPublicKeys(), 1);
    PGPSignature sig;/*  w w w.java2 s  .  co  m*/

    subHashedPacketsGen.setKeyFlags(false, KeyFlags.SIGN_DATA);

    {
        // forge a (newer) signature, which has the sign flag but no primary key binding sig
        PGPSignatureSubpacketGenerator unhashedSubs = new PGPSignatureSubpacketGenerator();

        // just add any random signature, because why not
        unhashedSubs.setEmbeddedSignature(false, forgeSignature(secretKey, PGPSignature.POSITIVE_CERTIFICATION,
                subHashedPacketsGen, secretKey.getPublicKey()));

        sig = forgeSignature(secretKey, PGPSignature.SUBKEY_BINDING, subHashedPacketsGen, unhashedSubs,
                secretKey.getPublicKey(), pKey.getPublicKey());

        // inject in the right position
        UncachedKeyRing modified = KeyringTestingHelper.injectPacket(ring, sig.getEncoded(), 8);

        // canonicalize, and check if we lose the bad signature
        CanonicalizedKeyRing canonicalized = modified.canonicalize(log, 0);
        Assert.assertFalse("subkey binding signature should be gone after canonicalization",
                KeyringTestingHelper.diffKeyrings(ring.getEncoded(), canonicalized.getEncoded(), onlyA, onlyB));
    }

    { // now try one with a /bad/ primary key binding signature

        PGPSignatureSubpacketGenerator unhashedSubs = new PGPSignatureSubpacketGenerator();
        // this one is signed by the primary key itself, not the subkey - but it IS primary binding
        unhashedSubs.setEmbeddedSignature(false, forgeSignature(secretKey, PGPSignature.PRIMARYKEY_BINDING,
                subHashedPacketsGen, secretKey.getPublicKey(), pKey.getPublicKey()));

        sig = forgeSignature(secretKey, PGPSignature.SUBKEY_BINDING, subHashedPacketsGen, unhashedSubs,
                secretKey.getPublicKey(), pKey.getPublicKey());

        // inject in the right position
        UncachedKeyRing modified = KeyringTestingHelper.injectPacket(ring, sig.getEncoded(), 8);

        // canonicalize, and check if we lose the bad signature
        CanonicalizedKeyRing canonicalized = modified.canonicalize(log, 0);
        Assert.assertFalse("subkey binding signature should be gone after canonicalization",
                KeyringTestingHelper.diffKeyrings(ring.getEncoded(), canonicalized.getEncoded(), onlyA, onlyB));
    }

}

From source file:org.sufficientlysecure.keychain.pgp.UncachedKeyringCanonicalizeTest.java

License:Open Source License

@Test
public void testSubkeyBindingRedundant() throws Exception {

    UncachedPublicKey pKey = KeyringTestingHelper.getNth(ring.getPublicKeys(), 2);

    subHashedPacketsGen.setKeyFlags(false, KeyFlags.ENCRYPT_COMMS);
    PGPSignature sig2 = forgeSignature(secretKey, PGPSignature.SUBKEY_BINDING, subHashedPacketsGen,
            secretKey.getPublicKey(), pKey.getPublicKey());

    subHashedPacketsGen.setSignatureCreationTime(false, new Date(new Date().getTime() - 1000 * 1000));
    PGPSignature sig1 = forgeSignature(secretKey, PGPSignature.SUBKEY_REVOCATION, subHashedPacketsGen,
            secretKey.getPublicKey(), pKey.getPublicKey());

    subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
    subHashedPacketsGen.setSignatureCreationTime(false, new Date(new Date().getTime() - 100 * 1000));
    PGPSignature sig3 = forgeSignature(secretKey, PGPSignature.SUBKEY_BINDING, subHashedPacketsGen,
            secretKey.getPublicKey(), pKey.getPublicKey());

    UncachedKeyRing modified = KeyringTestingHelper.injectPacket(ring, sig1.getEncoded(), 10);
    modified = KeyringTestingHelper.injectPacket(modified, sig2.getEncoded(), 11);
    modified = KeyringTestingHelper.injectPacket(modified, sig1.getEncoded(), 12);
    modified = KeyringTestingHelper.injectPacket(modified, sig3.getEncoded(), 13);

    // canonicalize, and check if we lose the bad signature
    CanonicalizedKeyRing canonicalized = modified.canonicalize(log, 0);
    Assert.assertTrue("subkey binding signature should be gone after canonicalization",
            KeyringTestingHelper.diffKeyrings(modified.getEncoded(), canonicalized.getEncoded(), onlyA, onlyB));

    Assert.assertEquals("canonicalized keyring should have lost two packets", 3, onlyA.size());
    Assert.assertEquals("canonicalized keyring should have no extra packets", 0, onlyB.size());

    Assert.assertEquals("first missing packet should be the subkey", PacketTags.SIGNATURE, onlyA.get(0).tag);
    Assert.assertEquals("second missing packet should be a signature", PacketTags.SIGNATURE, onlyA.get(1).tag);
    Assert.assertEquals("second missing packet should be a signature", PacketTags.SIGNATURE, onlyA.get(2).tag);

}

From source file:org.sufficientlysecure.keychain.pgp.UncachedPublicKey.java

License:Open Source License

/** Get all key usage flags.
 * If at least one key flag subpacket is present return these. If no
 * subpacket is present it returns null.
 *
 * Note that this method has package visiblity because it is used in test
 * cases. Certificates of UncachedPublicKey instances can NOT be assumed to
 * be verified or even by the correct key, so the result of this method
 * should never be used in other places!
 *//*from   www. ja  v a 2 s .c om*/
@SuppressWarnings("unchecked")
Integer getKeyUsage() {
    if (mCacheUsage == null) {
        PGPSignature mostRecentSig = null;
        for (PGPSignature sig : new IterableIterator<PGPSignature>(mPublicKey.getSignatures())) {
            if (mPublicKey.isMasterKey() && sig.getKeyID() != mPublicKey.getKeyID()) {
                continue;
            }

            switch (sig.getSignatureType()) {
            case PGPSignature.DEFAULT_CERTIFICATION:
            case PGPSignature.POSITIVE_CERTIFICATION:
            case PGPSignature.CASUAL_CERTIFICATION:
            case PGPSignature.NO_CERTIFICATION:
            case PGPSignature.SUBKEY_BINDING:
                break;
            // if this is not one of the above types, don't care
            default:
                continue;
            }

            // If we have no sig yet, take the first we can get
            if (mostRecentSig == null) {
                mostRecentSig = sig;
                continue;
            }

            // If the new sig is less recent, skip it
            if (mostRecentSig.getCreationTime().after(sig.getCreationTime())) {
                continue;
            }

            // Otherwise, note it down as the new "most recent" one
            mostRecentSig = sig;
        }

        // Initialize to 0 as cached but empty value, if there is no sig (can't happen
        // for canonicalized keyring), or there is no KEY_FLAGS packet in the sig
        mCacheUsage = 0;
        if (mostRecentSig != null) {
            // If a mostRecentSig has been found, (cache and) return its flags
            PGPSignatureSubpacketVector hashed = mostRecentSig.getHashedSubPackets();
            if (hashed != null && hashed.getSubpacket(SignatureSubpacketTags.KEY_FLAGS) != null) {
                mCacheUsage = hashed.getKeyFlags();
            }
        }

    }
    return mCacheUsage;
}

From source file:org.sufficientlysecure.keychain.support.KeyringBuilder.java

License:Open Source License

private static SignaturePacket createSubkeySignaturePacket() {
    int signatureType = PGPSignature.SUBKEY_BINDING;
    int keyAlgorithm = SignaturePacket.RSA_GENERAL;
    int hashAlgorithm = HashAlgorithmTags.SHA1;

    SignatureSubpacket[] hashedData = new SignatureSubpacket[] {
            new SignatureCreationTime(false, SIGNATURE_DATE),
            new KeyFlags(false, KeyFlags.ENCRYPT_COMMS + KeyFlags.ENCRYPT_STORAGE),
            new KeyExpirationTime(false, TimeUnit.DAYS.toSeconds(2)), };
    SignatureSubpacket[] unhashedData = new SignatureSubpacket[] {
            new IssuerKeyID(false, false, KEY_ID.toByteArray()) };
    byte[] fingerPrint = new BigInteger("234a", 16).toByteArray();
    MPInteger[] signature = new MPInteger[] { new MPInteger(CORRECT_SUBKEY_SIGNATURE) };
    return new SignaturePacket(signatureType, KEY_ID.longValue(), keyAlgorithm, hashAlgorithm, hashedData,
            unhashedData, fingerPrint, signature);
}