Example usage for org.bouncycastle.openpgp PGPSignature getCreationTime

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

Introduction

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

Prototype

public Date getCreationTime() 

Source Link

Document

Return the creation time of the signature.

Usage

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

License:Apache License

private static final void maybeAddUserID(List<UserID> uids, PGPPublicKey pk, String uid, StringBuilder errors)
        throws PGPException, SignatureException, IOException {

    Iterator<PGPSignature> sigit = Util.getTypedIterator(pk.getSignaturesForID(uid), PGPSignature.class);
    if (sigit == null) {
        errors.append(// w  w  w  . j  av a  2 s  .com
                "Reject name '" + uid + "' for " + nicePk(pk) + " because no self-signatures were found.\n");
        return;
    }

    // Select the most recent valid signature.
    PGPSignature validSig = null;
    long validTs = -1L;

    while (sigit.hasNext()) {
        PGPSignature sig = sigit.next();

        switch (sig.getSignatureType()) {
        case PGPSignature.DEFAULT_CERTIFICATION:
        case PGPSignature.NO_CERTIFICATION:
        case PGPSignature.CASUAL_CERTIFICATION:
        case PGPSignature.POSITIVE_CERTIFICATION:
        case PGPSignature.CERTIFICATION_REVOCATION:
            if (isGoodUIDSignature(sig, pk, uid, errors)) {
                long ts = sig.getCreationTime().getTime();
                if (ts > validTs) {
                    validTs = ts;
                    validSig = sig;
                }
            }
            break;

        default:
            break;
        }
    }

    if (validSig == null) {
        errors.append("Name '" + uid + "' rejected because no self-signatures were found.\n");
        return;
    }

    if (validSig.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION) {
        errors.append("Name '" + uid + "' rejected because it was revoked.\n");
        return;
    }

    // Add UID information.
    uids.add(new UserID(uid, validSig));
}

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

License:Apache License

private static final long getSignatureTimestamp(PGPSignature sig, StringBuilder errors) {
    long ts = sig.getCreationTime().getTime();
    // Work-around bouncycastle not indicating lack of timestamp as a
    // hashed subpacket.
    if (sig.getVersion() == 4) {
        // Make sure we actually have a timestamp packet in
        // the hashed section.
        PGPSignatureSubpacketVector svec = sig.getHashedSubPackets();
        if (svec == null) {
            errors.append(niceSig(sig) + " is missing a creation timestamp.\n");
            return -1L;
        }/*from ww w  .  j  a va  2s .  c  o  m*/
        SignatureCreationTime tspack = (SignatureCreationTime) svec
                .getSubpacket(SignatureSubpacketTags.CREATION_TIME);
        if (tspack == null) {
            errors.append(niceSig(sig) + " is missing a creation timestamp.\n");
            return -1L;
        }
        ts = tspack.getTime().getTime();
    }
    return ts;
}

From source file:org.kontalk.xmppserver.pgp.PGPUtils.java

License:Open Source License

public static boolean findValidRevocationSignature(PGPPublicKey key) throws PGPException {
    PGPSignature valid = null;

    @SuppressWarnings("unchecked")
    Iterator<PGPSignature> sigs = key.getSignaturesOfType(PGPSignature.KEY_REVOCATION);
    while (sigs != null && sigs.hasNext()) {
        PGPSignature sig = sigs.next();//from   w  w w .j a v  a  2  s.  c o m
        if (sig.getKeyID() == key.getKeyID() && verifyKeySignature(key, sig)) {
            if (valid == null || valid.getCreationTime().before(sig.getCreationTime()))
                valid = sig;
            // TODO else if (sig.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION) ...
        }
    }

    return valid != null;
}

From source file:org.kontalk.xmppserver.pgp.PGPUtils.java

License:Open Source License

public static boolean findValidKeySignature(PGPPublicKey key, String uid, PGPPublicKey signerKey)
        throws PGPException {
    PGPSignature valid = null;
    long keyId = signerKey.getKeyID();

    @SuppressWarnings("unchecked")
    Iterator<PGPSignature> sigs = key.getSignaturesForID(uid);
    while (sigs != null && sigs.hasNext()) {
        PGPSignature sig = sigs.next();/*w  w  w  .  j a v a2 s. c om*/
        if (sig.getKeyID() == keyId && verifyUidSignature(key, sig, signerKey, uid)) {
            if (sig.getSignatureType() == PGPSignature.DEFAULT_CERTIFICATION
                    || sig.getSignatureType() == PGPSignature.CASUAL_CERTIFICATION) {
                if (valid == null || valid.getCreationTime().before(sig.getCreationTime()))
                    valid = sig;
            }
            // TODO else if (sig.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION) ...
        }
    }

    return valid != null;
}

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

License:Open Source License

/** "Canonicalizes" a public key, removing inconsistencies in the process.
 *
 * More specifically:/*from w  ww. j a va2  s . co 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.UncachedPublicKey.java

License:Open Source License

/** Returns the primary user id, as indicated by the public key's self certificates.
 *
 * This is an expensive operation, since potentially a lot of certificates (and revocations)
 * have to be checked, and even then the result is NOT guaranteed to be constant through a
 * canonicalization operation./*from w  w  w.  j av a 2  s . com*/
 *
 * Returns null if there is no primary user id (as indicated by certificates)
 *
 */
public String getPrimaryUserId() {
    byte[] found = null;
    PGPSignature foundSig = null;
    // noinspection unchecked
    for (byte[] rawUserId : new IterableIterator<byte[]>(mPublicKey.getRawUserIDs())) {
        PGPSignature revocation = null;

        @SuppressWarnings("unchecked")
        Iterator<PGPSignature> signaturesIt = mPublicKey.getSignaturesForID(rawUserId);
        // no signatures for this User ID
        if (signaturesIt == null) {
            continue;
        }

        for (PGPSignature sig : new IterableIterator<>(signaturesIt)) {
            try {

                // if this is a revocation, this is not the user id
                if (sig.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION) {
                    // make sure it's actually valid
                    sig.init(new JcaPGPContentVerifierBuilderProvider()
                            .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME), mPublicKey);
                    if (!sig.verifyCertification(rawUserId, mPublicKey)) {
                        continue;
                    }
                    if (found != null && Arrays.equals(found, rawUserId)) {
                        found = null;
                    }
                    revocation = sig;
                    // this revocation may still be overridden by a newer cert
                    continue;
                }

                if (sig.getHashedSubPackets() != null && sig.getHashedSubPackets().isPrimaryUserID()) {
                    if (foundSig != null && sig.getCreationTime().before(foundSig.getCreationTime())) {
                        continue;
                    }
                    // ignore if there is a newer revocation for this user id
                    if (revocation != null && sig.getCreationTime().before(revocation.getCreationTime())) {
                        continue;
                    }
                    // make sure it's actually valid
                    sig.init(new JcaPGPContentVerifierBuilderProvider()
                            .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME), mPublicKey);
                    if (sig.verifyCertification(rawUserId, mPublicKey)) {
                        found = rawUserId;
                        foundSig = sig;
                        // this one can't be relevant anymore at this point
                        revocation = null;
                    }
                }

            } catch (Exception e) {
                // nothing bad happens, the key is just not considered the primary key id
            }
        }
    }
    if (found != null) {
        return Utf8Util.fromUTF8ByteArrayReplaceBadEncoding(found);
    } else {
        return null;
    }
}

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   ww w  . j av a2  s.c o m*/
@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;
}