package org.springframework.roo.felix.pgp;
import org.apache.commons.io.IOUtils;
import org.apache.felix.scr.annotations.Reference;
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.util.encoders.Hex;
import org.springframework.roo.shell.CliCommand;
import org.springframework.roo.shell.CliOption;
import org.springframework.roo.shell.CommandMarker;
import java.text.SimpleDateFormat;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.TimeZone;
/**
* Enables a user to manage the Roo PGP keystore.
*
* @author Ben Alex
* @since 1.1
*/
//@Service
//@Component
public class PgpCommands implements CommandMarker {
private static String getAlgorithm(final int algId) {
switch (algId) {
case PublicKeyAlgorithmTags.RSA_GENERAL:
return "RSA_GENERAL";
case PublicKeyAlgorithmTags.RSA_ENCRYPT:
return "RSA_ENCRYPT";
case PublicKeyAlgorithmTags.RSA_SIGN:
return "RSA_SIGN";
case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT:
return "ELGAMAL_ENCRYPT";
case PublicKeyAlgorithmTags.DSA:
return "DSA";
case PublicKeyAlgorithmTags.EC:
return "EC";
case PublicKeyAlgorithmTags.ECDSA:
return "ECDSA";
case PublicKeyAlgorithmTags.ELGAMAL_GENERAL:
return "ELGAMAL_GENERAL";
case PublicKeyAlgorithmTags.DIFFIE_HELLMAN:
return "DIFFIE_HELLMAN";
}
return "unknown";
}
@Reference
PgpService pgpService;
private void appendLine(final StringBuilder sb, final String line) {
sb.append(line).append(IOUtils.LINE_SEPARATOR);
}
@CliCommand(
value = "pgp automatic trust",
help = "Indicates to automatically trust all keys encountered until the command is invoked again")
public String automaticTrust() {
if (pgpService.isAutomaticTrust()) {
pgpService.setAutomaticTrust(false);
return "Automatic PGP key trusting disabled (this is the safest option)";
}
pgpService.setAutomaticTrust(true);
return "Automatic PGP key trusting enabled (this is potentially unsafe); disable by typing 'pgp automatic trust' again";
}
@SuppressWarnings("unchecked")
private void formatKeyRing(final StringBuilder sb, final PGPPublicKeyRing keyRing) {
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss Z");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
final Iterator<PGPPublicKey> it = keyRing.getPublicKeys();
boolean first = true;
while (it.hasNext()) {
final PGPPublicKey pgpKey = it.next();
if (first) {
appendLine(sb, ">>>> KEY ID: " + new PgpKeyId(pgpKey) + " <<<<");
appendLine(
sb,
" More Info: "
+ pgpService.getKeyServerUrlToRetrieveKeyInformation(new PgpKeyId(pgpKey)));
appendLine(sb, " Created: " + sdf.format(pgpKey.getCreationTime()));
appendLine(sb, " Fingerprint: " + new String(Hex.encode(pgpKey.getFingerprint())));
appendLine(sb, " Algorithm: " + getAlgorithm(pgpKey.getAlgorithm()));
final Iterator<String> userIdIterator = pgpKey.getUserIDs();
while (userIdIterator.hasNext()) {
final String userId = userIdIterator.next();
appendLine(sb, " User ID: " + userId);
final Iterator<PGPSignature> signatureIterator = pgpKey.getSignaturesForID(userId);
while (signatureIterator.hasNext()) {
final PGPSignature signature = signatureIterator.next();
appendLine(sb, " Signed By: "
+ getKeySummaryIfPossible(new PgpKeyId(signature)));
}
}
first = false;
} else {
appendLine(sb,
" Subkey ID: " + new PgpKeyId(pgpKey) + " [" + getAlgorithm(pgpKey.getAlgorithm())
+ "]");
}
}
}
@SuppressWarnings("unchecked")
private String getKeySummaryIfPossible(final PgpKeyId keyId) {
final List<PGPPublicKeyRing> keyRings = pgpService.getTrustedKeys();
for (final PGPPublicKeyRing keyRing : keyRings) {
final Iterator<PGPPublicKey> it = keyRing.getPublicKeys();
while (it.hasNext()) {
final PGPPublicKey pgpKey = it.next();
if (new PgpKeyId(pgpKey.getKeyID()).equals(keyId)) {
// We know about this key, so return a one-liner
final StringBuilder sb = new StringBuilder();
sb.append("Key ").append(keyId).append(" (");
final Iterator<String> userIds = pgpKey.getUserIDs();
if (userIds.hasNext()) {
final String userId = userIds.next();
sb.append(userId);
} else {
sb.append("no user ID in key");
}
sb.append(")");
return sb.toString();
}
}
}
return "Key " + keyId + " - not locally trusted";
}
@CliCommand(value = "pgp key view",
help = "Downloads a remote key and displays it to the user (does not change any trusts)")
public String keyView(@CliOption(key = "keyId", mandatory = true,
help = "The key ID to view (eg 00B5050F or 0x00B5050F)") final PgpKeyId keyId) {
final PGPPublicKeyRing keyRing = pgpService.getPublicKey(keyId);
final StringBuilder sb = new StringBuilder();
formatKeyRing(sb, keyRing);
return sb.toString();
}
@CliCommand(
value = "pgp list trusted keys",
help = "Lists the keys you currently trust and have not been revoked at the time last downloaded from a public key server")
public String listTrustedKeys() {
final List<PGPPublicKeyRing> keyRings = pgpService.getTrustedKeys();
if (keyRings.isEmpty()) {
final StringBuilder sb = new StringBuilder();
appendLine(sb,
"No keys trusted; use 'pgp trust' to add a key or 'pgp automatic trust' for automatic key addition");
return sb.toString();
}
final StringBuilder sb = new StringBuilder();
for (final PGPPublicKeyRing keyRing : keyRings) {
formatKeyRing(sb, keyRing);
}
return sb.toString();
}
@CliCommand(value = "pgp status", help = "Displays the status of the PGP environment")
public String pgpStatus() {
final List<PGPPublicKeyRing> keyRings = pgpService.getTrustedKeys();
final StringBuilder sb = new StringBuilder();
appendLine(sb, "File: " + pgpService.getKeyStorePhysicalLocation());
appendLine(sb, "Automatic trust: " + (pgpService.isAutomaticTrust() ? "enabled" : "disabled"));
appendLine(sb, "Key count: " + keyRings.size());
return sb.toString();
}
@CliCommand(value = "pgp refresh all", help = "Refreshes all keys from public key servers")
public String refreshKeysFromServer() {
final StringBuilder sb = new StringBuilder();
for (final Entry<PgpKeyId, String> entry : pgpService.refresh().entrySet()) {
final PgpKeyId key = entry.getKey();
final String outcome = entry.getValue();
appendLine(sb, key + " : " + outcome);
}
return sb.toString();
}
@CliCommand(value = "pgp trust", help = "Grants trust to a particular key ID")
public String trust(@CliOption(key = "keyId", mandatory = true,
help = "The key ID to trust (eg 00B5050F or 0x00B5050F)") final PgpKeyId keyId) {
final PGPPublicKeyRing keyRing = pgpService.trust(keyId);
final StringBuilder sb = new StringBuilder();
appendLine(sb, "Added trust for key:");
formatKeyRing(sb, keyRing);
return sb.toString();
}
@CliCommand(value = "pgp untrust", help = "Revokes your trust for a particular key ID")
public String untrust(@CliOption(key = "keyId", mandatory = true,
help = "The key ID to remove trust from (eg 00B5050F or 0x00B5050F)") final PgpKeyId keyId) {
final PGPPublicKeyRing keyRing = pgpService.untrust(keyId);
final StringBuilder sb = new StringBuilder();
appendLine(sb, "Revoked trust from key:");
formatKeyRing(sb, keyRing);
return sb.toString();
}
}