From b2accb0e9c07fa40fa9d7bf266a5763a1f63cc90 Mon Sep 17 00:00:00 2001
From: Thomas Wolf
Date: Wed, 6 Nov 2024 19:14:47 +0100
Subject: [PATCH] GPG: use BC PGP secret key parsing out of the box
Remove the custom S-expression parsing; BC has gotten many
improvements in 1.79 regarding PGP ed25519 keys, AES/OCB
encryption, and generally parsing key files. It now can do
all we need.
Change-Id: I392443e040cce150a9575d18795a7cb8195a3515
Signed-off-by: Thomas Wolf
---
.../META-INF/MANIFEST.MF | 11 +-
.../gpg/bc/internal/keys/SecretKeysTest.java | 62 +-
org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF | 37 +-
org.eclipse.jgit.gpg.bc/about.html | 26 -
.../jgit/gpg/bc/internal/BCText.properties | 14 +-
.../eclipse/jgit/gpg/bc/internal/BCText.java | 16 +-
.../bc/internal/BouncyCastleGpgSigner.java | 3 +-
.../keys/OCBPBEProtectionRemoverFactory.java | 132 ----
.../gpg/bc/internal/keys/SExprParser.java | 711 ------------------
.../jgit/gpg/bc/internal/keys/SXprUtils.java | 110 ---
.../jgit/gpg/bc/internal/keys/SecretKeys.java | 557 ++------------
11 files changed, 94 insertions(+), 1585 deletions(-)
delete mode 100644 org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/OCBPBEProtectionRemoverFactory.java
delete mode 100644 org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SExprParser.java
delete mode 100644 org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SXprUtils.java
diff --git a/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF
index c71f9b6541..a86f5ab2c6 100644
--- a/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF
@@ -8,11 +8,12 @@ Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-17
Require-Bundle: org.hamcrest.core;bundle-version="[1.3.0,2.0.0)"
-Import-Package: org.bouncycastle.jce.provider;version="[1.65.0,2.0.0)",
- org.bouncycastle.openpgp;version="[1.65.0,2.0.0)",
- org.bouncycastle.openpgp.operator;version="[1.65.0,2.0.0)",
- org.bouncycastle.openpgp.operator.jcajce;version="[1.65.0,2.0.0)",
- org.bouncycastle.util.encoders;version="[1.65.0,2.0.0)",
+Import-Package: org.bouncycastle.asn1.cryptlib;version="[1.79.0,2.0.0)",
+ org.bouncycastle.jce.provider;version="[1.79.0,2.0.0)",
+ org.bouncycastle.openpgp;version="[1.79.0,2.0.0)",
+ org.bouncycastle.openpgp.operator;version="[1.79.0,2.0.0)",
+ org.bouncycastle.openpgp.operator.jcajce;version="[1.79.0,2.0.0)",
+ org.bouncycastle.util.encoders;version="[1.79.0,2.0.0)",
org.eclipse.jgit.gpg.bc.internal;version="[7.1.0,7.2.0)",
org.eclipse.jgit.gpg.bc.internal.keys;version="[7.1.0,7.2.0)",
org.eclipse.jgit.util.sha1;version="[7.1.0,7.2.0)",
diff --git a/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeysTest.java b/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeysTest.java
index fed06103b6..d486c977f0 100644
--- a/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeysTest.java
+++ b/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeysTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 Thomas Wolf and others
+ * Copyright (C) 2021, 2024 Thomas Wolf and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -9,10 +9,7 @@
*/
package org.eclipse.jgit.gpg.bc.internal.keys;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
import java.io.BufferedInputStream;
import java.io.IOException;
@@ -20,8 +17,6 @@ import java.io.InputStream;
import java.security.Security;
import java.util.Iterator;
-import javax.crypto.Cipher;
-
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey;
@@ -49,39 +44,15 @@ public class SecretKeysTest {
}
}
- private static volatile Boolean haveOCB;
-
- private static boolean ocbAvailable() {
- Boolean haveIt = haveOCB;
- if (haveIt != null) {
- return haveIt.booleanValue();
- }
- try {
- Cipher c = Cipher.getInstance("AES/OCB/NoPadding"); //$NON-NLS-1$
- if (c == null) {
- haveOCB = Boolean.FALSE;
- return false;
- }
- } catch (NoClassDefFoundError | Exception e) {
- haveOCB = Boolean.FALSE;
- return false;
- }
- haveOCB = Boolean.TRUE;
- return true;
- }
-
private static class TestData {
final String name;
final boolean encrypted;
- final boolean keyValue;
-
- TestData(String name, boolean encrypted, boolean keyValue) {
+ TestData(String name, boolean encrypted) {
this.name = name;
this.encrypted = encrypted;
- this.keyValue = keyValue;
}
@Override
@@ -93,19 +64,12 @@ public class SecretKeysTest {
@Parameters(name = "{0}")
public static TestData[] initTestData() {
return new TestData[] {
- new TestData("AFDA8EA10E185ACF8C0D0F8885A0EF61A72ECB11", false, false),
- new TestData("2FB05DBB70FC07CB84C13431F640CA6CEA1DBF8A", false, true),
- new TestData("66CCECEC2AB46A9735B10FEC54EDF9FD0F77BAF9", true, true),
- new TestData("F727FAB884DA3BD402B6E0F5472E108D21033124", true, true),
- new TestData("62D43D7F117F7A5E4998ECB6617EE9942D069C14", true, true),
- new TestData("faked", false, true) };
- }
-
- private static byte[] readTestKey(String filename) throws Exception {
- try (InputStream in = new BufferedInputStream(
- SecretKeysTest.class.getResourceAsStream(filename))) {
- return SecretKeys.keyFromNameValueFormat(in);
- }
+ new TestData("AFDA8EA10E185ACF8C0D0F8885A0EF61A72ECB11", false),
+ new TestData("2FB05DBB70FC07CB84C13431F640CA6CEA1DBF8A", false),
+ new TestData("66CCECEC2AB46A9735B10FEC54EDF9FD0F77BAF9", true),
+ new TestData("F727FAB884DA3BD402B6E0F5472E108D21033124", true),
+ new TestData("62D43D7F117F7A5E4998ECB6617EE9942D069C14", true),
+ new TestData("faked", false) };
}
private static PGPPublicKey readAsc(InputStream in)
@@ -131,11 +95,6 @@ public class SecretKeysTest {
@Test
public void testKeyRead() throws Exception {
- if (data.keyValue) {
- byte[] bytes = readTestKey(data.name + ".key");
- assertEquals('(', bytes[0]);
- assertEquals(')', bytes[bytes.length - 1]);
- }
try (InputStream pubIn = this.getClass()
.getResourceAsStream(data.name + ".asc")) {
if (pubIn != null) {
@@ -151,11 +110,6 @@ public class SecretKeysTest {
: null,
publicKey);
assertNotNull(secretKey);
- } catch (PGPException e) {
- // Currently we may not be able to load OCB-encrypted keys.
- assertTrue(e.toString(), e.getMessage().contains("OCB"));
- assertTrue(data.encrypted);
- assertFalse(ocbAvailable());
}
}
}
diff --git a/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF b/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF
index 6e3321ebf6..1413c44dcb 100644
--- a/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF
@@ -8,26 +8,23 @@ Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: OSGI-INF/l10n/gpg_bc
Bundle-Version: 7.1.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-17
-Import-Package: org.bouncycastle.asn1;version="[1.69.0,2.0.0)",
- org.bouncycastle.asn1.x9;version="[1.69.0,2.0.0)",
- org.bouncycastle.bcpg;version="[1.69.0,2.0.0)",
- org.bouncycastle.bcpg.sig;version="[1.69.0,2.0.0)",
- org.bouncycastle.crypto.ec;version="[1.69.0,2.0.0)",
- org.bouncycastle.gpg;version="[1.69.0,2.0.0)",
- org.bouncycastle.gpg.keybox;version="[1.69.0,2.0.0)",
- org.bouncycastle.gpg.keybox.jcajce;version="[1.69.0,2.0.0)",
- org.bouncycastle.jcajce.interfaces;version="[1.69.0,2.0.0)",
- org.bouncycastle.jcajce.util;version="[1.69.0,2.0.0)",
- org.bouncycastle.jce.provider;version="[1.69.0,2.0.0)",
- org.bouncycastle.math.ec;version="[1.69.0,2.0.0)",
- org.bouncycastle.math.field;version="[1.69.0,2.0.0)",
- org.bouncycastle.openpgp;version="[1.69.0,2.0.0)",
- org.bouncycastle.openpgp.jcajce;version="[1.69.0,2.0.0)",
- org.bouncycastle.openpgp.operator;version="[1.69.0,2.0.0)",
- org.bouncycastle.openpgp.operator.jcajce;version="[1.69.0,2.0.0)",
- org.bouncycastle.util;version="[1.69.0,2.0.0)",
- org.bouncycastle.util.encoders;version="[1.69.0,2.0.0)",
- org.bouncycastle.util.io;version="[1.69.0,2.0.0)",
+Import-Package: org.bouncycastle.asn1;version="[1.79.0,2.0.0)",
+ org.bouncycastle.asn1.x9;version="[1.79.0,2.0.0)",
+ org.bouncycastle.bcpg;version="[1.79.0,2.0.0)",
+ org.bouncycastle.bcpg.sig;version="[1.79.0,2.0.0)",
+ org.bouncycastle.crypto.ec;version="[1.79.0,2.0.0)",
+ org.bouncycastle.gpg;version="[1.79.0,2.0.0)",
+ org.bouncycastle.gpg.keybox;version="[1.79.0,2.0.0)",
+ org.bouncycastle.gpg.keybox.jcajce;version="[1.79.0,2.0.0)",
+ org.bouncycastle.jcajce.interfaces;version="[1.79.0,2.0.0)",
+ org.bouncycastle.jcajce.util;version="[1.79.0,2.0.0)",
+ org.bouncycastle.math.ec;version="[1.79.0,2.0.0)",
+ org.bouncycastle.math.field;version="[1.79.0,2.0.0)",
+ org.bouncycastle.openpgp;version="[1.79.0,2.0.0)",
+ org.bouncycastle.openpgp.jcajce;version="[1.79.0,2.0.0)",
+ org.bouncycastle.openpgp.operator;version="[1.79.0,2.0.0)",
+ org.bouncycastle.openpgp.operator.jcajce;version="[1.79.0,2.0.0)",
+ org.bouncycastle.util.encoders;version="[1.79.0,2.0.0)",
org.slf4j;version="[1.7.0,3.0.0)"
Export-Package: org.eclipse.jgit.gpg.bc.internal;version="7.1.0";x-friends:="org.eclipse.jgit.gpg.bc.test",
org.eclipse.jgit.gpg.bc.internal.keys;version="7.1.0";x-friends:="org.eclipse.jgit.gpg.bc.test"
diff --git a/org.eclipse.jgit.gpg.bc/about.html b/org.eclipse.jgit.gpg.bc/about.html
index fc527d5a3a..92b9409831 100644
--- a/org.eclipse.jgit.gpg.bc/about.html
+++ b/org.eclipse.jgit.gpg.bc/about.html
@@ -58,32 +58,6 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWIS
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
-
-org.eclipse.jgit.gpg.bc.internal.keys.SExprParser - MIT
-
-Copyright (c) 2000-2021 The Legion of the Bouncy Castle Inc.
-(https://www.bouncycastle.org)
-
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software
-and associated documentation files (the "Software"), to deal in the Software without restriction,
-including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
-and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
-subject to the following conditions:
-
-
-The above copyright notice and this permission notice shall be included in all copies or substantial
-portions of the Software.
-
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
-INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
-
-