List of usage examples for org.bouncycastle.openpgp PGPSignature getSignatureType
public int getSignatureType()
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; }