From 433f5e6530b7f5b4b4d37dae65171f70382b8c3d Mon Sep 17 00:00:00 2001 From: Jason Tedor Date: Fri, 25 May 2018 11:49:20 -0400 Subject: [PATCH 1/3] Add public key header/footer A previous commit added the public key used for signing artifacts to the plugin CLI. This commit is an iteration on that to add the header and footer to the key so that it is clear what the key is. Instead, we strip the header/footer on read. With this change we simplify our test where keys already in this format are generated and we had to strip on the test side. --- .../plugins/InstallPluginCommand.java | 22 ++++++++++++++----- .../resources/{public_key => public_key.asc} | 5 +++++ .../plugins/InstallPluginCommandTests.java | 7 +----- 3 files changed, 23 insertions(+), 11 deletions(-) rename distribution/tools/plugin-cli/src/main/resources/{public_key => public_key.asc} (93%) diff --git a/distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/InstallPluginCommand.java b/distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/InstallPluginCommand.java index a47ea4f892616..d62dc2b140b69 100644 --- a/distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/InstallPluginCommand.java +++ b/distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/InstallPluginCommand.java @@ -47,6 +47,7 @@ import org.elasticsearch.env.Environment; import java.io.BufferedReader; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -71,7 +72,6 @@ import java.nio.file.attribute.PosixFilePermissions; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.security.Security; import java.util.ArrayList; import java.util.Arrays; import java.util.Base64; @@ -543,8 +543,8 @@ void verifySignature(final Path zip, final String urlString) throws IOException, InputStream fin = pluginZipInputStream(zip); // sin is a URL stream to the signature corresponding to the downloaded plugin zip InputStream sin = urlOpenStream(ascUrl); - // pin is a decoded base64 stream over the embedded public key in RFC2045 format - InputStream pin = Base64.getMimeDecoder().wrap(getPublicKey())) { + // pin is a input stream to the public key in ASCII-Armor format (RFC4880); the Armor data is in RFC2045 + InputStream pin = getPublicKey()) { final JcaPGPObjectFactory factory = new JcaPGPObjectFactory(PGPUtil.getDecoderStream(sin)); final PGPSignature signature = ((PGPSignatureList) factory.nextObject()).get(0); @@ -555,7 +555,19 @@ void verifySignature(final Path zip, final String urlString) throws IOException, } // compute the signature of the downloaded plugin zip - final PGPPublicKeyRingCollection collection = new PGPPublicKeyRingCollection(pin, new JcaKeyFingerprintCalculator()); + final List lines = + new BufferedReader(new InputStreamReader(pin, StandardCharsets.UTF_8)).lines().collect(Collectors.toList()); + // skip armor headers and possible blank line + int index = 1; + for (; index < lines.size(); index++) { + if (lines.get(index).matches("\\w: \\w") == false && lines.get(index).matches("\\s*")) { + break; + } + } + final byte[] armoredData = + lines.subList(index + 1, lines.size() - 1).stream().collect(Collectors.joining("\n")).getBytes(StandardCharsets.UTF_8); + final InputStream ain = Base64.getMimeDecoder().wrap(new ByteArrayInputStream(armoredData)); + final PGPPublicKeyRingCollection collection = new PGPPublicKeyRingCollection(ain, new JcaKeyFingerprintCalculator()); final PGPPublicKey key = collection.getPublicKey(signature.getKeyID()); signature.init(new JcaPGPContentVerifierBuilderProvider().setProvider(new BouncyCastleProvider()), key); final byte[] buffer = new byte[1024]; @@ -597,7 +609,7 @@ String getPublicKeyId() { * @return an input stream to the public key */ InputStream getPublicKey() { - return InstallPluginCommand.class.getResourceAsStream("/public_key"); + return InstallPluginCommand.class.getResourceAsStream("/public_key.asc"); } /** diff --git a/distribution/tools/plugin-cli/src/main/resources/public_key b/distribution/tools/plugin-cli/src/main/resources/public_key.asc similarity index 93% rename from distribution/tools/plugin-cli/src/main/resources/public_key rename to distribution/tools/plugin-cli/src/main/resources/public_key.asc index 552c8e3379d3b..57fb72a35cf6b 100644 --- a/distribution/tools/plugin-cli/src/main/resources/public_key +++ b/distribution/tools/plugin-cli/src/main/resources/public_key.asc @@ -1,3 +1,7 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: SKS 1.1.6 +Comment: Hostname: pgp.mit.edu + mQENBFI3HsoBCADXDtbNJnxbPqB1vDNtCsqhe49vFYsZN9IOZsZXgp7aHjh6CJBDA+bGFOwy hbd7at35jQjWAw1O3cfYsKAmFy+Ar3LHCMkV3oZspJACTIgCrwnkic/9CUliQe324qvObU2Q RtP4Fl0zWcfb/S8UYzWXWIFuJqMvE9MaRY1bwUBvzoqavLGZj3SF1SPO+TB5QrHkrQHBsmX+ @@ -22,3 +26,4 @@ EyUJ8SKsaHh4jV9wp9KmC8C+9CwMukL7vM5w8cgvJoAwsp3Fn59AxWthN3XJYcnMfStkIuWg R7U2r+a210W6vnUxU4oN0PmMcursYPyeV0NX/KQeUeNMwGTFB6QHS/anRaGQewijkrYYoTNt fllxIu9XYmiBERQ/qPDlGRlOgVTd9xUfHFkzB52c70E= =92oX +-----END PGP PUBLIC KEY BLOCK----- \ No newline at end of file diff --git a/distribution/tools/plugin-cli/src/test/java/org/elasticsearch/plugins/InstallPluginCommandTests.java b/distribution/tools/plugin-cli/src/test/java/org/elasticsearch/plugins/InstallPluginCommandTests.java index d9238091d8769..1db551934c768 100644 --- a/distribution/tools/plugin-cli/src/test/java/org/elasticsearch/plugins/InstallPluginCommandTests.java +++ b/distribution/tools/plugin-cli/src/test/java/org/elasticsearch/plugins/InstallPluginCommandTests.java @@ -893,12 +893,7 @@ InputStream getPublicKey() { final ArmoredOutputStream armored = new ArmoredOutputStream(output); secretKey.getPublicKey().encode(armored); armored.close(); - final String publicKey = new String(output.toByteArray(), "UTF-8"); - int start = publicKey.indexOf("\n", 1 + publicKey.indexOf("\n")); - int end = publicKey.lastIndexOf("\n", publicKey.lastIndexOf("\n") - 1); - // strip the header (first two lines) and footer (last line) - final String substring = publicKey.substring(1 + start, end); - return new ByteArrayInputStream(substring.getBytes("UTF-8")); + return new ByteArrayInputStream(output.toByteArray()); } catch (final IOException e) { throw new AssertionError(e); } From b108ece3e1ad32a646a55dd6a59984e473e33710 Mon Sep 17 00:00:00 2001 From: Jason Tedor Date: Fri, 25 May 2018 12:05:46 -0400 Subject: [PATCH 2/3] Fix comment --- .../java/org/elasticsearch/plugins/InstallPluginCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/InstallPluginCommand.java b/distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/InstallPluginCommand.java index d62dc2b140b69..bcc2e1cb5062c 100644 --- a/distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/InstallPluginCommand.java +++ b/distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/InstallPluginCommand.java @@ -543,7 +543,7 @@ void verifySignature(final Path zip, final String urlString) throws IOException, InputStream fin = pluginZipInputStream(zip); // sin is a URL stream to the signature corresponding to the downloaded plugin zip InputStream sin = urlOpenStream(ascUrl); - // pin is a input stream to the public key in ASCII-Armor format (RFC4880); the Armor data is in RFC2045 + // pin is a input stream to the public key in ASCII-Armor format (RFC4880); the Armor data is in RFC2045 format InputStream pin = getPublicKey()) { final JcaPGPObjectFactory factory = new JcaPGPObjectFactory(PGPUtil.getDecoderStream(sin)); final PGPSignature signature = ((PGPSignatureList) factory.nextObject()).get(0); From 9b103239d8fda87c951f36e2f872200bfde2c82f Mon Sep 17 00:00:00 2001 From: Jason Tedor Date: Fri, 25 May 2018 12:13:54 -0400 Subject: [PATCH 3/3] Adjust regex --- .../java/org/elasticsearch/plugins/InstallPluginCommand.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/InstallPluginCommand.java b/distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/InstallPluginCommand.java index bcc2e1cb5062c..6a3f57c98d205 100644 --- a/distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/InstallPluginCommand.java +++ b/distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/InstallPluginCommand.java @@ -560,12 +560,12 @@ void verifySignature(final Path zip, final String urlString) throws IOException, // skip armor headers and possible blank line int index = 1; for (; index < lines.size(); index++) { - if (lines.get(index).matches("\\w: \\w") == false && lines.get(index).matches("\\s*")) { + if (lines.get(index).matches(".*: .*") == false && lines.get(index).matches("\\s*") == false) { break; } } final byte[] armoredData = - lines.subList(index + 1, lines.size() - 1).stream().collect(Collectors.joining("\n")).getBytes(StandardCharsets.UTF_8); + lines.subList(index, lines.size() - 1).stream().collect(Collectors.joining("\n")).getBytes(StandardCharsets.UTF_8); final InputStream ain = Base64.getMimeDecoder().wrap(new ByteArrayInputStream(armoredData)); final PGPPublicKeyRingCollection collection = new PGPPublicKeyRingCollection(ain, new JcaKeyFingerprintCalculator()); final PGPPublicKey key = collection.getPublicKey(signature.getKeyID());