/** * Usage flags as Bouncy castle {@link PGPKeyFlags} bits. */ public int getUsageFlags() throws PGPException { if (publicKey == null) return 0; int flags = 0; // actually only need POSITIVE_CERTIFICATION (for master key) // and SUBKEY_BINDING (for subkeys) Iterator<PGPSignature> signatures = publicKey.getSignatures(); while (signatures.hasNext()) { PGPSignature signature = signatures.next(); PGPSignatureSubpacketVector hashedSubPackets = signature.getHashedSubPackets(); if (hashedSubPackets != null) flags |= hashedSubPackets.getKeyFlags(); } return flags; }
/** * Checks whether one of the signatures of the key has one of the expected * key flags * * @param key * @return {@link Boolean#TRUE} if key has one of the expected flag, * <code>null</code> if the key does not have any key flags, * {@link Boolean#FALSE} if the key has none of the expected flags */ private static Boolean hasOneOfExpectedKeyFlags(PGPPublicKey key, int[] expectedKeyFlags) { boolean containsKeyFlags = false; for (@SuppressWarnings("unchecked") Iterator<PGPSignature> itsig = key.getSignatures(); itsig.hasNext();) { PGPSignature sig = itsig.next(); PGPSignatureSubpacketVector subPacks = sig.getHashedSubPackets(); if (subPacks != null) { int keyFlag = subPacks.getKeyFlags(); if (keyFlag > 0 && !containsKeyFlags) { containsKeyFlags = true; } for (int expectdKeyFlag : expectedKeyFlags) { int result = keyFlag & expectdKeyFlag; if (result == expectdKeyFlag) { return Boolean.TRUE; } } } } if (containsKeyFlags) { return Boolean.FALSE; } return null; // no key flag }
private Set<PgpKeyFlag> getPgpKeyFlags() { final EnumSet<PgpKeyFlag> result = EnumSet.noneOf(PgpKeyFlag.class); final PgpKeyId masterKeyId = masterKey == null ? getPgpKeyId() : masterKey.getPgpKeyId(); final Iterator<?> sigIt = publicKey.getSignatures(); while (sigIt.hasNext()) { final PGPSignature signature = (PGPSignature) sigIt.next(); if (signature.getKeyID() != masterKeyId.longValue()) continue; // It seems, the signature type is not always the way it should be (to my understanding). // To look for PGPSignature.SUBKEY_BINDING works fine, but PGPSignature.PRIMARYKEY_BINDING seems to // never be used. I thus do not filter by signature-type at all, anymore, but collect all keyFlags // from all signatures made by the master-key. final PGPSignatureSubpacketVector hashedSubPackets = signature.getHashedSubPackets(); if (hashedSubPackets != null) { final int keyFlags = hashedSubPackets.getKeyFlags(); result.addAll(getPgpKeyFlags(keyFlags)); } } return result; }
/** * Check if the PGPSignature contains sub keys that suit our usage. We need * sub keys that are suitable for encrypting storage. * @param sig - PGPSignature * @param keyUsage - Usage type - Encrypt storage or communication * @return true if a sub key for encrypting storage is found else false */ private boolean isMatchingUsage(PGPSignature sig, int keyUsage) { if (sig.hasSubpackets()) { PGPSignatureSubpacketVector sv = sig.getHashedSubPackets(); if (sv.hasSubpacket(CryptDecryptUtil.KEY_FLAGS)) { if ((sv.getKeyFlags() == 0 && keyUsage == 0)) { return false; } } } return true; }
private static PGPPublicKeyRing addUserId( final PGPPublicKeyRing publicKeyRing, final String userId, final PGPSecretKeyRing secretKeyRing, final char[] passphrase, PGPContentSignerBuilder signerBuilder, final PGPSignatureSubpacketVector hashedSubpackets, final PGPSignatureSubpacketVector unhashedSubpackets) throws PGPException { assertNotNull(publicKeyRing, "publicKeyRing"); assertNotNull(userId, "userId"); final PGPPublicKey masterPublicKey = getMasterKeyOrFail(publicKeyRing); final PGPSecretKey masterSecretKey = secretKeyRing.getSecretKey(masterPublicKey.getKeyID()); assertNotNull(masterSecretKey, "masterSecretKey"); final PGPPrivateKey privateKey = extractPrivateKey(masterSecretKey, passphrase); final PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder); sGen.init(PGPSignature.POSITIVE_CERTIFICATION, privateKey); sGen.setHashedSubpackets(hashedSubpackets); sGen.setUnhashedSubpackets(unhashedSubpackets); final PGPSignature certification = sGen.generateCertification(userId, masterPublicKey); final PGPPublicKey newMasterPublicKey = PGPPublicKey.addCertification(masterPublicKey, userId, certification); PGPPublicKeyRing result = PGPPublicKeyRing.removePublicKey(publicKeyRing, masterPublicKey); result = PGPPublicKeyRing.insertPublicKey(result, newMasterPublicKey); return result; }
private static int getKeyFlags(PGPPublicKey key) { @SuppressWarnings("unchecked") Iterator<PGPSignature> sigs = key.getSignatures(); while (sigs.hasNext()) { PGPSignature sig = sigs.next(); PGPSignatureSubpacketVector subpackets = sig.getHashedSubPackets(); if (subpackets != null) return subpackets.getKeyFlags(); } return 0; }
private final static void maybeAddDesignated (List<byte[]> fps, PGPSignature sig, PGPPublicKey masterpk, StringBuilder errors) throws PGPException,SignatureException, IOException { if (!isGoodDirectSignature(sig, masterpk, masterpk, errors)) { return; } PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets(); if (hashed == null) { errors.append ("Designated revoking "+niceSig(sig)+ " is missing revocation key.\n"); return; } SignatureSubpacket spack = hashed.getSubpacket(SignatureSubpacketTags.REVOCATION_KEY); if (spack == null) { return; } // You might think that the parser actually creates a RevocationKey // type, but no - you have to do that yourself. RevocationKey designated_revoker = new RevocationKey(spack.isCritical(), spack.getData()); // 0x80 bit must be set if ((designated_revoker.getSignatureClass() & 0x80) == 0) { return; } // algorithm id must match if (designated_revoker.getAlgorithm() != masterpk.getAlgorithm()) { return; } fps.add(designated_revoker.getFingerprint()); }
private final static boolean hasKeyFlag(PGPSignature sig, int flag) { PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets(); if (hashed == null) { return false; } KeyFlags flags = (KeyFlags) hashed.getSubpacket(SignatureSubpacketTags.KEY_FLAGS); if (flags == null) { return false; } return ((flags.getFlags() & flag) != 0); }
private PGPSignatureSubpacketVector generateMasterKeySettings() { final PGPSignatureSubpacketGenerator settings = new PGPSignatureSubpacketGenerator(); settings.setKeyFlags(false, Flags.toBitmask(KeyFlag.MASTER_KEY_DEFAULTS)); settings.setPreferredSymmetricAlgorithms(false, Flags.toIntArray(SymmetricAlgorithm.ACCEPTABLE_ALGORITHMS)); settings.setPreferredHashAlgorithms(false, Flags.toIntArray(HashAlgorithm.ACCEPTABLE_ALGORITHMS)); settings.setPreferredCompressionAlgorithms(false, Flags.toIntArray(CompressionAlgorithm.ACCEPTABLE_ALGORITHMS)); return settings.generate(); }
static boolean hasFlag(final PGPSignature signature, final int flag) { if (signature.hasSubpackets()) { PGPSignatureSubpacketVector subpacketVector = signature.getHashedSubPackets(); if (subpacketVector.hasSubpacket(SignatureSubpacketTags.KEY_FLAGS)) { if ((subpacketVector.getKeyFlags() & flag) > 0) { return true; } } } return false; }
private void testMissingSubpackets(byte[] signature) throws IOException { PGPObjectFactory f = new PGPObjectFactory(signature); Object obj = f.nextObject(); while (!(obj instanceof PGPSignatureList)) { obj = f.nextObject(); if (obj instanceof PGPLiteralData) { InputStream in = ((PGPLiteralData)obj).getDataStream(); Streams.drain(in); } } PGPSignature sig = ((PGPSignatureList)obj).get(0); if (sig.getVersion() > 3) { PGPSignatureSubpacketVector v = sig.getHashedSubPackets(); if (v.getKeyExpirationTime() != 0) { fail("key expiration time not zero for missing subpackets"); } if (!sig.hasSubpackets()) { fail("hasSubpackets() returns false with packets"); } } else { if (sig.getHashedSubPackets() != null) { fail("hashed sub packets found when none expected"); } if (sig.getUnhashedSubPackets() != null) { fail("unhashed sub packets found when none expected"); } if (sig.hasSubpackets()) { fail("hasSubpackets() returns true with no packets"); } } }
private PGPSignatureSubpacketVector generateSubKeySettings() { final PGPSignatureSubpacketGenerator settings = new PGPSignatureSubpacketGenerator(); settings.setKeyFlags(false, Flags.toBitmask(KeyFlag.SUB_KEY_DEFAULTS)); return settings.generate(); }