Example usage for org.bouncycastle.openpgp PGPSignature getSignatureType

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

Introduction

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

Prototype

public int getSignatureType() 

Source Link

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(//from  w w w.jav a2s  .  co m
                "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 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;/*from w ww  .j  a v  a2 s  .  co  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:com.google.e2e.bcdriver.KeyChecker.java

License:Apache License

private static final String niceSig(PGPSignature sig) {
    return "signature (type=0x" + Integer.toHexString(sig.getSignatureType()) + ") issued by keyid 0x"
            + Long.toHexString(sig.getKeyID());
}

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

License:Apache License

private static final boolean isGoodDirectSignature(PGPSignature sig, PGPPublicKey signer, PGPPublicKey target,
        StringBuilder errors) throws PGPException, SignatureException, IOException {

    sig.init(new BcPGPContentVerifierBuilderProvider(), signer);

    boolean ok;//from w  w w.  j  a va 2  s.c om

    // There's a bug that prevents sig.verifyCertification(signer)
    // working for DIRECT_KEY signatures.
    //
    // So, re-implement the code again here.
    if (sig.getSignatureType() == PGPSignature.DIRECT_KEY) {
        byte[] bytes = target.getPublicKeyPacket().getEncodedContents();
        sig.update((byte) 0x99);
        sig.update((byte) (bytes.length >> 8));
        sig.update((byte) (bytes.length));
        sig.update(bytes);
        ok = sig.verify();
    } else {
        ok = sig.verifyCertification(target);
    }

    // If we have a good signature, also ensure the signature
    // hasn't expired.
    return ok && isSignatureCurrent(sig, errors);
}

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

License:Apache License

private static final boolean isGoodBackSignature(PGPSignature sig, PGPPublicKey signer, PGPPublicKey target,
        StringBuilder errors) throws PGPException, SignatureException, IOException {

    SignatureSubpacket esigpack = null;//  w  w w.j ava  2s. co  m

    // Prefer to get it from the hashed subpacket.
    PGPSignatureSubpacketVector svec = sig.getHashedSubPackets();
    if (svec != null) {
        esigpack = svec.getSubpacket(SignatureSubpacketTags.EMBEDDED_SIGNATURE);
    }

    if (esigpack == null) {
        svec = sig.getUnhashedSubPackets();
        if (svec != null) {
            esigpack = svec.getSubpacket(SignatureSubpacketTags.EMBEDDED_SIGNATURE);
        }
    }

    if (esigpack == null) {
        errors.append("Rejecting " + niceSig(sig) + " for subkey " + nicePk(target)
                + " because it doesn't have a cross-certification.\n"
                + "See https://www.gnupg.org/faq/subkey-cross-certify.html\n");
        return false;
    }

    // Unfortunately, since PGPSignature(byte[]) is not public, we
    // have to go through this ugly contortion to get a signature.

    ByteArrayOutputStream baout = new ByteArrayOutputStream();
    // dump out an old-style header.
    int hdr = 0x80 | (PacketTags.SIGNATURE << 2);
    int len = esigpack.getData().length;
    if (len <= 0xff) {
        baout.write(hdr);
        baout.write(len);
    } else if (len <= 0xffff) {
        baout.write(hdr | 0x01);
        baout.write((len >> 8) & 0xff);
        baout.write(len & 0xff);
    } else {
        baout.write(hdr | 0x02);
        baout.write((len >> 24) & 0xff);
        baout.write((len >> 16) & 0xff);
        baout.write((len >> 8) & 0xff);
        baout.write(len & 0xff);
    }

    baout.write(esigpack.getData());
    baout.close();

    PGPObjectFactory fact = new PGPObjectFactory(new ByteArrayInputStream(baout.toByteArray()),
            new BcKeyFingerprintCalculator());

    Object obj = fact.nextObject();

    if (!(obj instanceof PGPSignatureList)) {
        errors.append("Rejecting " + niceSig(sig) + " for subkey " + nicePk(target)
                + " because no usable embedded signature is available.\n");
        return false;
    }
    PGPSignatureList esiglist = (PGPSignatureList) obj;
    if (esiglist.size() != 1) {
        errors.append("Rejecting " + niceSig(sig) + " for subkey " + nicePk(target)
                + " because no usable embedded signature is available.\n");
        return false;
    }

    PGPSignature esig = esiglist.get(0);
    if (esig.getSignatureType() != PGPSignature.PRIMARYKEY_BINDING) {
        errors.append("Rejecting " + niceSig(sig) + " for subkey " + nicePk(target) + " because the embedded "
                + niceSig(esig) + " is not a proper backsignature.\n");
        return false;
    }

    esig.init(new BcPGPContentVerifierBuilderProvider(), target);

    return esig.verifyCertification(signer, target) && isSignatureCurrent(esig, errors);
}

From source file:com.google.gerrit.gpg.GerritPublicKeyChecker.java

License:Apache License

private static boolean isValidCertification(PGPPublicKey key, PGPSignature sig, String userId)
        throws PGPException {
    if (sig.getSignatureType() != PGPSignature.DEFAULT_CERTIFICATION
            && sig.getSignatureType() != PGPSignature.POSITIVE_CERTIFICATION) {
        return false;
    }//w  ww  .  ja va  2 s.  c  o m
    if (sig.getKeyID() != key.getKeyID()) {
        return false;
    }
    // TODO(dborowitz): Handle certification revocations:
    // - Is there a revocation by either this key or another key trusted by the
    //   server?
    // - Does such a revocation postdate all other valid certifications?

    sig.init(new BcPGPContentVerifierBuilderProvider(), key);
    return sig.verifyCertification(userId, key);
}

From source file:com.google.gerrit.gpg.PublicKeyChecker.java

License:Apache License

private CheckResult checkWebOfTrust(PGPPublicKey key, PublicKeyStore store, int depth, Set<Fingerprint> seen) {
    if (trusted == null || store == null) {
        return CheckResult.OK; // Trust checking not configured.
    }//from w  w  w  . java2 s  .  co m
    Fingerprint fp = new Fingerprint(key.getFingerprint());
    if (seen.contains(fp)) {
        return new CheckResult("Key is trusted in a cycle");
    }
    seen.add(fp);

    Fingerprint trustedFp = trusted.get(key.getKeyID());
    if (trustedFp != null && trustedFp.equals(fp)) {
        return CheckResult.OK; // Directly trusted.
    } else if (depth >= maxTrustDepth) {
        return new CheckResult("No path of depth <= " + maxTrustDepth + " to a trusted key");
    }

    List<CheckResult> signerResults = new ArrayList<>();
    @SuppressWarnings("unchecked")
    Iterator<String> userIds = key.getUserIDs();
    while (userIds.hasNext()) {
        String userId = userIds.next();
        @SuppressWarnings("unchecked")
        Iterator<PGPSignature> sigs = key.getSignaturesForID(userId);
        while (sigs.hasNext()) {
            PGPSignature sig = sigs.next();
            // TODO(dborowitz): Handle CERTIFICATION_REVOCATION.
            if (sig.getSignatureType() != PGPSignature.DEFAULT_CERTIFICATION
                    && sig.getSignatureType() != PGPSignature.POSITIVE_CERTIFICATION) {
                continue; // Not a certification.
            }

            PGPPublicKey signer = getSigner(store, sig, userId, key, signerResults);
            // TODO(dborowitz): Require self certification.
            if (signer == null || Arrays.equals(signer.getFingerprint(), key.getFingerprint())) {
                continue;
            }
            CheckResult signerResult = checkTrustSubpacket(sig, depth);
            if (signerResult.isOk()) {
                signerResult = check(signer, store, depth + 1, false, seen);
                if (signerResult.isOk()) {
                    return CheckResult.OK;
                }
            }
            signerResults.add(new CheckResult(
                    "Certification by " + keyToString(signer) + " is valid, but key is not trusted"));
        }
    }

    List<String> problems = new ArrayList<>();
    problems.add("No path to a trusted key");
    for (CheckResult signerResult : signerResults) {
        problems.addAll(signerResult.getProblems());
    }
    return new CheckResult(problems);
}

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;/*from  w  ww .  j a  v  a  2 s  .  co  m*/
    long keyId = signerKey.getKeyID();

    @SuppressWarnings("unchecked")
    Iterator<PGPSignature> sigs = key.getSignaturesForID(uid);
    while (sigs != null && sigs.hasNext()) {
        PGPSignature sig = sigs.next();
        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.PgpKeyOperation.java

License:Open Source License

private PgpEditKeyResult internal(PGPSecretKeyRing sKR, PGPSecretKey masterSecretKey, int masterKeyFlags,
        long masterKeyExpiry, CryptoInputParcel cryptoInput, SaveKeyringParcel saveParcel, OperationLog log,
        int indent) {

    SecurityTokenSignOperationsBuilder nfcSignOps = new SecurityTokenSignOperationsBuilder(
            cryptoInput.getSignatureTime(), masterSecretKey.getKeyID(), masterSecretKey.getKeyID());
    SecurityTokenKeyToCardOperationsBuilder nfcKeyToCardOps = new SecurityTokenKeyToCardOperationsBuilder(
            masterSecretKey.getKeyID());

    progress(R.string.progress_modify, 0);

    PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey();

    PGPPrivateKey masterPrivateKey;//  ww  w .ja va 2s  . co m

    if (isDivertToCard(masterSecretKey)) {
        masterPrivateKey = null;
        log.add(LogType.MSG_MF_DIVERT, indent);
    } else {

        // 1. Unlock private key
        progress(R.string.progress_modify_unlock, 10);
        log.add(LogType.MSG_MF_UNLOCK, indent);
        {
            try {
                PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
                        .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME)
                        .build(cryptoInput.getPassphrase().getCharArray());
                masterPrivateKey = masterSecretKey.extractPrivateKey(keyDecryptor);
            } catch (PGPException e) {
                log.add(LogType.MSG_MF_UNLOCK_ERROR, indent + 1);
                return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
            }
        }
    }

    try {

        // Check if we were cancelled
        if (checkCancelled()) {
            log.add(LogType.MSG_OPERATION_CANCELLED, indent);
            return new PgpEditKeyResult(PgpEditKeyResult.RESULT_CANCELLED, log, null);
        }

        { // work on master secret key

            PGPPublicKey modifiedPublicKey = masterPublicKey;

            // 2a. Add certificates for new user ids
            subProgressPush(15, 23);
            for (int i = 0; i < saveParcel.mAddUserIds.size(); i++) {

                progress(R.string.progress_modify_adduid, (i - 1) * (100 / saveParcel.mAddUserIds.size()));
                String userId = saveParcel.mAddUserIds.get(i);
                log.add(LogType.MSG_MF_UID_ADD, indent, userId);

                if ("".equals(userId)) {
                    log.add(LogType.MSG_MF_UID_ERROR_EMPTY, indent + 1);
                    return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
                }

                // this operation supersedes all previous binding and revocation certificates,
                // so remove those to retain assertions from canonicalization for later operations
                @SuppressWarnings("unchecked")
                Iterator<PGPSignature> it = modifiedPublicKey.getSignaturesForID(userId);
                if (it != null) {
                    for (PGPSignature cert : new IterableIterator<>(it)) {
                        if (cert.getKeyID() != masterPublicKey.getKeyID()) {
                            // foreign certificate?! error error error
                            log.add(LogType.MSG_MF_ERROR_INTEGRITY, indent);
                            return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
                        }
                        if (cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION
                                || cert.getSignatureType() == PGPSignature.NO_CERTIFICATION
                                || cert.getSignatureType() == PGPSignature.CASUAL_CERTIFICATION
                                || cert.getSignatureType() == PGPSignature.POSITIVE_CERTIFICATION
                                || cert.getSignatureType() == PGPSignature.DEFAULT_CERTIFICATION) {
                            modifiedPublicKey = PGPPublicKey.removeCertification(modifiedPublicKey, userId,
                                    cert);
                        }
                    }
                }

                // if it's supposed to be primary, we can do that here as well
                boolean isPrimary = saveParcel.mChangePrimaryUserId != null
                        && userId.equals(saveParcel.mChangePrimaryUserId);
                // generate and add new certificate
                try {
                    PGPSignature cert = generateUserIdSignature(
                            getSignatureGenerator(masterSecretKey, cryptoInput), cryptoInput.getSignatureTime(),
                            masterPrivateKey, masterPublicKey, userId, isPrimary, masterKeyFlags,
                            masterKeyExpiry);
                    modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
                } catch (NfcInteractionNeeded e) {
                    nfcSignOps.addHash(e.hashToSign, e.hashAlgo);
                }
            }
            subProgressPop();

            // 2b. Add certificates for new user ids
            subProgressPush(23, 32);
            for (int i = 0; i < saveParcel.mAddUserAttribute.size(); i++) {

                progress(R.string.progress_modify_adduat,
                        (i - 1) * (100 / saveParcel.mAddUserAttribute.size()));
                WrappedUserAttribute attribute = saveParcel.mAddUserAttribute.get(i);

                switch (attribute.getType()) {
                // the 'none' type must not succeed
                case WrappedUserAttribute.UAT_NONE:
                    log.add(LogType.MSG_MF_UAT_ERROR_EMPTY, indent);
                    return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
                case WrappedUserAttribute.UAT_IMAGE:
                    log.add(LogType.MSG_MF_UAT_ADD_IMAGE, indent);
                    break;
                default:
                    log.add(LogType.MSG_MF_UAT_ADD_UNKNOWN, indent);
                    break;
                }

                PGPUserAttributeSubpacketVector vector = attribute.getVector();

                // generate and add new certificate
                try {
                    PGPSignature cert = generateUserAttributeSignature(
                            getSignatureGenerator(masterSecretKey, cryptoInput), cryptoInput.getSignatureTime(),
                            masterPrivateKey, masterPublicKey, vector, masterKeyFlags, masterKeyExpiry);
                    modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, vector, cert);
                } catch (NfcInteractionNeeded e) {
                    nfcSignOps.addHash(e.hashToSign, e.hashAlgo);
                }
            }
            subProgressPop();

            // 2c. Add revocations for revoked user ids
            subProgressPush(32, 40);
            for (int i = 0; i < saveParcel.mRevokeUserIds.size(); i++) {

                progress(R.string.progress_modify_revokeuid,
                        (i - 1) * (100 / saveParcel.mRevokeUserIds.size()));
                String userId = saveParcel.mRevokeUserIds.get(i);
                log.add(LogType.MSG_MF_UID_REVOKE, indent, userId);

                // Make sure the user id exists (yes these are 10 LoC in Java!)
                boolean exists = false;
                //noinspection unchecked
                for (String uid : new IterableIterator<String>(modifiedPublicKey.getUserIDs())) {
                    if (userId.equals(uid)) {
                        exists = true;
                        break;
                    }
                }
                if (!exists) {
                    log.add(LogType.MSG_MF_ERROR_NOEXIST_REVOKE, indent);
                    return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
                }

                // a duplicate revocation will be removed during canonicalization, so no need to
                // take care of that here.
                try {
                    PGPSignature cert = generateRevocationSignature(
                            getSignatureGenerator(masterSecretKey, cryptoInput), cryptoInput.getSignatureTime(),
                            masterPrivateKey, masterPublicKey, userId);
                    modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
                } catch (NfcInteractionNeeded e) {
                    nfcSignOps.addHash(e.hashToSign, e.hashAlgo);
                }
            }
            subProgressPop();

            // 3. If primary user id changed, generate new certificates for both old and new
            if (saveParcel.mChangePrimaryUserId != null) {
                progress(R.string.progress_modify_primaryuid, 40);

                // keep track if we actually changed one
                boolean ok = false;
                log.add(LogType.MSG_MF_UID_PRIMARY, indent, saveParcel.mChangePrimaryUserId);
                indent += 1;

                // we work on the modifiedPublicKey here, to respect new or newly revoked uids
                // noinspection unchecked
                for (String userId : new IterableIterator<String>(modifiedPublicKey.getUserIDs())) {
                    boolean isRevoked = false;
                    PGPSignature currentCert = null;
                    // noinspection unchecked
                    for (PGPSignature cert : new IterableIterator<PGPSignature>(
                            modifiedPublicKey.getSignaturesForID(userId))) {
                        if (cert.getKeyID() != masterPublicKey.getKeyID()) {
                            // foreign certificate?! error error error
                            log.add(LogType.MSG_MF_ERROR_INTEGRITY, indent);
                            return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
                        }
                        // we know from canonicalization that if there is any revocation here, it
                        // is valid and not superseded by a newer certification.
                        if (cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION) {
                            isRevoked = true;
                            continue;
                        }
                        // we know from canonicalization that there is only one binding
                        // certification here, so we can just work with the first one.
                        if (cert.getSignatureType() == PGPSignature.NO_CERTIFICATION
                                || cert.getSignatureType() == PGPSignature.CASUAL_CERTIFICATION
                                || cert.getSignatureType() == PGPSignature.POSITIVE_CERTIFICATION
                                || cert.getSignatureType() == PGPSignature.DEFAULT_CERTIFICATION) {
                            currentCert = cert;
                        }
                    }

                    if (currentCert == null) {
                        // no certificate found?! error error error
                        log.add(LogType.MSG_MF_ERROR_INTEGRITY, indent);
                        return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
                    }

                    // we definitely should not update certifications of revoked keys, so just leave it.
                    if (isRevoked) {
                        // revoked user ids cannot be primary!
                        if (userId.equals(saveParcel.mChangePrimaryUserId)) {
                            log.add(LogType.MSG_MF_ERROR_REVOKED_PRIMARY, indent);
                            return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
                        }
                        continue;
                    }

                    // if this is~ the/a primary user id
                    if (currentCert.getHashedSubPackets() != null
                            && currentCert.getHashedSubPackets().isPrimaryUserID()) {
                        // if it's the one we want, just leave it as is
                        if (userId.equals(saveParcel.mChangePrimaryUserId)) {
                            ok = true;
                            continue;
                        }
                        // otherwise, generate new non-primary certification
                        log.add(LogType.MSG_MF_PRIMARY_REPLACE_OLD, indent);
                        modifiedPublicKey = PGPPublicKey.removeCertification(modifiedPublicKey, userId,
                                currentCert);
                        try {
                            PGPSignature newCert = generateUserIdSignature(
                                    getSignatureGenerator(masterSecretKey, cryptoInput),
                                    cryptoInput.getSignatureTime(), masterPrivateKey, masterPublicKey, userId,
                                    false, masterKeyFlags, masterKeyExpiry);
                            modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId,
                                    newCert);
                        } catch (NfcInteractionNeeded e) {
                            nfcSignOps.addHash(e.hashToSign, e.hashAlgo);
                        }

                        continue;
                    }

                    // if we are here, this is not currently a primary user id

                    // if it should be
                    if (userId.equals(saveParcel.mChangePrimaryUserId)) {
                        // add shiny new primary user id certificate
                        log.add(LogType.MSG_MF_PRIMARY_NEW, indent);
                        modifiedPublicKey = PGPPublicKey.removeCertification(modifiedPublicKey, userId,
                                currentCert);
                        try {
                            PGPSignature newCert = generateUserIdSignature(
                                    getSignatureGenerator(masterSecretKey, cryptoInput),
                                    cryptoInput.getSignatureTime(), masterPrivateKey, masterPublicKey, userId,
                                    true, masterKeyFlags, masterKeyExpiry);
                            modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId,
                                    newCert);
                        } catch (NfcInteractionNeeded e) {
                            nfcSignOps.addHash(e.hashToSign, e.hashAlgo);
                        }
                        ok = true;
                    }

                    // user id is not primary and is not supposed to be - nothing to do here.

                }

                indent -= 1;

                if (!ok) {
                    log.add(LogType.MSG_MF_ERROR_NOEXIST_PRIMARY, indent);
                    return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
                }
            }

            // Update the secret key ring
            if (modifiedPublicKey != masterPublicKey) {
                masterSecretKey = PGPSecretKey.replacePublicKey(masterSecretKey, modifiedPublicKey);
                masterPublicKey = modifiedPublicKey;
                sKR = PGPSecretKeyRing.insertSecretKey(sKR, masterSecretKey);
            }

        }

        // Check if we were cancelled - again
        if (checkCancelled()) {
            log.add(LogType.MSG_OPERATION_CANCELLED, indent);
            return new PgpEditKeyResult(PgpEditKeyResult.RESULT_CANCELLED, log, null);
        }

        // 4a. For each subkey change, generate new subkey binding certificate
        subProgressPush(50, 60);
        for (int i = 0; i < saveParcel.mChangeSubKeys.size(); i++) {

            progress(R.string.progress_modify_subkeychange, (i - 1) * (100 / saveParcel.mChangeSubKeys.size()));
            SaveKeyringParcel.SubkeyChange change = saveParcel.mChangeSubKeys.get(i);
            log.add(LogType.MSG_MF_SUBKEY_CHANGE, indent, KeyFormattingUtils.convertKeyIdToHex(change.mKeyId));

            PGPSecretKey sKey = sKR.getSecretKey(change.mKeyId);
            if (sKey == null) {
                log.add(LogType.MSG_MF_ERROR_SUBKEY_MISSING, indent + 1,
                        KeyFormattingUtils.convertKeyIdToHex(change.mKeyId));
                return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
            }

            if (change.mDummyStrip) {
                // IT'S DANGEROUS~
                // no really, it is. this operation irrevocably removes the private key data from the key
                sKey = PGPSecretKey.constructGnuDummyKey(sKey.getPublicKey());
                sKR = PGPSecretKeyRing.insertSecretKey(sKR, sKey);
            } else if (change.mMoveKeyToSecurityToken) {
                if (checkSecurityTokenCompatibility(sKey, log, indent + 1)) {
                    log.add(LogType.MSG_MF_KEYTOCARD_START, indent + 1,
                            KeyFormattingUtils.convertKeyIdToHex(change.mKeyId));
                    nfcKeyToCardOps.addSubkey(change.mKeyId);
                } else {
                    // Appropriate log message already set by checkSecurityTokenCompatibility
                    return new PgpEditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
                }
            } else if (change.mSecurityTokenSerialNo != null) {
                // NOTE: Does this code get executed? Or always handled in internalRestricted?
                if (change.mSecurityTokenSerialNo.length != 16) {
                    log.add(LogType.MSG_MF_ERROR_DIVERT_SERIAL, indent + 1,
                            KeyFormattingUtils.convertKeyIdToHex(change.mKeyId));
                    return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
                }
                log.add(LogType.MSG_MF_KEYTOCARD_FINISH, indent + 1,
                        KeyFormattingUtils.convertKeyIdToHex(change.mKeyId),
                        Hex.toHexString(change.mSecurityTokenSerialNo, 8, 6));
                sKey = PGPSecretKey.constructGnuDummyKey(sKey.getPublicKey(), change.mSecurityTokenSerialNo);
                sKR = PGPSecretKeyRing.insertSecretKey(sKR, sKey);
            }

            // This doesn't concern us any further
            if (!change.mRecertify && (change.mExpiry == null && change.mFlags == null)) {
                continue;
            }

            // expiry must not be in the past
            if (change.mExpiry != null && change.mExpiry != 0
                    && new Date(change.mExpiry * 1000).before(new Date())) {
                log.add(LogType.MSG_MF_ERROR_PAST_EXPIRY, indent + 1,
                        KeyFormattingUtils.convertKeyIdToHex(change.mKeyId));
                return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
            }

            // if this is the master key, update uid certificates instead
            if (change.mKeyId == masterPublicKey.getKeyID()) {
                int flags = change.mFlags == null ? masterKeyFlags : change.mFlags;
                long expiry = change.mExpiry == null ? masterKeyExpiry : change.mExpiry;

                if ((flags & KeyFlags.CERTIFY_OTHER) != KeyFlags.CERTIFY_OTHER) {
                    log.add(LogType.MSG_MF_ERROR_NO_CERTIFY, indent + 1);
                    return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
                }

                PGPPublicKey pKey = updateMasterCertificates(masterSecretKey, masterPrivateKey, masterPublicKey,
                        flags, expiry, cryptoInput, nfcSignOps, indent, log);
                if (pKey == null) {
                    // error log entry has already been added by updateMasterCertificates itself
                    return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
                }
                masterSecretKey = PGPSecretKey.replacePublicKey(sKey, pKey);
                masterPublicKey = pKey;
                sKR = PGPSecretKeyRing.insertSecretKey(sKR, masterSecretKey);
                continue;
            }

            // otherwise, continue working on the public key
            PGPPublicKey pKey = sKey.getPublicKey();

            // keep old flags, or replace with new ones
            int flags = change.mFlags == null ? readKeyFlags(pKey) : change.mFlags;
            long expiry;
            if (change.mExpiry == null) {
                long valid = pKey.getValidSeconds();
                expiry = valid == 0 ? 0 : pKey.getCreationTime().getTime() / 1000 + pKey.getValidSeconds();
            } else {
                expiry = change.mExpiry;
            }

            // drop all old signatures, they will be superseded by the new one
            //noinspection unchecked
            for (PGPSignature sig : new IterableIterator<PGPSignature>(pKey.getSignatures())) {
                // special case: if there is a revocation, don't use expiry from before
                if ((change.mExpiry == null || change.mExpiry == 0L)
                        && sig.getSignatureType() == PGPSignature.SUBKEY_REVOCATION) {
                    expiry = 0;
                }
                pKey = PGPPublicKey.removeCertification(pKey, sig);
            }

            PGPPrivateKey subPrivateKey;
            if (!isDivertToCard(sKey)) {
                PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
                        .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME)
                        .build(cryptoInput.getPassphrase().getCharArray());
                subPrivateKey = sKey.extractPrivateKey(keyDecryptor);
                // super special case: subkey is allowed to sign, but isn't available
                if (subPrivateKey == null) {
                    log.add(LogType.MSG_MF_ERROR_SUB_STRIPPED, indent + 1,
                            KeyFormattingUtils.convertKeyIdToHex(change.mKeyId));
                    return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
                }
            } else {
                subPrivateKey = null;
            }
            try {
                PGPSignature sig = generateSubkeyBindingSignature(
                        getSignatureGenerator(masterSecretKey, cryptoInput), cryptoInput.getSignatureTime(),
                        masterPublicKey, masterPrivateKey, getSignatureGenerator(sKey, cryptoInput),
                        subPrivateKey, pKey, flags, expiry);

                // generate and add new signature
                pKey = PGPPublicKey.addCertification(pKey, sig);
                sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
            } catch (NfcInteractionNeeded e) {
                nfcSignOps.addHash(e.hashToSign, e.hashAlgo);
            }

        }
        subProgressPop();

        // 4b. For each subkey revocation, generate new subkey revocation certificate
        subProgressPush(60, 65);
        for (int i = 0; i < saveParcel.mRevokeSubKeys.size(); i++) {

            progress(R.string.progress_modify_subkeyrevoke, (i - 1) * (100 / saveParcel.mRevokeSubKeys.size()));
            long revocation = saveParcel.mRevokeSubKeys.get(i);
            log.add(LogType.MSG_MF_SUBKEY_REVOKE, indent, KeyFormattingUtils.convertKeyIdToHex(revocation));

            PGPSecretKey sKey = sKR.getSecretKey(revocation);
            if (sKey == null) {
                log.add(LogType.MSG_MF_ERROR_SUBKEY_MISSING, indent + 1,
                        KeyFormattingUtils.convertKeyIdToHex(revocation));
                return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
            }
            PGPPublicKey pKey = sKey.getPublicKey();

            // generate and add new signature
            try {
                PGPSignature sig = generateRevocationSignature(
                        getSignatureGenerator(masterSecretKey, cryptoInput), cryptoInput.getSignatureTime(),
                        masterPublicKey, masterPrivateKey, pKey);

                pKey = PGPPublicKey.addCertification(pKey, sig);
                sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
            } catch (NfcInteractionNeeded e) {
                nfcSignOps.addHash(e.hashToSign, e.hashAlgo);
            }
        }
        subProgressPop();

        // 5. Generate and add new subkeys
        subProgressPush(70, 90);
        for (int i = 0; i < saveParcel.mAddSubKeys.size(); i++) {

            // Check if we were cancelled - again. This operation is expensive so we do it each loop.
            if (checkCancelled()) {
                log.add(LogType.MSG_OPERATION_CANCELLED, indent);
                return new PgpEditKeyResult(PgpEditKeyResult.RESULT_CANCELLED, log, null);
            }

            progress(R.string.progress_modify_subkeyadd, (i - 1) * (100 / saveParcel.mAddSubKeys.size()));
            SaveKeyringParcel.SubkeyAdd add = saveParcel.mAddSubKeys.get(i);
            log.add(LogType.MSG_MF_SUBKEY_NEW, indent,
                    KeyFormattingUtils.getAlgorithmInfo(add.mAlgorithm, add.mKeySize, add.mCurve));

            if (isDivertToCard(masterSecretKey)) {
                log.add(LogType.MSG_MF_ERROR_DIVERT_NEWSUB, indent + 1);
                return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
            }

            if (add.mExpiry == null) {
                log.add(LogType.MSG_MF_ERROR_NULL_EXPIRY, indent + 1);
                return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
            }

            if (add.mExpiry > 0L && new Date(add.mExpiry * 1000).before(new Date())) {
                log.add(LogType.MSG_MF_ERROR_PAST_EXPIRY, indent + 1);
                return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
            }

            // generate a new secret key (privkey only for now)
            subProgressPush((i - 1) * (100 / saveParcel.mAddSubKeys.size()),
                    i * (100 / saveParcel.mAddSubKeys.size()));
            PGPKeyPair keyPair = createKey(add, cryptoInput.getSignatureTime(), log, indent);
            subProgressPop();
            if (keyPair == null) {
                log.add(LogType.MSG_MF_ERROR_PGP, indent + 1);
                return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
            }

            // add subkey binding signature (making this a sub rather than master key)
            PGPPublicKey pKey = keyPair.getPublicKey();
            try {
                PGPSignature cert = generateSubkeyBindingSignature(
                        getSignatureGenerator(masterSecretKey, cryptoInput), cryptoInput.getSignatureTime(),
                        masterPublicKey, masterPrivateKey, getSignatureGenerator(pKey, cryptoInput, false),
                        keyPair.getPrivateKey(), pKey, add.mFlags, add.mExpiry);
                pKey = PGPPublicKey.addSubkeyBindingCertification(pKey, cert);
            } catch (NfcInteractionNeeded e) {
                nfcSignOps.addHash(e.hashToSign, e.hashAlgo);
            }

            PGPSecretKey sKey;
            {
                // Build key encrypter and decrypter based on passphrase
                PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder().build()
                        .get(PgpSecurityConstants.SECRET_KEY_ENCRYPTOR_HASH_ALGO);
                PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
                        PgpSecurityConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc,
                        PgpSecurityConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT)
                                .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME)
                                .build(cryptoInput.getPassphrase().getCharArray());

                PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build()
                        .get(PgpSecurityConstants.SECRET_KEY_SIGNATURE_CHECKSUM_HASH_ALGO);
                sKey = new PGPSecretKey(keyPair.getPrivateKey(), pKey, sha1Calc, false, keyEncryptor);
            }

            log.add(LogType.MSG_MF_SUBKEY_NEW_ID, indent + 1,
                    KeyFormattingUtils.convertKeyIdToHex(sKey.getKeyID()));

            sKR = PGPSecretKeyRing.insertSecretKey(sKR, sKey);

        }
        subProgressPop();

        // Check if we were cancelled - again. This operation is expensive so we do it each loop.
        if (checkCancelled()) {
            log.add(LogType.MSG_OPERATION_CANCELLED, indent);
            return new PgpEditKeyResult(PgpEditKeyResult.RESULT_CANCELLED, log, null);
        }

        // 6. If requested, change passphrase
        if (saveParcel.getChangeUnlockParcel() != null) {
            progress(R.string.progress_modify_passphrase, 90);
            log.add(LogType.MSG_MF_PASSPHRASE, indent);
            indent += 1;

            sKR = applyNewPassphrase(sKR, masterPublicKey, cryptoInput.getPassphrase(),
                    saveParcel.getChangeUnlockParcel().mNewPassphrase, log, indent);
            if (sKR == null) {
                // The error has been logged above, just return a bad state
                return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
            }

            indent -= 1;
        }

        // 7. if requested, change PIN and/or Admin PIN on security token
        if (saveParcel.mSecurityTokenPin != null) {
            progress(R.string.progress_modify_pin, 90);
            log.add(LogType.MSG_MF_PIN, indent);
            indent += 1;

            nfcKeyToCardOps.setPin(saveParcel.mSecurityTokenPin);

            indent -= 1;
        }
        if (saveParcel.mSecurityTokenAdminPin != null) {
            progress(R.string.progress_modify_admin_pin, 90);
            log.add(LogType.MSG_MF_ADMIN_PIN, indent);
            indent += 1;

            nfcKeyToCardOps.setAdminPin(saveParcel.mSecurityTokenAdminPin);

            indent -= 1;
        }

    } catch (IOException e) {
        Log.e(Constants.TAG, "encountered IOException while modifying key", e);
        log.add(LogType.MSG_MF_ERROR_ENCODE, indent + 1);
        return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
    } catch (PGPException e) {
        Log.e(Constants.TAG, "encountered pgp error while modifying key", e);
        log.add(LogType.MSG_MF_ERROR_PGP, indent + 1);
        return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
    } catch (SignatureException e) {
        Log.e(Constants.TAG, "encountered SignatureException while modifying key", e);
        log.add(LogType.MSG_MF_ERROR_SIG, indent + 1);
        return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
    }

    progress(R.string.progress_done, 100);

    if (!nfcSignOps.isEmpty() && !nfcKeyToCardOps.isEmpty()) {
        log.add(LogType.MSG_MF_ERROR_CONFLICTING_NFC_COMMANDS, indent + 1);
        return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
    }

    if (!nfcSignOps.isEmpty()) {
        log.add(LogType.MSG_MF_REQUIRE_DIVERT, indent);
        return new PgpEditKeyResult(log, nfcSignOps.build(), cryptoInput);
    }

    if (!nfcKeyToCardOps.isEmpty()) {
        log.add(LogType.MSG_MF_REQUIRE_DIVERT, indent);
        return new PgpEditKeyResult(log, nfcKeyToCardOps.build(), cryptoInput);
    }

    log.add(LogType.MSG_MF_SUCCESS, indent);
    return new PgpEditKeyResult(OperationResult.RESULT_OK, log, new UncachedKeyRing(sKR));

}

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

License:Open Source License

/** Update all (non-revoked) uid signatures with new flags and expiry time. */
private PGPPublicKey updateMasterCertificates(PGPSecretKey masterSecretKey, PGPPrivateKey masterPrivateKey,
        PGPPublicKey masterPublicKey, int flags, long expiry, CryptoInputParcel cryptoInput,
        SecurityTokenSignOperationsBuilder nfcSignOps, int indent, OperationLog log)
        throws PGPException, IOException, SignatureException {

    // keep track if we actually changed one
    boolean ok = false;
    log.add(LogType.MSG_MF_MASTER, indent);
    indent += 1;/*from  ww  w  . j  a  v  a2 s.c om*/

    PGPPublicKey modifiedPublicKey = masterPublicKey;

    // we work on the modifiedPublicKey here, to respect new or newly revoked uids
    // noinspection unchecked
    for (String userId : new IterableIterator<String>(modifiedPublicKey.getUserIDs())) {
        boolean isRevoked = false;
        PGPSignature currentCert = null;
        // noinspection unchecked
        for (PGPSignature cert : new IterableIterator<PGPSignature>(
                modifiedPublicKey.getSignaturesForID(userId))) {
            if (cert.getKeyID() != masterPublicKey.getKeyID()) {
                // foreign certificate?! error error error
                log.add(LogType.MSG_MF_ERROR_INTEGRITY, indent);
                return null;
            }
            // we know from canonicalization that if there is any revocation here, it
            // is valid and not superseded by a newer certification.
            if (cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION) {
                isRevoked = true;
                continue;
            }
            // we know from canonicalization that there is only one binding
            // certification here, so we can just work with the first one.
            if (cert.getSignatureType() == PGPSignature.NO_CERTIFICATION
                    || cert.getSignatureType() == PGPSignature.CASUAL_CERTIFICATION
                    || cert.getSignatureType() == PGPSignature.POSITIVE_CERTIFICATION
                    || cert.getSignatureType() == PGPSignature.DEFAULT_CERTIFICATION) {
                currentCert = cert;
            }
        }

        if (currentCert == null) {
            // no certificate found?! error error error
            log.add(LogType.MSG_MF_ERROR_INTEGRITY, indent);
            return null;
        }

        // we definitely should not update certifications of revoked keys, so just leave it.
        if (isRevoked) {
            continue;
        }

        // add shiny new user id certificate
        boolean isPrimary = currentCert.getHashedSubPackets() != null
                && currentCert.getHashedSubPackets().isPrimaryUserID();
        modifiedPublicKey = PGPPublicKey.removeCertification(modifiedPublicKey, userId, currentCert);
        try {
            PGPSignature newCert = generateUserIdSignature(getSignatureGenerator(masterSecretKey, cryptoInput),
                    cryptoInput.getSignatureTime(), masterPrivateKey, masterPublicKey, userId, isPrimary, flags,
                    expiry);
            modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, newCert);
        } catch (NfcInteractionNeeded e) {
            nfcSignOps.addHash(e.hashToSign, e.hashAlgo);
        }
        ok = true;

    }

    if (!ok) {
        // might happen, theoretically, if there is a key with no uid..
        log.add(LogType.MSG_MF_ERROR_MASTER_NONE, indent);
        return null;
    }

    return modifiedPublicKey;

}