mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-11-23 04:42:06 +01:00
Improve support for PGP[Secret|Public]KeyRingCollections
This commit is contained in:
parent
1a5baa0fa4
commit
82536eaa77
5 changed files with 217 additions and 34 deletions
|
@ -136,26 +136,6 @@ public class KeyRingReader {
|
||||||
isSilent);
|
isSilent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void validateStreamsNotBothNull(InputStream publicIn, InputStream secretIn) {
|
|
||||||
if (publicIn == null && secretIn == null) {
|
|
||||||
throw new NullPointerException("publicIn and secretIn cannot be BOTH null.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static PGPPublicKeyRing maybeReadPublicKeys(InputStream publicIn) throws IOException {
|
|
||||||
if (publicIn != null) {
|
|
||||||
return readPublicKeyRing(publicIn);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static PGPSecretKeyRing maybeReadSecretKeys(InputStream secretIn) throws IOException, PGPException {
|
|
||||||
if (secretIn != null) {
|
|
||||||
return readSecretKeyRing(secretIn);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hacky workaround for #96.
|
* Hacky workaround for #96.
|
||||||
* For {@link PGPPublicKeyRingCollection#PGPPublicKeyRingCollection(InputStream, KeyFingerPrintCalculator)}
|
* For {@link PGPPublicKeyRingCollection#PGPPublicKeyRingCollection(InputStream, KeyFingerPrintCalculator)}
|
||||||
|
|
|
@ -28,7 +28,9 @@ import org.bouncycastle.bcpg.ArmoredInputStream;
|
||||||
import org.bouncycastle.bcpg.ArmoredOutputStream;
|
import org.bouncycastle.bcpg.ArmoredOutputStream;
|
||||||
import org.bouncycastle.openpgp.PGPKeyRing;
|
import org.bouncycastle.openpgp.PGPKeyRing;
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
||||||
import org.bouncycastle.util.io.Streams;
|
import org.bouncycastle.util.io.Streams;
|
||||||
import org.pgpainless.algorithm.HashAlgorithm;
|
import org.pgpainless.algorithm.HashAlgorithm;
|
||||||
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
||||||
|
@ -54,6 +56,30 @@ public class ArmorUtils {
|
||||||
return toAsciiArmoredString(publicKeys.getEncoded(), header);
|
return toAsciiArmoredString(publicKeys.getEncoded(), header);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String toAsciiArmoredString(PGPSecretKeyRingCollection secretKeyRings) throws IOException {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (Iterator<PGPSecretKeyRing> iterator = secretKeyRings.iterator(); iterator.hasNext(); ) {
|
||||||
|
PGPSecretKeyRing secretKeyRing = iterator.next();
|
||||||
|
sb.append(toAsciiArmoredString(secretKeyRing));
|
||||||
|
if (iterator.hasNext()) {
|
||||||
|
sb.append('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toAsciiArmoredString(PGPPublicKeyRingCollection publicKeyRings) throws IOException {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (Iterator<PGPPublicKeyRing> iterator = publicKeyRings.iterator(); iterator.hasNext(); ) {
|
||||||
|
PGPPublicKeyRing publicKeyRing = iterator.next();
|
||||||
|
sb.append(toAsciiArmoredString(publicKeyRing));
|
||||||
|
if (iterator.hasNext()) {
|
||||||
|
sb.append('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
private static MultiMap<String, String> keyToHeader(PGPKeyRing keyRing) {
|
private static MultiMap<String, String> keyToHeader(PGPKeyRing keyRing) {
|
||||||
MultiMap<String, String> header = new MultiMap<>();
|
MultiMap<String, String> header = new MultiMap<>();
|
||||||
OpenPgpV4Fingerprint fingerprint = new OpenPgpV4Fingerprint(keyRing);
|
OpenPgpV4Fingerprint fingerprint = new OpenPgpV4Fingerprint(keyRing);
|
||||||
|
|
|
@ -0,0 +1,169 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 Paul Schaub.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.pgpainless.key.parsing;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.pgpainless.PGPainless;
|
||||||
|
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
||||||
|
import org.pgpainless.key.util.KeyRingUtils;
|
||||||
|
import org.pgpainless.util.ArmorUtils;
|
||||||
|
|
||||||
|
public class KeyRingCollectionReaderTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void writeAndParseKeyRingCollections() throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException {
|
||||||
|
// secret keys
|
||||||
|
PGPSecretKeyRing alice = PGPainless.generateKeyRing().modernKeyRing("Alice <alice@pgpainless.org>", null);
|
||||||
|
PGPSecretKeyRing bob = PGPainless.generateKeyRing().modernKeyRing("Bob <bob@pgpainless.org>", null);
|
||||||
|
|
||||||
|
PGPSecretKeyRingCollection collection = KeyRingUtils.keyRingsToKeyRingCollection(alice, bob);
|
||||||
|
String ascii = ArmorUtils.toAsciiArmoredString(collection);
|
||||||
|
|
||||||
|
PGPSecretKeyRingCollection parsed = PGPainless.readKeyRing().secretKeyRingCollection(ascii);
|
||||||
|
assertEquals(collection.size(), parsed.size());
|
||||||
|
|
||||||
|
// public keys
|
||||||
|
PGPPublicKeyRing pAlice = KeyRingUtils.publicKeyRingFrom(alice);
|
||||||
|
PGPPublicKeyRing pBob = KeyRingUtils.publicKeyRingFrom(bob);
|
||||||
|
|
||||||
|
PGPPublicKeyRingCollection pCollection = KeyRingUtils.keyRingsToKeyRingCollection(pAlice, pBob);
|
||||||
|
ascii = ArmorUtils.toAsciiArmoredString(pCollection);
|
||||||
|
|
||||||
|
PGPPublicKeyRingCollection pParsed = PGPainless.readKeyRing().publicKeyRingCollection(ascii);
|
||||||
|
assertEquals(pCollection.size(), pParsed.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void parseSeparatedSecretKeyRingCollection() throws PGPException, IOException {
|
||||||
|
String ascii = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
|
||||||
|
"Version: PGPainless\n" +
|
||||||
|
"Comment: 58F2 0119 232F BBC0 B624 CCA7 7BED B6B3 2279 0657\n" +
|
||||||
|
"Comment: Alice <alice@pgpainless.org>\n" +
|
||||||
|
"\n" +
|
||||||
|
"lFgEYLIldRYJKwYBBAHaRw8BAQdAv06tp4xghoxP/oDnIXuB//vH0RajTK7urjNn\n" +
|
||||||
|
"8YlYnucAAPsFAWLAW0c70rSktFw4CbtelRvtkcsGQkJVXXekRPcrGQ5jtBxBbGlj\n" +
|
||||||
|
"ZSA8YWxpY2VAcGdwYWlubGVzcy5vcmc+iHgEExYKACAFAmCyJXUCGwEFFgIDAQAE\n" +
|
||||||
|
"CwkIBwUVCgkICwIeAQIZAQAKCRB77bazInkGV9XIAP9M1yDWCPta2hMoNlKj74Yo\n" +
|
||||||
|
"kQXSI0VQT3FFq4ZIre5n9QEAxJTiMs+vhnmWChXz2RXvoqP/NdSYWZ6TLnqUy1Tz\n" +
|
||||||
|
"JQ2cXQRgsiV1EgorBgEEAZdVAQUBAQdAMUoA28ic8ZfbCzw3z60T3kmQNWQqdTQs\n" +
|
||||||
|
"HuxEQPj2B24DAQgHAAD/SWLvXh81Ho+6dysWNd9/qmtx0vcF1NeBsRu/Z+noe7gR\n" +
|
||||||
|
"c4h1BBgWCgAdBQJgsiV1AhsMBRYCAwEABAsJCAcFFQoJCAsCHgEACgkQe+22syJ5\n" +
|
||||||
|
"BleuPwEAvzGxpoCl4cRWk6t+UZdCALMdnM050sf0jruryQhg8lkBANa3i54K5Eze\n" +
|
||||||
|
"2ah+1f5O8JLudv5t9NS1kERY2JpqVlAPnFgEYLIldRYJKwYBBAHaRw8BAQdAO0VF\n" +
|
||||||
|
"ebLPMAYaxGl99jyLkQEJ4wNgdI1rBn3SDYnUq3kAAP4ugbF5XlRNHzxnSubS7Byf\n" +
|
||||||
|
"bF9gnmFt8eCQWdTM0FwUvREviNUEGBYKAH0FAmCyJXUCGwIFFgIDAQAECwkIBwUV\n" +
|
||||||
|
"CgkICwIeAV8gBBkWCgAGBQJgsiV1AAoJEOTg022wUXnBdqoA/1LjvNS65BieQ1uc\n" +
|
||||||
|
"l0kleh+K3rm4nFTs9dE39mbAI0k1AP9uHb4ucGunvqkq9x2nuFzCZHLoaBrzgi9S\n" +
|
||||||
|
"nGvLiHzLBgAKCRB77bazInkGV5S5AP433Ln47AHNr4u8Jo5aU5ML5f5KcxaOhQES\n" +
|
||||||
|
"SCBQ71BYWQEAlBFEhROHvJB2NCH695/zp5z5O6tmA0rLSQxZUTvyuQg=\n" +
|
||||||
|
"=Iwkd\n" +
|
||||||
|
"-----END PGP PRIVATE KEY BLOCK-----\n" +
|
||||||
|
"\n" +
|
||||||
|
"-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
|
||||||
|
"Version: PGPainless\n" +
|
||||||
|
"Comment: 88DD 9483 8B3D AB5B A07B 8F77 C852 EE0C 9502 F445\n" +
|
||||||
|
"Comment: Bob <bob@pgpainless.org>\n" +
|
||||||
|
"\n" +
|
||||||
|
"lFgEYLIldRYJKwYBBAHaRw8BAQdAY9AtZCfF3C8fLJ81o9qVlK4h6vgT///jGX6A\n" +
|
||||||
|
"qg/LsF4AAQDM5uiSRDYQBNqA/DydySUNLfjMvI4Aa7ONYwLqGoOvQA+mtBhCb2Ig\n" +
|
||||||
|
"PGJvYkBwZ3BhaW5sZXNzLm9yZz6IeAQTFgoAIAUCYLIldQIbAQUWAgMBAAQLCQgH\n" +
|
||||||
|
"BRUKCQgLAh4BAhkBAAoJEMhS7gyVAvRFdPgBAN36fO2Oo7iXukCgzOVRxb2sE1Ay\n" +
|
||||||
|
"+pWE+Vpt2Y4NiUrVAQCKmD0hl3SIolJf+sFpInToqT7s1P34o4hYPozEDj1IBZxd\n" +
|
||||||
|
"BGCyJXUSCisGAQQBl1UBBQEBB0C48wzNDfxyS/vjXNDWj06C4TLiu9JizHP1SQzN\n" +
|
||||||
|
"vs2YNQMBCAcAAP95XEFiQHLBbmpwvZiSRCt7MjXe4ODk+LPY787YyGiImBNUiHUE\n" +
|
||||||
|
"GBYKAB0FAmCyJXUCGwwFFgIDAQAECwkIBwUVCgkICwIeAQAKCRDIUu4MlQL0RVX1\n" +
|
||||||
|
"AP0Y1E2XEZZSBjU6a3LDY7so5h/WKyj2wFhPNlYJMPyEwAD/YwUd7K3Iu2jnSRyQ\n" +
|
||||||
|
"YkMPpBlUiCzY1WsPrYIpsrlhsAicWARgsiV1FgkrBgEEAdpHDwEBB0D2w+nDeSk1\n" +
|
||||||
|
"X8sGbIDc0eajB0nYaGoZ61LGjmJRXyxn/QABANmdFE//RkuC9vq150kbIXzjrm54\n" +
|
||||||
|
"TJ/l3HLv2Vb9JV5oEhSI1QQYFgoAfQUCYLIldQIbAgUWAgMBAAQLCQgHBRUKCQgL\n" +
|
||||||
|
"Ah4BXyAEGRYKAAYFAmCyJXUACgkQ9mL4hDfRd/aN9AEAnI2ssrPZwREpOcZsrYIe\n" +
|
||||||
|
"xSRFKc8n8RMDizHgnSyj3ZgBAPVceQEU78wnatz/x/Jbr2hE9Pj8IJK8fT96aXti\n" +
|
||||||
|
"CEEOAAoJEMhS7gyVAvRFw+0A/34n6qI1mJuXUNWdJd2yiGCKXLvVkwvpn2wQ5kaX\n" +
|
||||||
|
"9/m2AQCJC+MXorN3ro7aGtlz/81rtHREZftt2YH+pAy2OWq/BQ==\n" +
|
||||||
|
"=JB3F\n" +
|
||||||
|
"-----END PGP PRIVATE KEY BLOCK-----";
|
||||||
|
|
||||||
|
PGPSecretKeyRingCollection collection = PGPainless.readKeyRing().secretKeyRingCollection(ascii);
|
||||||
|
assertEquals(2, collection.size());
|
||||||
|
Iterator<PGPSecretKeyRing> iterator = collection.getKeyRings();
|
||||||
|
assertEquals(new OpenPgpV4Fingerprint("58F2 0119 232F BBC0 B624 CCA7 7BED B6B3 2279 0657"),
|
||||||
|
new OpenPgpV4Fingerprint(iterator.next()));
|
||||||
|
assertEquals(new OpenPgpV4Fingerprint("88DD 9483 8B3D AB5B A07B 8F77 C852 EE0C 9502 F445"),
|
||||||
|
new OpenPgpV4Fingerprint(iterator.next()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void parseConcatenatedSecretKeyRingCollection() throws PGPException, IOException {
|
||||||
|
// same key ring collection as above, but concatenated in a single armor block
|
||||||
|
String ascii = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
|
||||||
|
"Version: BCPG v1.68\n" +
|
||||||
|
"\n" +
|
||||||
|
"lFgEYLIldRYJKwYBBAHaRw8BAQdAv06tp4xghoxP/oDnIXuB//vH0RajTK7urjNn\n" +
|
||||||
|
"8YlYnucAAPsFAWLAW0c70rSktFw4CbtelRvtkcsGQkJVXXekRPcrGQ5jtBxBbGlj\n" +
|
||||||
|
"ZSA8YWxpY2VAcGdwYWlubGVzcy5vcmc+iHgEExYKACAFAmCyJXUCGwEFFgIDAQAE\n" +
|
||||||
|
"CwkIBwUVCgkICwIeAQIZAQAKCRB77bazInkGV9XIAP9M1yDWCPta2hMoNlKj74Yo\n" +
|
||||||
|
"kQXSI0VQT3FFq4ZIre5n9QEAxJTiMs+vhnmWChXz2RXvoqP/NdSYWZ6TLnqUy1Tz\n" +
|
||||||
|
"JQ2cXQRgsiV1EgorBgEEAZdVAQUBAQdAMUoA28ic8ZfbCzw3z60T3kmQNWQqdTQs\n" +
|
||||||
|
"HuxEQPj2B24DAQgHAAD/SWLvXh81Ho+6dysWNd9/qmtx0vcF1NeBsRu/Z+noe7gR\n" +
|
||||||
|
"c4h1BBgWCgAdBQJgsiV1AhsMBRYCAwEABAsJCAcFFQoJCAsCHgEACgkQe+22syJ5\n" +
|
||||||
|
"BleuPwEAvzGxpoCl4cRWk6t+UZdCALMdnM050sf0jruryQhg8lkBANa3i54K5Eze\n" +
|
||||||
|
"2ah+1f5O8JLudv5t9NS1kERY2JpqVlAPnFgEYLIldRYJKwYBBAHaRw8BAQdAO0VF\n" +
|
||||||
|
"ebLPMAYaxGl99jyLkQEJ4wNgdI1rBn3SDYnUq3kAAP4ugbF5XlRNHzxnSubS7Byf\n" +
|
||||||
|
"bF9gnmFt8eCQWdTM0FwUvREviNUEGBYKAH0FAmCyJXUCGwIFFgIDAQAECwkIBwUV\n" +
|
||||||
|
"CgkICwIeAV8gBBkWCgAGBQJgsiV1AAoJEOTg022wUXnBdqoA/1LjvNS65BieQ1uc\n" +
|
||||||
|
"l0kleh+K3rm4nFTs9dE39mbAI0k1AP9uHb4ucGunvqkq9x2nuFzCZHLoaBrzgi9S\n" +
|
||||||
|
"nGvLiHzLBgAKCRB77bazInkGV5S5AP433Ln47AHNr4u8Jo5aU5ML5f5KcxaOhQES\n" +
|
||||||
|
"SCBQ71BYWQEAlBFEhROHvJB2NCH695/zp5z5O6tmA0rLSQxZUTvyuQiUWARgsiV1\n" +
|
||||||
|
"FgkrBgEEAdpHDwEBB0Bj0C1kJ8XcLx8snzWj2pWUriHq+BP//+MZfoCqD8uwXgAB\n" +
|
||||||
|
"AMzm6JJENhAE2oD8PJ3JJQ0t+My8jgBrs41jAuoag69AD6a0GEJvYiA8Ym9iQHBn\n" +
|
||||||
|
"cGFpbmxlc3Mub3JnPoh4BBMWCgAgBQJgsiV1AhsBBRYCAwEABAsJCAcFFQoJCAsC\n" +
|
||||||
|
"HgECGQEACgkQyFLuDJUC9EV0+AEA3fp87Y6juJe6QKDM5VHFvawTUDL6lYT5Wm3Z\n" +
|
||||||
|
"jg2JStUBAIqYPSGXdIiiUl/6wWkidOipPuzU/fijiFg+jMQOPUgFnF0EYLIldRIK\n" +
|
||||||
|
"KwYBBAGXVQEFAQEHQLjzDM0N/HJL++Nc0NaPToLhMuK70mLMc/VJDM2+zZg1AwEI\n" +
|
||||||
|
"BwAA/3lcQWJAcsFuanC9mJJEK3syNd7g4OT4s9jvztjIaIiYE1SIdQQYFgoAHQUC\n" +
|
||||||
|
"YLIldQIbDAUWAgMBAAQLCQgHBRUKCQgLAh4BAAoJEMhS7gyVAvRFVfUA/RjUTZcR\n" +
|
||||||
|
"llIGNTprcsNjuyjmH9YrKPbAWE82Vgkw/ITAAP9jBR3srci7aOdJHJBiQw+kGVSI\n" +
|
||||||
|
"LNjVaw+tgimyuWGwCJxYBGCyJXUWCSsGAQQB2kcPAQEHQPbD6cN5KTVfywZsgNzR\n" +
|
||||||
|
"5qMHSdhoahnrUsaOYlFfLGf9AAEA2Z0UT/9GS4L2+rXnSRshfOOubnhMn+Xccu/Z\n" +
|
||||||
|
"Vv0lXmgSFIjVBBgWCgB9BQJgsiV1AhsCBRYCAwEABAsJCAcFFQoJCAsCHgFfIAQZ\n" +
|
||||||
|
"FgoABgUCYLIldQAKCRD2YviEN9F39o30AQCcjayys9nBESk5xmytgh7FJEUpzyfx\n" +
|
||||||
|
"EwOLMeCdLKPdmAEA9Vx5ARTvzCdq3P/H8luvaET0+Pwgkrx9P3ppe2IIQQ4ACgkQ\n" +
|
||||||
|
"yFLuDJUC9EXD7QD/fifqojWYm5dQ1Z0l3bKIYIpcu9WTC+mfbBDmRpf3+bYBAIkL\n" +
|
||||||
|
"4xeis3eujtoa2XP/zWu0dERl+23Zgf6kDLY5ar8F\n" +
|
||||||
|
"=TTn+\n" +
|
||||||
|
"-----END PGP PRIVATE KEY BLOCK-----";
|
||||||
|
|
||||||
|
PGPSecretKeyRingCollection collection = PGPainless.readKeyRing().secretKeyRingCollection(ascii);
|
||||||
|
assertEquals(2, collection.size());
|
||||||
|
Iterator<PGPSecretKeyRing> iterator = collection.getKeyRings();
|
||||||
|
assertEquals(new OpenPgpV4Fingerprint("58F2 0119 232F BBC0 B624 CCA7 7BED B6B3 2279 0657"),
|
||||||
|
new OpenPgpV4Fingerprint(iterator.next()));
|
||||||
|
assertEquals(new OpenPgpV4Fingerprint("88DD 9483 8B3D AB5B A07B 8F77 C852 EE0C 9502 F445"),
|
||||||
|
new OpenPgpV4Fingerprint(iterator.next()));
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,6 +25,7 @@ import java.util.List;
|
||||||
|
|
||||||
import org.bouncycastle.openpgp.PGPException;
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
import org.pgpainless.PGPainless;
|
import org.pgpainless.PGPainless;
|
||||||
|
|
||||||
|
@ -47,10 +48,13 @@ public class SopKeyUtil {
|
||||||
List<PGPPublicKeyRing> publicKeyRings = new ArrayList<>();
|
List<PGPPublicKeyRing> publicKeyRings = new ArrayList<>();
|
||||||
for (File file : files) {
|
for (File file : files) {
|
||||||
try (FileInputStream in = new FileInputStream(file)) {
|
try (FileInputStream in = new FileInputStream(file)) {
|
||||||
publicKeyRings.add(PGPainless.readKeyRing().publicKeyRing(in));
|
PGPPublicKeyRingCollection collection = PGPainless.readKeyRing().publicKeyRingCollection(in);
|
||||||
} catch (IOException e) {
|
for (PGPPublicKeyRing keyRing : collection) {
|
||||||
|
publicKeyRings.add(keyRing);
|
||||||
|
}
|
||||||
|
} catch (IOException | PGPException e) {
|
||||||
err_ln("Could not read certificate from file " + file.getName() + ": " + e.getMessage());
|
err_ln("Could not read certificate from file " + file.getName() + ": " + e.getMessage());
|
||||||
throw e;
|
throw new IOException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return publicKeyRings;
|
return publicKeyRings;
|
||||||
|
|
|
@ -17,6 +17,7 @@ package org.pgpainless.sop.commands;
|
||||||
|
|
||||||
import org.bouncycastle.openpgp.PGPException;
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||||
import org.bouncycastle.openpgp.PGPSignature;
|
import org.bouncycastle.openpgp.PGPSignature;
|
||||||
import org.bouncycastle.util.io.Streams;
|
import org.bouncycastle.util.io.Streams;
|
||||||
import org.pgpainless.PGPainless;
|
import org.pgpainless.PGPainless;
|
||||||
|
@ -88,7 +89,7 @@ public class Verify implements Runnable {
|
||||||
Date notBeforeDate = parseNotBefore();
|
Date notBeforeDate = parseNotBefore();
|
||||||
Date notAfterDate = parseNotAfter();
|
Date notAfterDate = parseNotAfter();
|
||||||
|
|
||||||
Map<File, PGPPublicKeyRing> publicKeys = readCertificatesFromFiles();
|
Map<PGPPublicKeyRing, File> publicKeys = readCertificatesFromFiles();
|
||||||
if (publicKeys.isEmpty()) {
|
if (publicKeys.isEmpty()) {
|
||||||
err_ln("No certificates supplied.");
|
err_ln("No certificates supplied.");
|
||||||
System.exit(19);
|
System.exit(19);
|
||||||
|
@ -100,7 +101,7 @@ public class Verify implements Runnable {
|
||||||
.onInputStream(System.in)
|
.onInputStream(System.in)
|
||||||
.doNotDecrypt()
|
.doNotDecrypt()
|
||||||
.verifyDetachedSignature(sigIn)
|
.verifyDetachedSignature(sigIn)
|
||||||
.verifyWith(new HashSet<>(publicKeys.values()))
|
.verifyWith(new HashSet<>(publicKeys.keySet()))
|
||||||
.ignoreMissingPublicKeys()
|
.ignoreMissingPublicKeys()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
@ -138,30 +139,33 @@ public class Verify implements Runnable {
|
||||||
printValidSignatures(signaturesInTimeRange, publicKeys);
|
printValidSignatures(signaturesInTimeRange, publicKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void printValidSignatures(Map<OpenPgpV4Fingerprint, PGPSignature> validSignatures, Map<File, PGPPublicKeyRing> publicKeys) {
|
private void printValidSignatures(Map<OpenPgpV4Fingerprint, PGPSignature> validSignatures, Map<PGPPublicKeyRing, File> publicKeys) {
|
||||||
for (OpenPgpV4Fingerprint sigKeyFp : validSignatures.keySet()) {
|
for (OpenPgpV4Fingerprint sigKeyFp : validSignatures.keySet()) {
|
||||||
PGPSignature signature = validSignatures.get(sigKeyFp);
|
PGPSignature signature = validSignatures.get(sigKeyFp);
|
||||||
for (File file : publicKeys.keySet()) {
|
for (PGPPublicKeyRing ring : publicKeys.keySet()) {
|
||||||
// Search signing key ring
|
// Search signing key ring
|
||||||
PGPPublicKeyRing publicKeyRing = publicKeys.get(file);
|
File file = publicKeys.get(ring);
|
||||||
if (publicKeyRing.getPublicKey(sigKeyFp.getKeyId()) == null) {
|
if (ring.getPublicKey(sigKeyFp.getKeyId()) == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
String utcSigDate = df.format(signature.getCreationTime());
|
String utcSigDate = df.format(signature.getCreationTime());
|
||||||
OpenPgpV4Fingerprint primaryKeyFp = new OpenPgpV4Fingerprint(publicKeyRing);
|
OpenPgpV4Fingerprint primaryKeyFp = new OpenPgpV4Fingerprint(ring);
|
||||||
print_ln(utcSigDate + " " + sigKeyFp.toString() + " " + primaryKeyFp.toString() +
|
print_ln(utcSigDate + " " + sigKeyFp.toString() + " " + primaryKeyFp.toString() +
|
||||||
" signed by " + file.getName());
|
" signed by " + file.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<File, PGPPublicKeyRing> readCertificatesFromFiles() {
|
private Map<PGPPublicKeyRing, File> readCertificatesFromFiles() {
|
||||||
Map<File, PGPPublicKeyRing> publicKeys = new HashMap<>();
|
Map<PGPPublicKeyRing, File> publicKeys = new HashMap<>();
|
||||||
for (File cert : certificates) {
|
for (File cert : certificates) {
|
||||||
try (FileInputStream in = new FileInputStream(cert)) {
|
try (FileInputStream in = new FileInputStream(cert)) {
|
||||||
publicKeys.put(cert, PGPainless.readKeyRing().publicKeyRing(in));
|
PGPPublicKeyRingCollection collection = PGPainless.readKeyRing().publicKeyRingCollection(in);
|
||||||
} catch (IOException e) {
|
for (PGPPublicKeyRing ring : collection) {
|
||||||
|
publicKeys.put(ring, cert);
|
||||||
|
}
|
||||||
|
} catch (IOException | PGPException e) {
|
||||||
err_ln("Cannot read certificate from file " + cert.getAbsolutePath() + ":");
|
err_ln("Cannot read certificate from file " + cert.getAbsolutePath() + ":");
|
||||||
err_ln(e.getMessage());
|
err_ln(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue