Return problems and key status enum in GpgKeyInfo

Change-Id: I2430887dccae1db6a60d6ed78d544786853e95f5
diff --git a/Documentation/rest-api-accounts.txt b/Documentation/rest-api-accounts.txt
index 7497a64..a320a54 100644
--- a/Documentation/rest-api-accounts.txt
+++ b/Documentation/rest-api-accounts.txt
@@ -713,7 +713,9 @@
       "user_ids": [
         "John Doe \u003cjohn.doe@example.com\u003e"
       ],
-      "key": "-----BEGIN PGP PUBLIC KEY BLOCK-----\nVersion: BCPG v1.52\n\nmQENBFXUpNcBCACv4paCiyKxZ0EcKy8VaWVNkJlNebRBiyw9WxU85wPOq5Gz/3GT\nRQwKqeY0SxVdQT8VNBw2sBe2m6eqcfZ2iKmesSlbXMe15DA7k8Bg4zEpQ0tXNG1L\nhceZDVQ1Xk06T2sgkunaiPsXi82nwN3UWYtDXxX4is5e6xBNL48Jgz4lbqo6+8D5\nvsVYiYMx4AwRkJyt/oA3IZAtSlY8Yd445nY14VPcnsGRwGWTLyZv9gxKHRUppVhQ\nE3o6ePXKEVgmONnQ4CjqmkGwWZvjMF2EPtAxvQLAuFa8Hqtkq5cgfgVkv/Vrcln4\nnQZVoMm3a3f5ODii2tQzNh6+7LL1bpqAmVEtABEBAAG0H0pvaG4gRG9lIDxqb2hu\nLmRvZUBleGFtcGxlLmNvbT6JATgEEwECACIFAlXUpNcCGwMGCwkIBwMCBhUIAgkK\nCwQWAgMBAh4BAheAAAoJEJNQnkuvyKSbfjoH/2OcSQOu1kJ20ndjhgY2yNChm7gd\ntU7TEBbB0TsLeazkrrLtKvrpW5+CRe07ZAG9HOtp3DikwAyrhSxhlYgVsQDhgB8q\nG0tYiZtQ88YyYrncCQ4hwknrcWXVW9bK3V4ZauxzPv3ADSloyR9tMURw5iHCIeL5\nfIw/pLvA3RjPMx4Sfow/bqRCUELua39prGw5Tv8a2ZRFbj2sgP5j8lUFegyJPQ4z\ntJhe6zZvKOzvIyxHO8llLmdrImsXRL9eqroWGs0VYqe6baQpY6xpSjbYK0J5HYcg\nTO+/u80JI+ROTMHE6unGp5Pgh/xIz6Wd34E0lWL1eOyNfGiPLyRWn1d0"
+      "key": "-----BEGIN PGP PUBLIC KEY BLOCK-----\nVersion: BCPG v1.52\n\nmQENBFXUpNcBCACv4paCiyKxZ0EcKy8VaWVNkJlNebRBiyw9WxU85wPOq5Gz/3GT\nRQwKqeY0SxVdQT8VNBw2sBe2m6eqcfZ2iKmesSlbXMe15DA7k8Bg4zEpQ0tXNG1L\nhceZDVQ1Xk06T2sgkunaiPsXi82nwN3UWYtDXxX4is5e6xBNL48Jgz4lbqo6+8D5\nvsVYiYMx4AwRkJyt/oA3IZAtSlY8Yd445nY14VPcnsGRwGWTLyZv9gxKHRUppVhQ\nE3o6ePXKEVgmONnQ4CjqmkGwWZvjMF2EPtAxvQLAuFa8Hqtkq5cgfgVkv/Vrcln4\nnQZVoMm3a3f5ODii2tQzNh6+7LL1bpqAmVEtABEBAAG0H0pvaG4gRG9lIDxqb2hu\nLmRvZUBleGFtcGxlLmNvbT6JATgEEwECACIFAlXUpNcCGwMGCwkIBwMCBhUIAgkK\nCwQWAgMBAh4BAheAAAoJEJNQnkuvyKSbfjoH/2OcSQOu1kJ20ndjhgY2yNChm7gd\ntU7TEBbB0TsLeazkrrLtKvrpW5+CRe07ZAG9HOtp3DikwAyrhSxhlYgVsQDhgB8q\nG0tYiZtQ88YyYrncCQ4hwknrcWXVW9bK3V4ZauxzPv3ADSloyR9tMURw5iHCIeL5\nfIw/pLvA3RjPMx4Sfow/bqRCUELua39prGw5Tv8a2ZRFbj2sgP5j8lUFegyJPQ4z\ntJhe6zZvKOzvIyxHO8llLmdrImsXRL9eqroWGs0VYqe6baQpY6xpSjbYK0J5HYcg\nTO+/u80JI+ROTMHE6unGp5Pgh/xIz6Wd34E0lWL1eOyNfGiPLyRWn1d0",
+      "status": "TRUSTED",
+      "problems": [],
     },
   }
 ----
@@ -747,7 +749,9 @@
     "user_ids": [
       "John Doe \u003cjohn.doe@example.com\u003e"
     ],
-    "key": "-----BEGIN PGP PUBLIC KEY BLOCK-----\nVersion: BCPG v1.52\n\nmQENBFXUpNcBCACv4paCiyKxZ0EcKy8VaWVNkJlNebRBiyw9WxU85wPOq5Gz/3GT\nRQwKqeY0SxVdQT8VNBw2sBe2m6eqcfZ2iKmesSlbXMe15DA7k8Bg4zEpQ0tXNG1L\nhceZDVQ1Xk06T2sgkunaiPsXi82nwN3UWYtDXxX4is5e6xBNL48Jgz4lbqo6+8D5\nvsVYiYMx4AwRkJyt/oA3IZAtSlY8Yd445nY14VPcnsGRwGWTLyZv9gxKHRUppVhQ\nE3o6ePXKEVgmONnQ4CjqmkGwWZvjMF2EPtAxvQLAuFa8Hqtkq5cgfgVkv/Vrcln4\nnQZVoMm3a3f5ODii2tQzNh6+7LL1bpqAmVEtABEBAAG0H0pvaG4gRG9lIDxqb2hu\nLmRvZUBleGFtcGxlLmNvbT6JATgEEwECACIFAlXUpNcCGwMGCwkIBwMCBhUIAgkK\nCwQWAgMBAh4BAheAAAoJEJNQnkuvyKSbfjoH/2OcSQOu1kJ20ndjhgY2yNChm7gd\ntU7TEBbB0TsLeazkrrLtKvrpW5+CRe07ZAG9HOtp3DikwAyrhSxhlYgVsQDhgB8q\nG0tYiZtQ88YyYrncCQ4hwknrcWXVW9bK3V4ZauxzPv3ADSloyR9tMURw5iHCIeL5\nfIw/pLvA3RjPMx4Sfow/bqRCUELua39prGw5Tv8a2ZRFbj2sgP5j8lUFegyJPQ4z\ntJhe6zZvKOzvIyxHO8llLmdrImsXRL9eqroWGs0VYqe6baQpY6xpSjbYK0J5HYcg\nTO+/u80JI+ROTMHE6unGp5Pgh/xIz6Wd34E0lWL1eOyNfGiPLyRWn1d0"
+    "key": "-----BEGIN PGP PUBLIC KEY BLOCK-----\nVersion: BCPG v1.52\n\nmQENBFXUpNcBCACv4paCiyKxZ0EcKy8VaWVNkJlNebRBiyw9WxU85wPOq5Gz/3GT\nRQwKqeY0SxVdQT8VNBw2sBe2m6eqcfZ2iKmesSlbXMe15DA7k8Bg4zEpQ0tXNG1L\nhceZDVQ1Xk06T2sgkunaiPsXi82nwN3UWYtDXxX4is5e6xBNL48Jgz4lbqo6+8D5\nvsVYiYMx4AwRkJyt/oA3IZAtSlY8Yd445nY14VPcnsGRwGWTLyZv9gxKHRUppVhQ\nE3o6ePXKEVgmONnQ4CjqmkGwWZvjMF2EPtAxvQLAuFa8Hqtkq5cgfgVkv/Vrcln4\nnQZVoMm3a3f5ODii2tQzNh6+7LL1bpqAmVEtABEBAAG0H0pvaG4gRG9lIDxqb2hu\nLmRvZUBleGFtcGxlLmNvbT6JATgEEwECACIFAlXUpNcCGwMGCwkIBwMCBhUIAgkK\nCwQWAgMBAh4BAheAAAoJEJNQnkuvyKSbfjoH/2OcSQOu1kJ20ndjhgY2yNChm7gd\ntU7TEBbB0TsLeazkrrLtKvrpW5+CRe07ZAG9HOtp3DikwAyrhSxhlYgVsQDhgB8q\nG0tYiZtQ88YyYrncCQ4hwknrcWXVW9bK3V4ZauxzPv3ADSloyR9tMURw5iHCIeL5\nfIw/pLvA3RjPMx4Sfow/bqRCUELua39prGw5Tv8a2ZRFbj2sgP5j8lUFegyJPQ4z\ntJhe6zZvKOzvIyxHO8llLmdrImsXRL9eqroWGs0VYqe6baQpY6xpSjbYK0J5HYcg\nTO+/u80JI+ROTMHE6unGp5Pgh/xIz6Wd34E0lWL1eOyNfGiPLyRWn1d0",
+    "status": "TRUSTED",
+    "problems": [],
   }
 ----
 
@@ -797,6 +801,8 @@
         "John Doe \u003cjohn.doe@example.com\u003e"
       ],
       "key": "-----BEGIN PGP PUBLIC KEY BLOCK-----\nVersion: BCPG v1.52\n\nmQENBFXUpNcBCACv4paCiyKxZ0EcKy8VaWVNkJlNebRBiyw9WxU85wPOq5Gz/3GT\nRQwKqeY0SxVdQT8VNBw2sBe2m6eqcfZ2iKmesSlbXMe15DA7k8Bg4zEpQ0tXNG1L\nhceZDVQ1Xk06T2sgkunaiPsXi82nwN3UWYtDXxX4is5e6xBNL48Jgz4lbqo6+8D5\nvsVYiYMx4AwRkJyt/oA3IZAtSlY8Yd445nY14VPcnsGRwGWTLyZv9gxKHRUppVhQ\nE3o6ePXKEVgmONnQ4CjqmkGwWZvjMF2EPtAxvQLAuFa8Hqtkq5cgfgVkv/Vrcln4\nnQZVoMm3a3f5ODii2tQzNh6+7LL1bpqAmVEtABEBAAG0H0pvaG4gRG9lIDxqb2hu\nLmRvZUBleGFtcGxlLmNvbT6JATgEEwECACIFAlXUpNcCGwMGCwkIBwMCBhUIAgkK\nCwQWAgMBAh4BAheAAAoJEJNQnkuvyKSbfjoH/2OcSQOu1kJ20ndjhgY2yNChm7gd\ntU7TEBbB0TsLeazkrrLtKvrpW5+CRe07ZAG9HOtp3DikwAyrhSxhlYgVsQDhgB8q\nG0tYiZtQ88YyYrncCQ4hwknrcWXVW9bK3V4ZauxzPv3ADSloyR9tMURw5iHCIeL5\nfIw/pLvA3RjPMx4Sfow/bqRCUELua39prGw5Tv8a2ZRFbj2sgP5j8lUFegyJPQ4z\ntJhe6zZvKOzvIyxHO8llLmdrImsXRL9eqroWGs0VYqe6baQpY6xpSjbYK0J5HYcg\nTO+/u80JI+ROTMHE6unGp5Pgh/xIz6Wd34E0lWL1eOyNfGiPLyRWn1d0"
+      "status": "TRUSTED",
+      "problems": [],
     }
     "DEADBEEF": {}
   }
@@ -1843,6 +1849,15 @@
 link:https://tools.ietf.org/html/rfc4880#section-5.11[OpenPGP User IDs]
 associated with the public key.
 |`key`        |Not set for deleted keys|ASCII armored public key material.
+|`status`     |Not set for deleted keys|
+The result of server-side checks on the key; one of `BAD`, `OK`, or `TRUSTED`.
+`BAD` keys have serious problems and should not be used. If a key is `OK,
+inspecting only that key found no problems, but the system does not fully trust
+the key's origin. A `TRUSTED` key is valid, and the system knows enough about
+the key and its origin to trust it.
+|`problems`   |Not set for deleted keys|
+A list of human-readable problem strings found in the course of checking whether
+the key is valid and trusted.
 |========================
 
 [[gpg-keys-input]]
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AccountIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AccountIT.java
index 8f2a11a..58b4013 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AccountIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AccountIT.java
@@ -412,6 +412,8 @@
     assertThat(actual.userIds).named(id).containsExactlyElementsIn(userIds);
     assertThat(actual.key).named(id)
         .startsWith("-----BEGIN PGP PUBLIC KEY BLOCK-----\n");
+    assertThat(actual.status).isEqualTo(GpgKeyInfo.Status.TRUSTED);
+    assertThat(actual.problems).isEmpty();
   }
 
   private void addExternalIdEmail(TestAccount account, String email)
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/GpgKeyInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/GpgKeyInfo.java
index 184099f..33adbea 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/GpgKeyInfo.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/GpgKeyInfo.java
@@ -43,4 +43,7 @@
   public String fingerprint;
   public List<String> userIds;
   public String key;
+
+  public Status status;
+  public List<String> problems;
 }
diff --git a/gerrit-gpg/src/main/java/com/google/gerrit/gpg/server/GpgKeys.java b/gerrit-gpg/src/main/java/com/google/gerrit/gpg/server/GpgKeys.java
index b22ca0e..52c429a 100644
--- a/gerrit-gpg/src/main/java/com/google/gerrit/gpg/server/GpgKeys.java
+++ b/gerrit-gpg/src/main/java/com/google/gerrit/gpg/server/GpgKeys.java
@@ -32,7 +32,9 @@
 import com.google.gerrit.extensions.restapi.RestReadView;
 import com.google.gerrit.extensions.restapi.RestView;
 import com.google.gerrit.gpg.BouncyCastleUtil;
+import com.google.gerrit.gpg.CheckResult;
 import com.google.gerrit.gpg.Fingerprint;
+import com.google.gerrit.gpg.PublicKeyChecker;
 import com.google.gerrit.gpg.PublicKeyStore;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.AccountExternalId;
@@ -68,14 +70,17 @@
   private final DynamicMap<RestView<GpgKey>> views;
   private final Provider<ReviewDb> db;
   private final Provider<PublicKeyStore> storeProvider;
+  private final PublicKeyChecker checker;
 
   @Inject
   GpgKeys(DynamicMap<RestView<GpgKey>> views,
       Provider<ReviewDb> db,
-      Provider<PublicKeyStore> storeProvider) {
+      Provider<PublicKeyStore> storeProvider,
+      PublicKeyChecker checker) {
     this.views = views;
     this.db = db;
     this.storeProvider = storeProvider;
+    this.checker = checker;
   }
 
   @Override
@@ -155,7 +160,7 @@
           for (PGPPublicKeyRing keyRing : store.get(keyId(fp))) {
             if (Arrays.equals(keyRing.getPublicKey().getFingerprint(), fp)) {
               found = true;
-              GpgKeyInfo info = toJson(keyRing);
+              GpgKeyInfo info = toJson(keyRing, checker, store);
               keys.put(info.id, info);
               info.id = null;
               break;
@@ -173,9 +178,21 @@
 
   @Singleton
   public static class Get implements RestReadView<GpgKey> {
+    private final Provider<PublicKeyStore> storeProvider;
+    private final PublicKeyChecker checker;
+
+    @Inject
+    Get(Provider<PublicKeyStore> storeProvider,
+        PublicKeyChecker checker) {
+      this.storeProvider = storeProvider;
+      this.checker = checker;
+    }
+
     @Override
     public GpgKeyInfo apply(GpgKey rsrc) throws IOException {
-      return toJson(rsrc.getKeyRing());
+      try (PublicKeyStore store = storeProvider.get()) {
+        return toJson(rsrc.getKeyRing(), checker, store);
+      }
     }
   }
 
@@ -207,7 +224,8 @@
     }
   }
 
-  static GpgKeyInfo toJson(PGPPublicKeyRing keyRing) throws IOException {
+  static GpgKeyInfo toJson(PGPPublicKeyRing keyRing, PublicKeyChecker checker,
+      PublicKeyStore store) throws IOException {
     PGPPublicKey key = keyRing.getPublicKey();
     GpgKeyInfo info = new GpgKeyInfo();
     info.id = PublicKeyStore.keyIdToString(key.getKeyID());
@@ -215,6 +233,7 @@
     @SuppressWarnings("unchecked")
     Iterator<String> userIds = key.getUserIDs();
     info.userIds = ImmutableList.copyOf(userIds);
+
     try (ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
         ArmoredOutputStream aout = new ArmoredOutputStream(out)) {
       // This is not exactly the key stored in the store, but is equivalent. In
@@ -224,6 +243,11 @@
       key.encode(aout);
       info.key = new String(out.toByteArray(), UTF_8);
     }
+
+    CheckResult checkResult = checker.check(key, store);
+    info.status = checkResult.getStatus();
+    info.problems = checkResult.getProblems();
+
     return info;
   }
 }
diff --git a/gerrit-gpg/src/main/java/com/google/gerrit/gpg/server/PostGpgKeys.java b/gerrit-gpg/src/main/java/com/google/gerrit/gpg/server/PostGpgKeys.java
index abe96ad..a6a1fbf 100644
--- a/gerrit-gpg/src/main/java/com/google/gerrit/gpg/server/PostGpgKeys.java
+++ b/gerrit-gpg/src/main/java/com/google/gerrit/gpg/server/PostGpgKeys.java
@@ -36,6 +36,7 @@
 import com.google.gerrit.gpg.CheckResult;
 import com.google.gerrit.gpg.Fingerprint;
 import com.google.gerrit.gpg.GerritPublicKeyChecker;
+import com.google.gerrit.gpg.PublicKeyChecker;
 import com.google.gerrit.gpg.PublicKeyStore;
 import com.google.gerrit.gpg.server.PostGpgKeys.Input;
 import com.google.gerrit.reviewdb.client.AccountExternalId;
@@ -135,7 +136,7 @@
               return toExtIdKey(fp.get());
             }
           }));
-      return toJson(newKeys, toRemove);
+      return toJson(newKeys, toRemove, store);
     }
   }
 
@@ -240,11 +241,12 @@
 
   private static Map<String, GpgKeyInfo> toJson(
       Collection<PGPPublicKeyRing> keys,
-      Set<Fingerprint> deleted) throws IOException {
+      Set<Fingerprint> deleted, PublicKeyStore store) throws IOException {
+    PublicKeyChecker checker = new PublicKeyChecker();
     Map<String, GpgKeyInfo> infos =
         Maps.newHashMapWithExpectedSize(keys.size() + deleted.size());
     for (PGPPublicKeyRing keyRing : keys) {
-      GpgKeyInfo info = GpgKeys.toJson(keyRing);
+      GpgKeyInfo info = GpgKeys.toJson(keyRing, checker, store);
       infos.put(info.id, info);
       info.id = null;
     }