Merge branch 'stable-5.10' into stable-5.11

* stable-5.10:
  Add missing since tag for SshTestHarness#publicKey2
  Silence API errors
  Prevent infinite loop rescanning the pack list on
PackMismatchException
  Remove blank in maven.config

Migrated "Prevent infinite loop rescanning the pack list on
PackMismatchException" to refactoring done in
https://git.eclipse.org/r/q/topic:restore-preserved-packs

Change-Id: I0fb77bb9b498d48d5da88a93486b99bf8121e3bd
diff --git a/.bazelversion b/.bazelversion
index 8faff82..fcdb2e1 100644
--- a/.bazelversion
+++ b/.bazelversion
@@ -1 +1 @@
-4.0.0rc2
+4.0.0
diff --git a/BUILD b/BUILD
index be6dd76..184ab27 100644
--- a/BUILD
+++ b/BUILD
@@ -13,6 +13,8 @@
         "//org.eclipse.jgit.lfs:jgit-lfs",
         "//org.eclipse.jgit.lfs.server:jgit-lfs-server",
         "//org.eclipse.jgit.junit:junit",
+        "//org.eclipse.jgit.ssh.apache:ssh-apache",
+        "//org.eclipse.jgit.ssh.jsch:ssh-jsch",
     ],
     outs = ["all.zip"],
     cmd = " && ".join([
diff --git a/DEPENDENCIES b/DEPENDENCIES
new file mode 100644
index 0000000..bffe3d9
--- /dev/null
+++ b/DEPENDENCIES
@@ -0,0 +1,66 @@
+maven/mavencentral/args4j/args4j/2.33, MIT, approved, CQ11068
+maven/mavencentral/com.google.code.gson/gson/2.8.6, Apache-2.0, approved, CQ23102
+maven/mavencentral/com.googlecode.javaewah/JavaEWAH/1.1.7, Apache-2.0, approved, CQ11658
+maven/mavencentral/com.jcraft/jsch/0.1.55, BSD-3-Clause, approved, CQ19435
+maven/mavencentral/com.jcraft/jzlib/1.1.1, BSD-2-Clause, approved, CQ6218
+maven/mavencentral/commons-codec/commons-codec/1.11, Apache-2.0, approved, CQ15971
+maven/mavencentral/commons-logging/commons-logging/1.2, Apache-2.0, approved, CQ10162
+maven/mavencentral/javax.servlet/javax.servlet-api/3.1.0, Apache-2.0 AND (CDDL-1.1 OR GPL-2.0 WITH Classpath-exception-2.0), approved, emo_ip_team
+maven/mavencentral/junit/junit/4.13, , approved, CQ22796
+maven/mavencentral/log4j/log4j/1.2.15, Apache-2.0, approved, CQ7837
+maven/mavencentral/net.bytebuddy/byte-buddy-agent/1.9.0, Apache-2.0, approved, clearlydefined
+maven/mavencentral/net.bytebuddy/byte-buddy/1.9.0, Apache-2.0, approved, clearlydefined
+maven/mavencentral/net.i2p.crypto/eddsa/0.3.0, CC0, approved, CQ17804
+maven/mavencentral/net.sf.jopt-simple/jopt-simple/4.6, MIT, approved, clearlydefined
+maven/mavencentral/org.apache.ant/ant-launcher/1.10.8, Apache-2.0 AND W3C AND LicenseRef-Public-Domain, approved, CQ15560
+maven/mavencentral/org.apache.ant/ant/1.10.8, Apache-2.0 AND W3C AND LicenseRef-Public-Domain, approved, CQ15560
+maven/mavencentral/org.apache.commons/commons-compress/1.19, Apache-2.0, approved, clearlydefined
+maven/mavencentral/org.apache.commons/commons-math3/3.2, Apache-2.0, approved, clearlydefined
+maven/mavencentral/org.apache.httpcomponents/httpclient/4.5.13, Apache-2.0, approved, CQ22761
+maven/mavencentral/org.apache.httpcomponents/httpcore/4.4.14, Apache-2.0, approved, CQ18704
+maven/mavencentral/org.apache.sshd/sshd-common/2.6.0, Apache-2.0 AND ISC, approved, CQ22992
+maven/mavencentral/org.apache.sshd/sshd-core/2.6.0, Apache-2.0 AND ISC, approved, CQ22992
+maven/mavencentral/org.apache.sshd/sshd-osgi/2.6.0, Apache-2.0 AND ISC, approved, CQ22992
+maven/mavencentral/org.apache.sshd/sshd-sftp/2.6.0, Apache-2.0 AND ISC, approved, CQ22993
+maven/mavencentral/org.assertj/assertj-core/3.14.0, Apache-2.0, approved, clearlydefined
+maven/mavencentral/org.bouncycastle/bcpg-jdk15on/1.65, Apache-2.0, approved, CQ21975
+maven/mavencentral/org.bouncycastle/bcpkix-jdk15on/1.65, MIT AND LicenseRef-Public-Domain, approved, CQ21976
+maven/mavencentral/org.bouncycastle/bcprov-jdk15on/1.65.01, MIT AND LicenseRef-Public-Domain, approved, CQ21977
+maven/mavencentral/org.eclipse.jetty/jetty-http/9.4.36.v20210114, , approved, eclipse
+maven/mavencentral/org.eclipse.jetty/jetty-io/9.4.36.v20210114, , approved, eclipse
+maven/mavencentral/org.eclipse.jetty/jetty-security/9.4.36.v20210114, , approved, eclipse
+maven/mavencentral/org.eclipse.jetty/jetty-server/9.4.36.v20210114, , approved, eclipse
+maven/mavencentral/org.eclipse.jetty/jetty-servlet/9.4.36.v20210114, , approved, eclipse
+maven/mavencentral/org.eclipse.jetty/jetty-util-ajax/9.4.36.v20210114, , approved, eclipse
+maven/mavencentral/org.eclipse.jetty/jetty-util/9.4.36.v20210114, , approved, eclipse
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ant.test/5.11.0-SNAPSHOT, , approved, eclipse
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ant/5.11.0-SNAPSHOT, , approved, eclipse
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.archive/5.11.0-SNAPSHOT, , approved, eclipse
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.gpg.bc/5.11.0-SNAPSHOT, , approved, eclipse
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.http.apache/5.11.0-SNAPSHOT, , approved, eclipse
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.http.server/5.11.0-SNAPSHOT, , approved, eclipse
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.http.test/5.11.0-SNAPSHOT, , approved, eclipse
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.junit.http/5.11.0-SNAPSHOT, , approved, eclipse
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.junit.ssh/5.11.0-SNAPSHOT, , approved, eclipse
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.junit/5.11.0-SNAPSHOT, , approved, eclipse
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.lfs.server.test/5.11.0-SNAPSHOT, , approved, eclipse
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.lfs.server/5.11.0-SNAPSHOT, , approved, eclipse
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.lfs.test/5.11.0-SNAPSHOT, , approved, eclipse
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.lfs/5.11.0-SNAPSHOT, , approved, eclipse
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.pgm.test/5.11.0-SNAPSHOT, , approved, eclipse
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.pgm/5.11.0-SNAPSHOT, , approved, eclipse
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ssh.apache.test/5.11.0-SNAPSHOT, , approved, eclipse
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ssh.apache/5.11.0-SNAPSHOT, , approved, eclipse
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ssh.jsch/5.11.0-SNAPSHOT, , approved, eclipse
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.test/5.11.0-SNAPSHOT, , approved, eclipse
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ui/5.11.0-SNAPSHOT, , approved, eclipse
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit/5.11.0-SNAPSHOT, , approved, eclipse
+maven/mavencentral/org.hamcrest/hamcrest-core/1.3, BSD-2-Clause, approved, CQ7063
+maven/mavencentral/org.mockito/mockito-core/2.23.0, MIT, approved, CQ17976
+maven/mavencentral/org.objenesis/objenesis/2.6, Apache-2.0, approved, CQ15478
+maven/mavencentral/org.openjdk.jmh/jmh-core/1.21, GPL-2.0, approved, CQ20517
+maven/mavencentral/org.openjdk.jmh/jmh-generator-annprocess/1.21, GPL-2.0, approved, CQ20518
+maven/mavencentral/org.osgi/org.osgi.core/4.3.1, Apache-2.0, approved, CQ10111
+maven/mavencentral/org.slf4j/slf4j-api/1.7.30, MIT, approved, CQ13368
+maven/mavencentral/org.slf4j/slf4j-log4j12/1.7.30, MIT, approved, CQ7665
+maven/mavencentral/org.tukaani/xz/1.8, LicenseRef-Public-Domain, approved, CQ15386
diff --git a/WORKSPACE b/WORKSPACE
index ad04d14..224968a 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -111,26 +111,26 @@
 
 maven_jar(
     name = "httpclient",
-    artifact = "org.apache.httpcomponents:httpclient:4.5.10",
-    sha1 = "7ca2e4276f4ef95e4db725a8cd4a1d1e7585b9e5",
+    artifact = "org.apache.httpcomponents:httpclient:4.5.13",
+    sha1 = "e5f6cae5ca7ecaac1ec2827a9e2d65ae2869cada",
 )
 
 maven_jar(
     name = "httpcore",
-    artifact = "org.apache.httpcomponents:httpcore:4.4.12",
-    sha1 = "21ebaf6d532bc350ba95bd81938fa5f0e511c132",
+    artifact = "org.apache.httpcomponents:httpcore:4.4.14",
+    sha1 = "9dd1a631c082d92ecd4bd8fd4cf55026c720a8c1",
 )
 
 maven_jar(
     name = "sshd-osgi",
-    artifact = "org.apache.sshd:sshd-osgi:2.4.0",
-    sha1 = "fc4551c1eeda35e4671b263297d37d2bca81c4d4",
+    artifact = "org.apache.sshd:sshd-osgi:2.6.0",
+    sha1 = "40e365bb799e1bff3d31dc858b1e59a93c123f29",
 )
 
 maven_jar(
     name = "sshd-sftp",
-    artifact = "org.apache.sshd:sshd-sftp:2.4.0",
-    sha1 = "92e1b7d1e19c715efb4a8871d34145da8f87cdb2",
+    artifact = "org.apache.sshd:sshd-sftp:2.6.0",
+    sha1 = "6eddfe8fdf59a3d9a49151e4177f8c1bebeb30c9",
 )
 
 maven_jar(
@@ -233,52 +233,59 @@
 
 maven_jar(
     name = "gson",
-    artifact = "com.google.code.gson:gson:2.8.2",
-    sha1 = "3edcfe49d2c6053a70a2a47e4e1c2f94998a49cf",
+    artifact = "com.google.code.gson:gson:2.8.6",
+    sha1 = "9180733b7df8542621dc12e21e87557e8c99b8cb",
 )
 
-JETTY_VER = "9.4.30.v20200611"
+JETTY_VER = "9.4.36.v20210114"
 
 maven_jar(
     name = "jetty-servlet",
     artifact = "org.eclipse.jetty:jetty-servlet:" + JETTY_VER,
-    sha1 = "ca3dea2cd34ee88cec017001603af0c9e74781d6",
-    src_sha1 = "6908f24428060bd542bddfa3e89e03d0dbbc2a6d",
+    sha1 = "b189e52a5ee55ae172e4e99e29c5c314f5daf4b9",
+    src_sha1 = "3a0fa449772ab0d76625f6afb81f60c32a490613",
 )
 
 maven_jar(
     name = "jetty-security",
     artifact = "org.eclipse.jetty:jetty-security:" + JETTY_VER,
-    sha1 = "1a5261f6ad4081ad9e9bb01416d639931d391273",
-    src_sha1 = "6ca41b34aa4f84c267603edd4b069122bd5f17d3",
+    sha1 = "42030d6ed7dfc0f75818cde0adcf738efc477574",
+    src_sha1 = "612220a97d45fad3983ccc56b0cb9a271f3fd003",
 )
 
 maven_jar(
     name = "jetty-server",
     artifact = "org.eclipse.jetty:jetty-server:" + JETTY_VER,
-    sha1 = "e5ede3724d062717d0c04e4c77f74fe8115c2a6f",
-    src_sha1 = "c8b02a47a35c1f083b310cbd202738cf08bc1d55",
+    sha1 = "88a7d342974aadca658e7386e8d0fcc5c0788f41",
+    src_sha1 = "4552c0c6db2948e8557db477b6b48d291006e481",
 )
 
 maven_jar(
     name = "jetty-http",
     artifact = "org.eclipse.jetty:jetty-http:" + JETTY_VER,
-    sha1 = "cd6223382e4f82b9ea807d8cdb04a23e5d629f1c",
-    src_sha1 = "00520c04b10609b981159b5ca284b5a158c077a9",
+    sha1 = "1eee89a55e04ff94df0f85d95200fc48acb43d86",
+    src_sha1 = "552a784ec789c7ba581c5341ae6d8b6353ed5ace",
 )
 
 maven_jar(
     name = "jetty-io",
     artifact = "org.eclipse.jetty:jetty-io:" + JETTY_VER,
-    sha1 = "9c360d08e903b2dbd5d1f8e889a32046948628ce",
-    src_sha1 = "dac8f8a3f84afdd3686d36f58b5ccb276961b8ce",
+    sha1 = "84a8faf9031eb45a5a2ddb7681e22c483d81ab3a",
+    src_sha1 = "72d5fc6d909e28f8720394b25babda80805a46b9",
 )
 
 maven_jar(
     name = "jetty-util",
     artifact = "org.eclipse.jetty:jetty-util:" + JETTY_VER,
-    sha1 = "39ec6aa4745952077f5407cb1394d8ba2db88b13",
-    src_sha1 = "f41f9391f91884a79350f3ad9b09b8e46c9be0ec",
+    sha1 = "925257fbcca6b501a25252c7447dbedb021f7404",
+    src_sha1 = "532e8b66044f4e58ca5da3aec19f02a2f3c16ddd",
+)
+
+maven_jar(
+    name = "jetty-util-ajax",
+    artifact = "org.eclipse.jetty:jetty-util-ajax:" + JETTY_VER,
+    sha1 = "2f478130c21787073facb64d7242e06f94980c60",
+    src_sha1 = "7153d7ca38878d971fd90992c303bb7719ba7a21",
 )
 
 BOUNCYCASTLE_VER = "1.65"
diff --git a/lib/BUILD b/lib/BUILD
index 7720696..8ad49d4 100644
--- a/lib/BUILD
+++ b/lib/BUILD
@@ -132,7 +132,10 @@
     name = "jetty-servlet",
     # TODO: This should be testonly but org.eclipse.jgit.pgm depends on it.
     visibility = ["//visibility:public"],
-    exports = ["@jetty-servlet//jar"],
+    exports = [
+        "@jetty-servlet//jar",
+        "@jetty-util-ajax//jar",
+    ],
 )
 
 java_library(
@@ -159,6 +162,7 @@
         "//org.eclipse.jgit:__pkg__",
         "//org.eclipse.jgit.gpg.bc:__pkg__",
         "//org.eclipse.jgit.test:__pkg__",
+        "//org.eclipse.jgit.gpg.bc.test:__pkg__",
     ],
     exports = ["@bcpg//jar"],
 )
@@ -169,6 +173,7 @@
         "//org.eclipse.jgit:__pkg__",
         "//org.eclipse.jgit.gpg.bc:__pkg__",
         "//org.eclipse.jgit.test:__pkg__",
+        "//org.eclipse.jgit.gpg.bc.test:__pkg__",
     ],
     exports = ["@bcprov//jar"],
 )
diff --git a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
index e1c5192..e0d802e 100644
--- a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
@@ -5,13 +5,13 @@
 Automatic-Module-Name: org.eclipse.jgit.ant.test
 Bundle-SymbolicName: org.eclipse.jgit.ant.test
 Bundle-Vendor: %Bundle-Vendor
-Bundle-Version: 5.10.1.qualifier
+Bundle-Version: 5.11.2.qualifier
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Import-Package: org.apache.tools.ant,
- org.eclipse.jgit.ant.tasks;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.junit;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lib;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.util;version="[5.10.1,5.11.0)",
+ org.eclipse.jgit.ant.tasks;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.junit;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.lib;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.util;version="[5.11.2,5.12.0)",
  org.hamcrest.core;version="[1.1.0,2.0.0)",
  org.junit;version="[4.13,5.0.0)"
diff --git a/org.eclipse.jgit.ant.test/pom.xml b/org.eclipse.jgit.ant.test/pom.xml
index 002c7fe..155e763 100644
--- a/org.eclipse.jgit.ant.test/pom.xml
+++ b/org.eclipse.jgit.ant.test/pom.xml
@@ -17,7 +17,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.10.1-SNAPSHOT</version>
+    <version>5.11.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.ant.test</artifactId>
diff --git a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
index ea2bd15..f3ecc34 100644
--- a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
@@ -3,13 +3,13 @@
 Bundle-Name: %Bundle-Name
 Automatic-Module-Name: org.eclipse.jgit.ant
 Bundle-SymbolicName: org.eclipse.jgit.ant
-Bundle-Version: 5.10.1.qualifier
+Bundle-Version: 5.11.2.qualifier
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Import-Package: org.apache.tools.ant,
-  org.eclipse.jgit.storage.file;version="[5.10.1,5.11.0)"
+  org.eclipse.jgit.storage.file;version="[5.11.2,5.12.0)"
 Bundle-Localization: plugin
 Bundle-Vendor: %Bundle-Vendor
-Export-Package: org.eclipse.jgit.ant;version="5.10.1",
- org.eclipse.jgit.ant.tasks;version="5.10.1";
+Export-Package: org.eclipse.jgit.ant;version="5.11.2",
+ org.eclipse.jgit.ant.tasks;version="5.11.2";
   uses:="org.apache.tools.ant,
    org.apache.tools.ant.types"
diff --git a/org.eclipse.jgit.ant/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.ant/META-INF/SOURCE-MANIFEST.MF
index aacb3c4..4ed9bc0 100644
--- a/org.eclipse.jgit.ant/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.ant/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
 Bundle-Name: org.eclipse.jgit.ant - Sources
 Bundle-SymbolicName: org.eclipse.jgit.ant.source
 Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 5.10.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.ant;version="5.10.1.qualifier";roots="."
+Bundle-Version: 5.11.2.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.ant;version="5.11.2.qualifier";roots="."
diff --git a/org.eclipse.jgit.ant/pom.xml b/org.eclipse.jgit.ant/pom.xml
index 927fe4c..0ef0f28 100644
--- a/org.eclipse.jgit.ant/pom.xml
+++ b/org.eclipse.jgit.ant/pom.xml
@@ -15,7 +15,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.10.1-SNAPSHOT</version>
+    <version>5.11.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.ant</artifactId>
diff --git a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
index 0f98722..a772db1 100644
--- a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-Name: %Bundle-Name
 Automatic-Module-Name: org.eclipse.jgit.archive
 Bundle-SymbolicName: org.eclipse.jgit.archive
-Bundle-Version: 5.10.1.qualifier
+Bundle-Version: 5.11.2.qualifier
 Bundle-Vendor: %Bundle-Vendor
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
@@ -13,17 +13,17 @@
  org.apache.commons.compress.compressors.bzip2;version="[1.4,2.0)",
  org.apache.commons.compress.compressors.gzip;version="[1.4,2.0)",
  org.apache.commons.compress.compressors.xz;version="[1.4,2.0)",
- org.eclipse.jgit.api;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lib;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.nls;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.revwalk;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.util;version="[5.10.1,5.11.0)",
+ org.eclipse.jgit.api;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.lib;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.nls;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.revwalk;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.util;version="[5.11.2,5.12.0)",
  org.osgi.framework;version="[1.3.0,2.0.0)"
 Bundle-ActivationPolicy: lazy
 Bundle-Activator: org.eclipse.jgit.archive.FormatActivator
-Export-Package: org.eclipse.jgit.archive;version="5.10.1";
+Export-Package: org.eclipse.jgit.archive;version="5.11.2";
   uses:="org.eclipse.jgit.lib,
    org.eclipse.jgit.api,
    org.apache.commons.compress.archivers,
    org.osgi.framework",
- org.eclipse.jgit.archive.internal;version="5.10.1";x-internal:=true
+ org.eclipse.jgit.archive.internal;version="5.11.2";x-internal:=true
diff --git a/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF
index 7c8f179..749a21e 100644
--- a/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
 Bundle-Name: org.eclipse.jgit.archive - Sources
 Bundle-SymbolicName: org.eclipse.jgit.archive.source
 Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 5.10.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.archive;version="5.10.1.qualifier";roots="."
+Bundle-Version: 5.11.2.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.archive;version="5.11.2.qualifier";roots="."
diff --git a/org.eclipse.jgit.archive/pom.xml b/org.eclipse.jgit.archive/pom.xml
index a11e015..6cb8675 100644
--- a/org.eclipse.jgit.archive/pom.xml
+++ b/org.eclipse.jgit.archive/pom.xml
@@ -17,7 +17,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.10.1-SNAPSHOT</version>
+    <version>5.11.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.archive</artifactId>
diff --git a/org.eclipse.jgit.archive/resources/org/eclipse/jgit/archive/internal/ArchiveText.properties b/org.eclipse.jgit.archive/resources/org/eclipse/jgit/archive/internal/ArchiveText.properties
index 3b50bb4..e6e1227 100644
--- a/org.eclipse.jgit.archive/resources/org/eclipse/jgit/archive/internal/ArchiveText.properties
+++ b/org.eclipse.jgit.archive/resources/org/eclipse/jgit/archive/internal/ArchiveText.properties
@@ -1,3 +1,4 @@
 cannotSetOption=Cannot set option: {0}
+invalidCompressionLevel=Invalid compression level: {0}
 pathDoesNotMatchMode=Path {0} does not match mode {1}
 unsupportedMode=Unsupported mode {0}
diff --git a/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/BaseFormat.java b/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/BaseFormat.java
index 27f001e..0ebac77 100644
--- a/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/BaseFormat.java
+++ b/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/BaseFormat.java
@@ -25,6 +25,11 @@
  * @since 4.0
  */
 public class BaseFormat {
+	/**
+	 * Compression-level for the archive file. Only values in [0-9] are allowed.
+	 * @since 5.11
+	 */
+	protected static final String COMPRESSION_LEVEL = "compression-level"; //$NON-NLS-1$
 
 	/**
 	 * Apply options to archive output stream
@@ -40,6 +45,9 @@ protected ArchiveOutputStream applyFormatOptions(ArchiveOutputStream s,
 			Map<String, Object> o) throws IOException {
 		for (Map.Entry<String, Object> p : o.entrySet()) {
 			try {
+				if (p.getKey().equals(COMPRESSION_LEVEL)) {
+					continue;
+				}
 				new Statement(s, "set" + StringUtils.capitalize(p.getKey()), //$NON-NLS-1$
 						new Object[] { p.getValue() }).execute();
 			} catch (Exception e) {
@@ -49,4 +57,32 @@ protected ArchiveOutputStream applyFormatOptions(ArchiveOutputStream s,
 		}
 		return s;
 	}
+
+	/**
+	 * Removes and returns the {@link #COMPRESSION_LEVEL} key from the input map
+	 * parameter if it exists, or -1 if this key does not exist.
+	 *
+	 * @param o
+	 *            options map
+	 * @return The compression level if it exists in the map, or -1 instead.
+	 * @throws IllegalArgumentException
+	 *             if the {@link #COMPRESSION_LEVEL} option does not parse to an
+	 *             Integer.
+	 * @since 5.11
+	 */
+	protected int getCompressionLevel(Map<String, Object> o) {
+		if (!o.containsKey(COMPRESSION_LEVEL)) {
+			return -1;
+		}
+		Object option = o.get(COMPRESSION_LEVEL);
+		try {
+			Integer compressionLevel = (Integer) option;
+			return compressionLevel.intValue();
+		} catch (ClassCastException e) {
+			throw new IllegalArgumentException(
+					MessageFormat.format(
+							ArchiveText.get().invalidCompressionLevel, option),
+					e);
+		}
+	}
 }
diff --git a/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/Tbz2Format.java b/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/Tbz2Format.java
index e880f5e..940dafd 100644
--- a/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/Tbz2Format.java
+++ b/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/Tbz2Format.java
@@ -45,7 +45,13 @@ public ArchiveOutputStream createArchiveOutputStream(OutputStream s)
 	@Override
 	public ArchiveOutputStream createArchiveOutputStream(OutputStream s,
 			Map<String, Object> o) throws IOException {
-		BZip2CompressorOutputStream out = new BZip2CompressorOutputStream(s);
+		BZip2CompressorOutputStream out;
+		int compressionLevel = getCompressionLevel(o);
+		if (compressionLevel != -1) {
+			out = new BZip2CompressorOutputStream(s, compressionLevel);
+		} else {
+			out = new BZip2CompressorOutputStream(s);
+		}
 		return tarFormat.createArchiveOutputStream(out, o);
 	}
 
diff --git a/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/TgzFormat.java b/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/TgzFormat.java
index 859a59d..72e2439 100644
--- a/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/TgzFormat.java
+++ b/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/TgzFormat.java
@@ -18,6 +18,7 @@
 
 import org.apache.commons.compress.archivers.ArchiveOutputStream;
 import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
+import org.apache.commons.compress.compressors.gzip.GzipParameters;
 import org.eclipse.jgit.api.ArchiveCommand;
 import org.eclipse.jgit.lib.FileMode;
 import org.eclipse.jgit.lib.ObjectId;
@@ -45,7 +46,15 @@ public ArchiveOutputStream createArchiveOutputStream(OutputStream s)
 	@Override
 	public ArchiveOutputStream createArchiveOutputStream(OutputStream s,
 			Map<String, Object> o) throws IOException {
-		GzipCompressorOutputStream out = new GzipCompressorOutputStream(s);
+		GzipCompressorOutputStream out;
+		int compressionLevel = getCompressionLevel(o);
+		if (compressionLevel != -1) {
+			GzipParameters parameters = new GzipParameters();
+			parameters.setCompressionLevel(compressionLevel);
+			out = new GzipCompressorOutputStream(s, parameters);
+		} else {
+			out = new GzipCompressorOutputStream(s);
+		}
 		return tarFormat.createArchiveOutputStream(out, o);
 	}
 
diff --git a/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/TxzFormat.java b/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/TxzFormat.java
index 484ab57..b16fb6d 100644
--- a/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/TxzFormat.java
+++ b/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/TxzFormat.java
@@ -45,7 +45,13 @@ public ArchiveOutputStream createArchiveOutputStream(OutputStream s)
 	@Override
 	public ArchiveOutputStream createArchiveOutputStream(OutputStream s,
 			Map<String, Object> o) throws IOException {
-		XZCompressorOutputStream out = new XZCompressorOutputStream(s);
+		XZCompressorOutputStream out;
+		int compressionLevel = getCompressionLevel(o);
+		if (compressionLevel != -1) {
+			out = new XZCompressorOutputStream(s, compressionLevel);
+		} else {
+			out = new XZCompressorOutputStream(s);
+		}
 		return tarFormat.createArchiveOutputStream(out, o);
 	}
 
diff --git a/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/ZipFormat.java b/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/ZipFormat.java
index 59a9765..97a24c7 100644
--- a/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/ZipFormat.java
+++ b/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/ZipFormat.java
@@ -47,7 +47,12 @@ public ArchiveOutputStream createArchiveOutputStream(OutputStream s)
 	@Override
 	public ArchiveOutputStream createArchiveOutputStream(OutputStream s,
 			Map<String, Object> o) throws IOException {
-		return applyFormatOptions(new ZipArchiveOutputStream(s), o);
+		ZipArchiveOutputStream out = new ZipArchiveOutputStream(s);
+		int compressionLevel = getCompressionLevel(o);
+		if (compressionLevel != -1) {
+			out.setLevel(compressionLevel);
+		}
+		return applyFormatOptions(out, o);
 	}
 
 	/** {@inheritDoc} */
diff --git a/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/internal/ArchiveText.java b/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/internal/ArchiveText.java
index 45f96fa..551646b 100644
--- a/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/internal/ArchiveText.java
+++ b/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/internal/ArchiveText.java
@@ -28,6 +28,7 @@ public static ArchiveText get() {
 
 	// @formatter:off
 	/***/ public String cannotSetOption;
+	/***/ public String invalidCompressionLevel;
 	/***/ public String pathDoesNotMatchMode;
 	/***/ public String unsupportedMode;
 }
diff --git a/org.eclipse.jgit.benchmarks/.settings/edu.umd.cs.findbugs.core.prefs b/org.eclipse.jgit.benchmarks/.settings/edu.umd.cs.findbugs.core.prefs
new file mode 100644
index 0000000..1c0a344
--- /dev/null
+++ b/org.eclipse.jgit.benchmarks/.settings/edu.umd.cs.findbugs.core.prefs
@@ -0,0 +1,145 @@
+#SpotBugs User Preferences
+#Fri Dec 04 10:39:51 CET 2020
+detectorExplicitSerialization=ExplicitSerialization|true
+detectorMultithreadedInstanceAccess=MultithreadedInstanceAccess|true
+detectorConfusionBetweenInheritedAndOuterMethod=ConfusionBetweenInheritedAndOuterMethod|true
+detectorWrongMapIterator=WrongMapIterator|true
+detectorUnnecessaryMath=UnnecessaryMath|true
+detectorUselessSubclassMethod=UselessSubclassMethod|false
+filter_settings=Medium|BAD_PRACTICE,CORRECTNESS,EXPERIMENTAL,I18N,MALICIOUS_CODE,MT_CORRECTNESS,PERFORMANCE,SECURITY,STYLE|false|15
+detectorURLProblems=URLProblems|true
+detectorIteratorIdioms=IteratorIdioms|true
+detectorMutableEnum=MutableEnum|true
+detectorFindNonShortCircuit=FindNonShortCircuit|true
+detectorSynchronizeAndNullCheckField=SynchronizeAndNullCheckField|true
+detectorVolatileUsage=VolatileUsage|true
+detectorFindNakedNotify=FindNakedNotify|true
+detectorFindUninitializedGet=FindUninitializedGet|true
+detectorFindUseOfNonSerializableValue=FindUseOfNonSerializableValue|true
+detectorFindJSR166LockMonitorenter=FindJSR166LockMonitorenter|true
+detectorQuestionableBooleanAssignment=QuestionableBooleanAssignment|true
+detectorSwitchFallthrough=SwitchFallthrough|true
+detectorFindLocalSelfAssignment2=FindLocalSelfAssignment2|true
+detectorConfusedInheritance=ConfusedInheritance|true
+detectorSynchronizationOnSharedBuiltinConstant=SynchronizationOnSharedBuiltinConstant|true
+detectorMutableStaticFields=MutableStaticFields|true
+detectorInvalidJUnitTest=InvalidJUnitTest|true
+detectorInfiniteLoop=InfiniteLoop|true
+detectorFindRunInvocations=FindRunInvocations|true
+detectorBadSyntaxForRegularExpression=BadSyntaxForRegularExpression|true
+detectorXMLFactoryBypass=XMLFactoryBypass|true
+detectorFindOpenStream=FindOpenStream|true
+detectorCheckExpectedWarnings=CheckExpectedWarnings|false
+detectorHugeSharedStringConstants=HugeSharedStringConstants|true
+detectorLostLoggerDueToWeakReference=LostLoggerDueToWeakReference|true
+detectorStringConcatenation=StringConcatenation|true
+detectorLoadOfKnownNullValue=LoadOfKnownNullValue|true
+detectorFinalizerNullsFields=FinalizerNullsFields|true
+detectorFindFieldSelfAssignment=FindFieldSelfAssignment|true
+detectorInefficientToArray=InefficientToArray|false
+detectorDontCatchIllegalMonitorStateException=DontCatchIllegalMonitorStateException|true
+detectorInconsistentAnnotations=InconsistentAnnotations|true
+detectorBadlyOverriddenAdapter=BadlyOverriddenAdapter|true
+detectorInstantiateStaticClass=InstantiateStaticClass|true
+detectorCheckRelaxingNullnessAnnotation=CheckRelaxingNullnessAnnotation|true
+detectorMethodReturnCheck=MethodReturnCheck|true
+detectorEqualsOperandShouldHaveClassCompatibleWithThis=EqualsOperandShouldHaveClassCompatibleWithThis|true
+detectorFindDoubleCheck=FindDoubleCheck|true
+detectorFindBadForLoop=FindBadForLoop|true
+detectorDefaultEncodingDetector=DefaultEncodingDetector|true
+detectorFindInconsistentSync2=FindInconsistentSync2|true
+detectorFindSpinLoop=FindSpinLoop|true
+detectorFindMaskedFields=FindMaskedFields|true
+detectorBooleanReturnNull=BooleanReturnNull|true
+detectorFindUnsyncGet=FindUnsyncGet|true
+detectorCrossSiteScripting=CrossSiteScripting|true
+detectorDroppedException=DroppedException|true
+detectorFindDeadLocalStores=FindDeadLocalStores|true
+detectorCheckImmutableAnnotation=CheckImmutableAnnotation|true
+detectorInfiniteRecursiveLoop=InfiniteRecursiveLoop|true
+detectorFindRefComparison=FindRefComparison|true
+detectorFindRoughConstants=FindRoughConstants|true
+detectorMutableLock=MutableLock|true
+detectorFindNullDeref=FindNullDeref|true
+detectorFindReturnRef=FindReturnRef|true
+detectorSynchronizeOnClassLiteralNotGetClass=SynchronizeOnClassLiteralNotGetClass|true
+detectorFindUselessControlFlow=FindUselessControlFlow|true
+detectorOverridingEqualsNotSymmetrical=OverridingEqualsNotSymmetrical|true
+detectorIDivResultCastToDouble=IDivResultCastToDouble|true
+detectorReadOfInstanceFieldInMethodInvokedByConstructorInSuperclass=ReadOfInstanceFieldInMethodInvokedByConstructorInSuperclass|true
+detectorFindSelfComparison=FindSelfComparison|true
+detectorFindFloatEquality=FindFloatEquality|true
+detectorFindComparatorProblems=FindComparatorProblems|true
+detectorRepeatedConditionals=RepeatedConditionals|true
+filter_settings_neg=NOISE|
+detectorInefficientMemberAccess=InefficientMemberAccess|false
+detectorFindUncalledPrivateMethods=FindUncalledPrivateMethods|true
+detectorNumberConstructor=NumberConstructor|true
+detectorDontAssertInstanceofInTests=DontAssertInstanceofInTests|true
+detectorFindFinalizeInvocations=FindFinalizeInvocations|true
+detectorFindNullDerefsInvolvingNonShortCircuitEvaluation=FindNullDerefsInvolvingNonShortCircuitEvaluation|true
+detectorDontIgnoreResultOfPutIfAbsent=DontIgnoreResultOfPutIfAbsent|true
+detectorFindUnconditionalWait=FindUnconditionalWait|true
+detectorFindTwoLockWait=FindTwoLockWait|true
+detectorFindSleepWithLockHeld=FindSleepWithLockHeld|true
+detectorFindUnreleasedLock=FindUnreleasedLock|true
+detectorInefficientIndexOf=InefficientIndexOf|false
+detectorDoInsideDoPrivileged=DoInsideDoPrivileged|true
+detectorFindEmptySynchronizedBlock=FindEmptySynchronizedBlock|true
+detectorOverridingMethodsMustInvokeSuperDetector=OverridingMethodsMustInvokeSuperDetector|true
+detectorWaitInLoop=WaitInLoop|true
+detectorIntCast2LongAsInstant=IntCast2LongAsInstant|true
+detectorBadUseOfReturnValue=BadUseOfReturnValue|true
+detectorFindSqlInjection=FindSqlInjection|true
+detectorUnreadFields=UnreadFields|true
+detectorSynchronizingOnContentsOfFieldToProtectField=SynchronizingOnContentsOfFieldToProtectField|true
+detectorFindUselessObjects=FindUselessObjects|true
+detectorBadAppletConstructor=BadAppletConstructor|false
+detectorInheritanceUnsafeGetResource=InheritanceUnsafeGetResource|true
+detectorSerializableIdiom=SerializableIdiom|true
+detectorNaming=Naming|true
+detectorNoteUnconditionalParamDerefs=NoteUnconditionalParamDerefs|true
+detectorFormatStringChecker=FormatStringChecker|true
+detectorSuspiciousThreadInterrupted=SuspiciousThreadInterrupted|true
+detectorEmptyZipFileEntry=EmptyZipFileEntry|false
+detectorFindCircularDependencies=FindCircularDependencies|false
+detectorPreferZeroLengthArrays=PreferZeroLengthArrays|true
+detectorAtomicityProblem=AtomicityProblem|true
+detectorRuntimeExceptionCapture=RuntimeExceptionCapture|true
+detectorInitializationChain=InitializationChain|true
+detectorInitializeNonnullFieldsInConstructor=InitializeNonnullFieldsInConstructor|true
+detectorOptionalReturnNull=OptionalReturnNull|true
+detectorStartInConstructor=StartInConstructor|true
+detectorFindUnsatisfiedObligation=FindUnsatisfiedObligation|true
+detectorRedundantConditions=RedundantConditions|true
+effort=default
+detectorRedundantInterfaces=RedundantInterfaces|true
+detectorDuplicateBranches=DuplicateBranches|true
+detectorCheckTypeQualifiers=CheckTypeQualifiers|true
+detectorComparatorIdiom=ComparatorIdiom|true
+detectorFindBadCast2=FindBadCast2|true
+detectorFindMismatchedWaitOrNotify=FindMismatchedWaitOrNotify|true
+excludefilter0=findBugs/FindBugsExcludeFilter.xml|true
+detectorBadResultSetAccess=BadResultSetAccess|true
+detectorIncompatMask=IncompatMask|true
+detectorCovariantArrayAssignment=CovariantArrayAssignment|false
+detectorDumbMethodInvocations=DumbMethodInvocations|true
+run_at_full_build=false
+detectorStaticCalendarDetector=StaticCalendarDetector|true
+detectorUncallableMethodOfAnonymousClass=UncallableMethodOfAnonymousClass|true
+detectorVarArgsProblems=VarArgsProblems|true
+detectorInefficientInitializationInsideLoop=InefficientInitializationInsideLoop|false
+detectorCloneIdiom=CloneIdiom|true
+detectorFindHEmismatch=FindHEmismatch|true
+detectorAppendingToAnObjectOutputStream=AppendingToAnObjectOutputStream|true
+detectorFindSelfComparison2=FindSelfComparison2|true
+detectorLazyInit=LazyInit|true
+detectorFindUnrelatedTypesInGenericContainer=FindUnrelatedTypesInGenericContainer|true
+detectorDontUseEnum=DontUseEnum|true
+detectorFindPuzzlers=FindPuzzlers|true
+detectorCallToUnsupportedMethod=CallToUnsupportedMethod|false
+detectorSuperfluousInstanceOf=SuperfluousInstanceOf|true
+detectorReadReturnShouldBeChecked=ReadReturnShouldBeChecked|true
+detector_threshold=2
+detectorPublicSemaphores=PublicSemaphores|false
+detectorDumbMethods=DumbMethods|true
diff --git a/org.eclipse.jgit.benchmarks/findBugs/FindBugsExcludeFilter.xml b/org.eclipse.jgit.benchmarks/findBugs/FindBugsExcludeFilter.xml
new file mode 100644
index 0000000..ad63e8f
--- /dev/null
+++ b/org.eclipse.jgit.benchmarks/findBugs/FindBugsExcludeFilter.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<FindBugsFilter>
+     <!-- Silence warnings in classes generated by apt -->
+     <Match>
+       <Package name="org.eclipse.jgit.benchmarks.generated" />
+       <Bug pattern="DLS_DEAD_LOCAL_STORE" />
+     </Match>
+</FindBugsFilter>
diff --git a/org.eclipse.jgit.benchmarks/pom.xml b/org.eclipse.jgit.benchmarks/pom.xml
index 4033fdd..e26ac30 100644
--- a/org.eclipse.jgit.benchmarks/pom.xml
+++ b/org.eclipse.jgit.benchmarks/pom.xml
@@ -14,7 +14,7 @@
   <modelVersion>4.0.0</modelVersion>
 
   <groupId>org.eclipse.jgit</groupId>
-  <version>5.10.1-SNAPSHOT</version>
+  <version>5.11.2-SNAPSHOT</version>
   <artifactId>org.eclipse.jgit.benchmarks</artifactId>
   <packaging>jar</packaging>
 
@@ -51,51 +51,37 @@
     <plugins>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-compiler-plugin</artifactId>
-        <version>3.8.1</version>
-        <configuration>
-          <compilerVersion>${javac.target}</compilerVersion>
-          <source>${javac.target}</source>
-          <target>${javac.target}</target>
-          <generatedSourcesDirectory>.apt_generated</generatedSourcesDirectory>
-        </configuration>
+        <artifactId>maven-enforcer-plugin</artifactId>
+        <version>3.0.0-M3</version>
         <executions>
           <execution>
-            <id>compile-with-errorprone</id>
-            <phase>compile</phase>
+            <id>enforce-maven</id>
             <goals>
-              <goal>compile</goal>
+              <goal>enforce</goal>
             </goals>
             <configuration>
-              <compilerId>javac-with-errorprone</compilerId>
-              <forceJavacCompilerUse>true</forceJavacCompilerUse>
+              <rules>
+                <requireMavenVersion>
+                  <version>3.6.3</version>
+                </requireMavenVersion>
+              </rules>
             </configuration>
           </execution>
         </executions>
-        <dependencies>
-          <dependency>
-            <groupId>org.codehaus.plexus</groupId>
-            <artifactId>plexus-compiler-javac</artifactId>
-            <version>2.8.5</version>
-          </dependency>
-          <dependency>
-            <groupId>org.codehaus.plexus</groupId>
-            <artifactId>plexus-compiler-javac-errorprone</artifactId>
-            <version>2.8.5</version>
-          </dependency>
-          <!-- override plexus-compiler-javac-errorprone's dependency on
-               Error Prone with the latest version -->
-          <dependency>
-            <groupId>com.google.errorprone</groupId>
-            <artifactId>error_prone_core</artifactId>
-            <version>2.3.4</version>
-          </dependency>
-        </dependencies>
+      </plugin>
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <encoding>UTF-8</encoding>
+          <source>1.8</source>
+          <target>1.8</target>
+          <generatedSourcesDirectory>.apt_generated</generatedSourcesDirectory>
+        </configuration>
       </plugin>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-shade-plugin</artifactId>
-        <version>3.2.1</version>
+        <version>3.2.4</version>
         <executions>
           <execution>
             <phase>package</phase>
@@ -157,19 +143,19 @@
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-site-plugin</artifactId>
-          <version>3.8.2</version>
+          <version>3.9.1</version>
           <dependencies>
             <dependency><!-- add support for ssh/scp -->
               <groupId>org.apache.maven.wagon</groupId>
               <artifactId>wagon-ssh</artifactId>
-              <version>3.3.4</version>
+              <version>3.4.2</version>
             </dependency>
           </dependencies>
         </plugin>
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-surefire-report-plugin</artifactId>
-          <version>3.0.0-M3</version>
+          <version>3.0.0-M5</version>
         </plugin>
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
diff --git a/org.eclipse.jgit.coverage/pom.xml b/org.eclipse.jgit.coverage/pom.xml
index 94cce0a..6b02158 100644
--- a/org.eclipse.jgit.coverage/pom.xml
+++ b/org.eclipse.jgit.coverage/pom.xml
@@ -14,7 +14,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.10.1-SNAPSHOT</version>
+    <version>5.11.2-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
@@ -27,88 +27,88 @@
     <dependency>
       <groupId>org.eclipse.jgit</groupId>
       <artifactId>org.eclipse.jgit</artifactId>
-      <version>5.10.1-SNAPSHOT</version>
+      <version>5.11.2-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jgit</groupId>
       <artifactId>org.eclipse.jgit.ant</artifactId>
-      <version>5.10.1-SNAPSHOT</version>
+      <version>5.11.2-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jgit</groupId>
       <artifactId>org.eclipse.jgit.archive</artifactId>
-      <version>5.10.1-SNAPSHOT</version>
+      <version>5.11.2-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jgit</groupId>
       <artifactId>org.eclipse.jgit.http.apache</artifactId>
-      <version>5.10.1-SNAPSHOT</version>
+      <version>5.11.2-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jgit</groupId>
       <artifactId>org.eclipse.jgit.http.server</artifactId>
-      <version>5.10.1-SNAPSHOT</version>
+      <version>5.11.2-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jgit</groupId>
       <artifactId>org.eclipse.jgit.lfs</artifactId>
-      <version>5.10.1-SNAPSHOT</version>
+      <version>5.11.2-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jgit</groupId>
       <artifactId>org.eclipse.jgit.lfs.server</artifactId>
-      <version>5.10.1-SNAPSHOT</version>
+      <version>5.11.2-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jgit</groupId>
       <artifactId>org.eclipse.jgit.pgm</artifactId>
-      <version>5.10.1-SNAPSHOT</version>
+      <version>5.11.2-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jgit</groupId>
       <artifactId>org.eclipse.jgit.ui</artifactId>
-      <version>5.10.1-SNAPSHOT</version>
+      <version>5.11.2-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jgit</groupId>
       <artifactId>org.eclipse.jgit.ssh.apache</artifactId>
-      <version>5.10.1-SNAPSHOT</version>
+      <version>5.11.2-SNAPSHOT</version>
     </dependency>
 
     <dependency>
       <groupId>org.eclipse.jgit</groupId>
       <artifactId>org.eclipse.jgit.test</artifactId>
-      <version>5.10.1-SNAPSHOT</version>
+      <version>5.11.2-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jgit</groupId>
       <artifactId>org.eclipse.jgit.ant.test</artifactId>
-      <version>5.10.1-SNAPSHOT</version>
+      <version>5.11.2-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jgit</groupId>
       <artifactId>org.eclipse.jgit.http.test</artifactId>
-      <version>5.10.1-SNAPSHOT</version>
+      <version>5.11.2-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jgit</groupId>
       <artifactId>org.eclipse.jgit.pgm.test</artifactId>
-      <version>5.10.1-SNAPSHOT</version>
+      <version>5.11.2-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jgit</groupId>
       <artifactId>org.eclipse.jgit.lfs.test</artifactId>
-      <version>5.10.1-SNAPSHOT</version>
+      <version>5.11.2-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jgit</groupId>
       <artifactId>org.eclipse.jgit.lfs.server.test</artifactId>
-      <version>5.10.1-SNAPSHOT</version>
+      <version>5.11.2-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jgit</groupId>
       <artifactId>org.eclipse.jgit.ssh.apache.test</artifactId>
-      <version>5.10.1-SNAPSHOT</version>
+      <version>5.11.2-SNAPSHOT</version>
     </dependency>
   </dependencies>
 
diff --git a/org.eclipse.jgit.gpg.bc.test/.classpath b/org.eclipse.jgit.gpg.bc.test/.classpath
index f08af0a..0acccba 100644
--- a/org.eclipse.jgit.gpg.bc.test/.classpath
+++ b/org.eclipse.jgit.gpg.bc.test/.classpath
@@ -2,10 +2,15 @@
 <classpath>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
-	<classpathentry kind="src" path="tst">
+	<classpathentry kind="src" output="bin-tst" path="tst">
 		<attributes>
 			<attribute name="test" value="true"/>
 		</attributes>
 	</classpathentry>
-	<classpathentry kind="output" path="bin"/>
+	<classpathentry kind="src" output="bin-tst" path="tst-rsrc">
+		<attributes>
+			<attribute name="test" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="output" path="bin-tst"/>
 </classpath>
diff --git a/org.eclipse.jgit.gpg.bc.test/.gitignore b/org.eclipse.jgit.gpg.bc.test/.gitignore
index 934e0e0..8b6760c 100644
--- a/org.eclipse.jgit.gpg.bc.test/.gitignore
+++ b/org.eclipse.jgit.gpg.bc.test/.gitignore
@@ -1,2 +1,3 @@
 /bin
+/bin-tst
 /target
diff --git a/org.eclipse.jgit.gpg.bc.test/BUILD b/org.eclipse.jgit.gpg.bc.test/BUILD
index 1e3677d..925536e 100644
--- a/org.eclipse.jgit.gpg.bc.test/BUILD
+++ b/org.eclipse.jgit.gpg.bc.test/BUILD
@@ -1,4 +1,9 @@
 load(
+    "@com_googlesource_gerrit_bazlets//tools:genrule2.bzl",
+    "genrule2",
+)
+load("@rules_java//java:defs.bzl", "java_import")
+load(
     "@com_googlesource_gerrit_bazlets//tools:junit.bzl",
     "junit_tests",
 )
@@ -8,7 +13,23 @@
     srcs = glob(["tst/**/*.java"]),
     tags = ["bc"],
     deps = [
+        "//lib:bcpg",
+        "//lib:bcprov",
         "//lib:junit",
+        "//org.eclipse.jgit:jgit",
         "//org.eclipse.jgit.gpg.bc:gpg-bc",
+        "//org.eclipse.jgit.gpg.bc.test:tst_rsrc",
     ],
 )
+
+java_import(
+    name = "tst_rsrc",
+    jars = [":tst_rsrc_jar"],
+)
+
+genrule2(
+    name = "tst_rsrc_jar",
+    srcs = glob(["tst-rsrc/**"]),
+    outs = ["tst_rsrc.jar"],
+    cmd = "o=$$PWD/$@ && tar cf - $(SRCS) | tar -C $$TMP --strip-components=2 -xf - && cd  $$TMP && zip -qr $$o .",
+)
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 2658c4c..0a121a7 100644
--- a/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF
@@ -3,12 +3,22 @@
 Bundle-Name: %Bundle-Name
 Automatic-Module-Name: org.eclipse.jgit.gpg.bc.test
 Bundle-SymbolicName: org.eclipse.jgit.gpg.bc.test
-Bundle-Version: 5.10.1.qualifier
+Bundle-Version: 5.11.2.qualifier
 Bundle-Vendor: %Bundle-Vendor
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.eclipse.jgit.gpg.bc.internal;version="[5.10.1,5.11.0)",
- org.junit;version="[4.13,5.0.0)"
-Export-Package: org.eclipse.jgit.gpg.bc.internal;x-internal:=true
+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)",
+ org.eclipse.jgit.gpg.bc.internal;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.gpg.bc.internal.keys;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.util.sha1;version="[5.11.2,5.12.0)",
+ org.junit;version="[4.13,5.0.0)",
+ org.junit.runner;version="[4.13,5.0.0)",
+ org.junit.runners;version="[4.13,5.0.0)"
+Export-Package: org.eclipse.jgit.gpg.bc.internal;x-internal:=true,
+ org.eclipse.jgit.gpg.bc.internal.keys;x-internal:=true
 Require-Bundle: org.hamcrest.core;bundle-version="[1.1.0,2.0.0)",
  org.hamcrest.library;bundle-version="[1.1.0,2.0.0)"
diff --git a/org.eclipse.jgit.gpg.bc.test/build.properties b/org.eclipse.jgit.gpg.bc.test/build.properties
index 9ffa0ca..e36d666 100644
--- a/org.eclipse.jgit.gpg.bc.test/build.properties
+++ b/org.eclipse.jgit.gpg.bc.test/build.properties
@@ -1,5 +1,5 @@
 source.. = tst/
-output.. = bin/
+output.. = bin-tst/
 bin.includes = META-INF/,\
                .,\
                plugin.properties
diff --git a/org.eclipse.jgit.gpg.bc.test/pom.xml b/org.eclipse.jgit.gpg.bc.test/pom.xml
index 6a119a8..08966f8 100644
--- a/org.eclipse.jgit.gpg.bc.test/pom.xml
+++ b/org.eclipse.jgit.gpg.bc.test/pom.xml
@@ -17,7 +17,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.10.1-SNAPSHOT</version>
+    <version>5.11.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.gpg.bc.test</artifactId>
@@ -85,6 +85,12 @@
     <sourceDirectory>src/</sourceDirectory>
     <testSourceDirectory>tst/</testSourceDirectory>
 
+    <testResources>
+      <testResource>
+        <directory>tst-rsrc/</directory>
+      </testResource>
+    </testResources>
+
     <plugins>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/2FB05DBB70FC07CB84C13431F640CA6CEA1DBF8A.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/2FB05DBB70FC07CB84C13431F640CA6CEA1DBF8A.asc
new file mode 100644
index 0000000..355462c
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/2FB05DBB70FC07CB84C13431F640CA6CEA1DBF8A.asc
@@ -0,0 +1,41 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQGNBGAHBLQBDACsS1vFqE3qgKD2R5X9n90Gz8bucwwvJWIqaHDsVoAtF6IcKIDo
+1hQC9YksTQYl/L7BsMDdmjyEbWRfzW4ory5596d342Hl6g7ZB5jJR5kJJdhy2MCJ
+BUiMy/724Fr/Dz8PNPcEoULz9ZH7HEaPRKqWWEQDUCq5ak0MfLKXtWVUBgsY5Mry
+29d/GLJvnxZ5v16PK+P4oqZ7vh7FWJPlqPK2TCZ6s1rYfWlu9XbHOzwXwozVg7IX
+tfFq4Rij4c0sg0S0GY8hGAlnOpRc/6J2S41Y8p3WqND6r1LPDQUFnNCKXVoHUGeK
+X9U5iAP7pxZSuonsFCqr3CDGxr+kKUpbfZeLrqTA4lBUK7T6w6Wq0qHosCYUU7YC
+GZjlEeCZBRWNfeq45LKlhdNUxHWWgaBsgWaaDmpFWaivblmQGOvmSv1nJMNmedRs
+DSF51nsJnkQceprsvThSa6qJwEYi7pj6L9HO2UGgJLCb3dL5VTQih2gdhghckUSB
+okUkvqBvvdiP2nEAEQEAAbQdVGVzdGVyMiA8dGVzdGVyMkBleGFtcGxlLm9yZz6J
+Ac4EEwEKADgWIQRPCAvglun3I2Bs1iITM2XBzCpwbgUCYAcEtAIbAwULCQgHAwUV
+CgkICwUWAgMBAAIeAQIXgAAKCRATM2XBzCpwboiBC/493+ruANV2eiro8MY8wZ3Y
+gdjp3pHBSg9RK74SIh95J+MW5qzPwkU+vHd8l0+aj9e1sDQb5BFcFk/Z1ioI3TDW
+B4vYWoMkdN932fJ/LcIlhOGjWwSNFZphbYmJzrAwUTA499yx3jt9Dg+vSU88S+8S
+FzYe6CBNt+PqDCbk6Gm+ZcVpR+elq/QJeyhdDzCCrrfNXwPwsVGAM61Z8SvdvNKE
+DA5gHXRsOKf8fu8lqW2Ay0MCvgsZLMIGOMDPCyBUd1bhlU0p18V6D6wdatfzu9gR
+X/k36HJyqB2cHh89/F2KdBSonRVRJOvHc/88zEeRFkiV5pUyrXv40l099+5dvA+2
+h4ODftY7ZbR22k4iX5rqj2BRow3H+N5lTIWgiADPUl+H8z4ZY5G+LWk9Xms3o1G9
+DmEepM3ma1pg4sZbxf0iStikch7aPvL/HgGRPJnDxA/W4KJxqmSw9TTMH/6XHq3D
+ah5Z1lbcylChgrFLFVJi+shnLTZSYttTeKOIqTPi0765AY0EYAcEtAEMANS23tqF
+Dr69wz0AaT7tjoccT/WlSO/gxd80ShMr4vbr21PZp8qGklFmlcrSrMDRwfXY04x2
+qxHR/Kf+hCD5gNvg8kh/yH2lQRcvekzQ4/rLmSXBfGOFg+LioQQ3CZJ1MZyIHzu5
+YVZ2pqALfJwJSw9P5Z340y8sq8AOPaJ+cpIC0rYBp9BUAmz9IeLVT7fUc6CjaWBo
+++E8H+9FyZC71RIPNcCvY+24Qky8ms7nw4hA47Dlht1pqL8dzOggCnohuSYMCXs2
+YPLvDGdZMg7GgQ3AyZawDmjTxFWt51VU5hunGfGiC5Aock8rVHSYsQzUFjVBSR+Y
+Zy+c4noxZD1eRfb8KdFnrewyVqGKFtc/JwA61qhhyYFe5AWMAFtudjGYG0WiTP82
+CmFFc1Qsvyls9G2yMkLuay5wsdIJMnRW9XwBzwxm0mdZI6D3nSbWjPUUfRcGBY8C
+Hqpc736G+UzMevZtorwy/5Q6D8v+Obrk02DIDKa6CJ7g7dTwK0I/fleJlwARAQAB
+iQG2BBgBCgAgFiEETwgL4Jbp9yNgbNYiEzNlwcwqcG4FAmAHBLQCGwwACgkQEzNl
+wcwqcG6mYQv8CFIVGj7/Qnr+wmviMzm8+B4WwQIUHGryqv9hnfp9hLOXMFmNuEDl
+QYkHVChWO7ehrR3fpvpebhcieV19skf/WO8xm0pGSXyjV2/0/bVhXq01xesXHH9r
+4aFxsCu0E8M9fZVAHP7NBr4A67knQ4EHRF6Rwml2ba6Zt2oP15IHvsAq/2B3f8ar
+5sUau4zM1cItG3tg49rbYr6V71HdgkWA22+EkbXL/Qq3haY/er2dIGc73lu8t7oQ
+msGK4LSAGc2661wMvJ6w6feCagkXAtrqyxodhSLoWgF3i0QVQnMbgmYWKEK2B6YA
+g669CZCCXJF+9Ebq+PP/d3Cy/k9iUmWDh72C7iL136kYZt+71b+yOmlDRT9l6DvU
+FP3bhRZWomOt3F3aP5mAdbwrP1NbvlxTYUAf++nUPdpr0Jrvgi67/VHVjaUtVh/K
+gVQ2C+4Cp/fllxXXKQMPcC8dD1x/AL6ytDzPu099ETMULntgbt7A5Lsd/fFScnF3
+ZNx6wjRReIvT
+=8E/K
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/2FB05DBB70FC07CB84C13431F640CA6CEA1DBF8A.key b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/2FB05DBB70FC07CB84C13431F640CA6CEA1DBF8A.key
new file mode 100644
index 0000000..afa459c
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/2FB05DBB70FC07CB84C13431F640CA6CEA1DBF8A.key
@@ -0,0 +1,42 @@
+Key: (private-key (rsa (n #00AC4B5BC5A84DEA80A0F64795FD9FDD06CFC6EE730C
+ 2F25622A6870EC56802D17A21C2880E8D61402F5892C4D0625FCBEC1B0C0DD9A3C846D
+ 645FCD6E28AF2E79F7A777E361E5EA0ED90798C947990925D872D8C08905488CCBFEF6
+ E05AFF0F3F0F34F704A142F3F591FB1C468F44AA96584403502AB96A4D0C7CB297B565
+ 54060B18E4CAF2DBD77F18B26F9F1679BF5E8F2BE3F8A2A67BBE1EC55893E5A8F2B64C
+ 267AB35AD87D696EF576C73B3C17C28CD583B217B5F16AE118A3E1CD2C8344B4198F21
+ 1809673A945CFFA2764B8D58F29DD6A8D0FAAF52CF0D05059CD08A5D5A0750678A5FD5
+ 398803FBA71652BA89EC142AABDC20C6C6BFA4294A5B7D978BAEA4C0E250542BB4FAC3
+ A5AAD2A1E8B0261453B6021998E511E09905158D7DEAB8E4B2A585D354C4759681A06C
+ 81669A0E6A4559A8AF6E599018EBE64AFD6724C36679D46C0D2179D67B099E441C7A9A
+ ECBD38526BAA89C04622EE98FA2FD1CED941A024B09BDDD2F955342287681D86085C91
+ 4481A24524BEA06FBDD88FDA71#)(e #010001#)(d
+  #208024A31FF0F6B3E5E91F2ED58572F1A67F1D9AD9290991BF732D1DFFE134E058E5
+ 9BE459478CC5D42058997CF7EC79E55A9CBF10A9AAC761E04A85A5AA0A07DAE61DD0E8
+ 36311534EE606D5392B42D8DEB7824B594280FDB2950D39886B58F0D24CE15F2FF88BA
+ 819B8F4566202B57A9F5C6743862FA80E7429C83CEA57B189ABE4AE657B28DAF7D6EA7
+ 6CA89635B9B6232EE14779452D636B919E707B92B13DA3229133A953DAF021E0928B83
+ 75EDEE98163C2189E22CE9A236C3D0EABD2608DAEF09211B2C77FFE9158A95F8EF2750
+ 221C5ADEDAED0446DC0E4CD8D38AD897D44FA3915934B6CF03F489DFAA6D939AB9F8EF
+ 1C2A0CDCFC3F2207D63A9EB55B09A0A45323D5F59AE4A9D48E819E98E53D04F022905A
+ 9C4D137F32CB33A974F202B0D3AD4AC64CFBA2A4C18650B671AB753D1D3BD7C4FCC8D2
+ 0F85D1876D89A3D94C77423778C08BDF8FBA23A8501D766FC1B4D51F2D4BB4C27B8491
+ CC2595FF54034F4F192D668C1934D292752A4E44C95135D29449B75928BAF1A2389ED9
+ #)(p #00CCD74AC0DC1CC46052F784DB19545A09FF904846247BAD1AFA5E00CE84A4DA
+ BFCD3BCA175508C068553226DBA49EDAFBCC33CF2A914F9006326FCB62C0473B1E93F6
+ DCF89A24006B090834E5686464A8C216B70AD797732E671ED78CD3E922161069E46BA7
+ 489F2A79CE46BDC4E6F5FCE97C3C9DC59399212235C53246609F8B7FDBF2AD191B3FB4
+ 4CC59760BA6D2029541811D1E9B72DC2ADC98513589A9715C82EE88ADF9000A41512C9
+ 6D491D2A30269FBFCD9CF5D2F275A1DBFFEEB72BE5#)(q
+  #00D7532ABA5F442A994ED8290AA71EAAB6F8137FE3F01488298637084157972D31EA
+ E9F495B4360A6E92ABA7C2418A5960DF29B8C8146CC7D1DF1201C17509D7315B6ECF86
+ F0A73C9F5B48D96F2108DD323FAE6BF897A8CB773EDCF5C82E203813945405F414E3F2
+ 99EEDE43EE6259FDED1C01B47C20F67AC488209585FE6FB7D958AF5EF567737E1ACCB4
+ E293724BE8AB6159CD5A6603FFEFC2DBC30FB6EAF647DBE7D9664ED0BBA1C4A2268AE3
+ DE0850572E145BA811EB2087E1E26490F9439D#)(u
+  #00A8026DB6685170EC05DA3574451678718501489843227BCEB772FDB86B20AB2F2A
+ 00B790A2373FD5DF7AD2CAA2E3896C4C9CBA08581F3644DF67743FA4BE1153421F8FB2
+ 47F0EFB64C566CB7E361BAB21CCAF029B43B7172232D11D14912BC035E17FB8BC663CA
+ 6766E6D2531F87AF378896A2AC7D98824AA8F51C5D6C11B7DC266209BCD3B23597F02B
+ A317CCAACC979402F84E47F3D143187F9739FE9A6C71829CC94E4003D70CFFA33AC0FA
+ A12776EFAFFB8261ABE664C6A6FAE623D3678F#)))
+Created: 20210119T161132
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/66CCECEC2AB46A9735B10FEC54EDF9FD0F77BAF9.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/66CCECEC2AB46A9735B10FEC54EDF9FD0F77BAF9.asc
new file mode 100644
index 0000000..362e210
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/66CCECEC2AB46A9735B10FEC54EDF9FD0F77BAF9.asc
@@ -0,0 +1,42 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQGNBGAHBAUBDADAzIW1FhCcQmP/NDhzXoeRQ+DNACqTed7eEhqm3rowkW4wKi56
+v1UxFR0ZoA3LoT1oQQjiL3IS2l4/qpBR3JQhMFH3pl7yBsCIrN7JvZfAvxq2Ud4e
+YbdonY8mv/yCLq+nkTWlHkWGCppKMm6DupEUw5CFUCiptPXIxikU0uQYB7VRtXhh
+Q1RGdsv6mcOwMIh7hj9flTrX025x0vRypjqgDR05RuM3hMMpJDGMAuf51w/lbRl9
+dAsJzFzg2cf+8qv92Gx3RuP3a3yl6pEuKnkpddC47lj2pvuhWZBf2sXZMyPvMIvA
+Dve4GIVj6k+wXE3DMp0xMy0Fvaxw5OORPxUAKNBR/BgjoRbkbjm+rJZzviu/XVPR
+42+78isvsa+lnEAmTeoTqiz9nlTTPN+6JjwJXYn2LuiFM8XzNPJwNmd/86lW1qbP
+DxZHhD9jjeXZNHUBUCKTIj2Rs2uFa0xrALdhhhGEao9JlVcUqz/Tw85qC+DlzSa3
+3re5C6wGe2pnW3sAEQEAAbRGVGVzdGVyICjDhG5kZXJ1bmdlbiBpbiBHUEcga8O2
+bm5lbiBGb2xnZW4gaGFiZW4hKSA8dGVzdGVyQGV4YW1wbGUub3JnPokBzgQTAQoA
+OBYhBPidC43dWzUvOqsRbzx6+72u3pDoBQJgBwQFAhsDBQsJCAcDBRUKCQgLBRYC
+AwEAAh4BAheAAAoJEDx6+72u3pDogeAL/iNn1aKxA7pKmucyuzcbzvUjtcbbqFL8
+lOLdRxkrQNCDMb+wHgGY1UqJ6wsDruhV+TdPLzUXHpCl731MeLxZyIENr4wnjTBf
+Cr4SU8eFUkusVf3aWK3rlk54W50EkfBjMvDVavRKNkVbCWAAwXZ7mTRf3UlWxg+F
+9Sq4j2P/hEZIznKV3y7zXLDYg0OpMZLgbo3si0CD19/1T/8Z9C680qSwyAiPtjRo
+vfJYqZFQc+ZH7j1Hmvg68d2Qwrkg/WMfOGoTLZq/6PQcM5leQBAodcS1t7C8o1JQ
+6D+f2gLHpMfFdUKh9TkmvnKYI20TWUVm9XQLqyAHsOn2vRMUhydcZ8OP103TKmP4
+mbpgiyp4i4S/7XofHSeFBrbdqt73ebubESuZVXNjTuuSUjH8Jq5nHq22ZrmotSd0
+FNwc9qQmwPG/gmOGq3rUdT/KzUVntc66QN/+hMhFDYMRJsjJhhyszvGuuBp6vBzI
+lMZqx5jqOaI9ON0m0o8CKC50sKdJ25G3wLkBjQRgBwQFAQwAqMXwgfSaIM+eSQWs
+xb4Sf2aCr/RZi5wzZz89lSomMcblqtCpuHv9/C1PSd+N/D1yJKzPChbDjHh6B6gc
+4OUvuDKHmxK+oAiURpvR+yJEdbSEYwiBhfAUD6u2q3IfY5PpyyZT3NjZ9EY8FpOX
+wpgdSOdSiZVZfZt0xUPsGbW/xP1yVR1NHYLuZX5P5oTCvyNJyP8zQQmToamJsvzR
+v9r+2sa5di9roe53kZwq24VjIvTDOOE4xoYEXk5UD83u1LA++9Nfdisxxts1bxgj
+w1ThO/IRTyY5y5bKSQPskYFD3eVz+azjVurqhbj6ep69mR2X2gjLCetz6G1l4PU2
+R6wcqVG6gR6XpGFPsN+M2JRtbgKrtMElA8egJIMMpH4hdXYqIqmpe/31zXhClHkO
+99EbBpk6OawZC+MnreQFN4NIK5uO2aLi+3KL1FFnNlFCXkh/8afbt4+6rHcWC6En
+q5W0ZkLZnpjdFOF5NPTinAdei+14gnf2QhIlFLeMHvqiVEXvABEBAAGJAbYEGAEK
+ACAWIQT4nQuN3Vs1LzqrEW88evu9rt6Q6AUCYAcEBQIbDAAKCRA8evu9rt6Q6DcX
+C/4orMX1YBZNJK5hLLdjfk45EsQDfCnhf8H991xd0Rq4VPJP6bvzikSdOn9bTUEz
+AAhA4JnFu9AMTh8ioOA7ZtViIccplFBivsxi3rAVrQvmCfoP2AdHfG/jB6D9uWGs
+MV5/o1p93Hr0ReO73HK6G4Q3FbJOG3fg6wTcMYyyEQrD5g4IQhKiIhudUlSkKUkA
+9hWKlXSLw3Yx/S2Nq5Ye+Pqr4CU7UFOTCsBIH4Ky+6gLTmP6esPx0k8vXLcOjaCk
+ENcLi0OaL/AgfATH/InN3wzrx2AFfU6eQdEG7HS+402eHl0fmWwMGV+SCsLl+2hx
+AguLFwjetuVrroc/d+XeZdTcpr/2vojsr4UgbkH8Pa2KrGIpK7V85nSOeVbpDUru
+tuimIRSxIQ6GDF2c7Ih5yBy+JPV47gppSV/GgHPgrOlebeqy4sytshRiEYw/nJzZ
+LKBaG6gykN+6MeV6+A7c1BlCYpyi2vcyvouU+l3/Z9gR7vY+Oj1eAaxrqeTFf++3
+qnA=
+=03Wd
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/66CCECEC2AB46A9735B10FEC54EDF9FD0F77BAF9.key b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/66CCECEC2AB46A9735B10FEC54EDF9FD0F77BAF9.key
new file mode 100644
index 0000000..cef72f6
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/66CCECEC2AB46A9735B10FEC54EDF9FD0F77BAF9.key
@@ -0,0 +1,45 @@
+Key: (protected-private-key (rsa (n #00C0CC85B516109C4263FF3438735E8791
+ 43E0CD002A9379DEDE121AA6DEBA30916E302A2E7ABF5531151D19A00DCBA13D684108
+ E22F7212DA5E3FAA9051DC94213051F7A65EF206C088ACDEC9BD97C0BF1AB651DE1E61
+ B7689D8F26BFFC822EAFA79135A51E45860A9A4A326E83BA9114C390855028A9B4F5C8
+ C62914D2E41807B551B5786143544676CBFA99C3B030887B863F5F953AD7D36E71D2F4
+ 72A63AA00D1D3946E33784C32924318C02E7F9D70FE56D197D740B09CC5CE0D9C7FEF2
+ ABFDD86C7746E3F76B7CA5EA912E2A792975D0B8EE58F6A6FBA159905FDAC5D93323EF
+ 308BC00EF7B8188563EA4FB05C4DC3329D31332D05BDAC70E4E3913F150028D051FC18
+ 23A116E46E39BEAC9673BE2BBF5D53D1E36FBBF22B2FB1AFA59C40264DEA13AA2CFD9E
+ 54D33CDFBA263C095D89F62EE88533C5F334F27036677FF3A956D6A6CF0F1647843F63
+ 8DE5D9347501502293223D91B36B856B4C6B00B7618611846A8F49955714AB3FD3C3CE
+ 6A0BE0E5CD26B7DEB7B90BAC067B6A675B7B#)(e #010001#)(protected
+  openpgp-s2k3-ocb-aes ((sha1 #84A4A8051974D94E#
+  "26420224")#914E6847983627126D1CDF93#)#DEB66FA3201F91591F688F5D2B1B79
+ 39FD75F58A962C227BC739C6F2F814ADE5115BD85B2E55427153CEC82612F0C5BBE8B9
+ 71A0E5A6B796111B6B1A03C4C926825F03B871CBFE0F64BD0F0CC65EA34E718BA823BD
+ 136D78C9E88CA1733DFC8D6A38830274322A589BC522A2A824FCEAF453523CDD9BC391
+ EEF1355470C110E9A92681DA0C61563465D5238CECCA2D6CFA78FFDFBDDA17A308D6E1
+ 3B1858890EF25A7655F22FE6305AA0129DE5A353B657065E608A616A23C6AF561C4472
+ 5AA705E55343E9C728641BB63C64F804F76A4C5008CE5FFBC09F03B632B42180425D28
+ 9DC1201D91B1989627EE5930E6EF2F6606108B2F048934A9D79DB4834DD950C4A2013C
+ A40B50EE54FA9E3CCB20C210244BFACA795494A1FCFF35856ACF63214A0498ED894BAB
+ FE80CC24D8A478AD08D0BE8CDC8F357FB7F28A30B87540B9B4970D6EA0AEEF46A2549F
+ BA43A98FAD75B4228108DB50D1C3654422E24B4C7754673A66281BB283CD6A1EA8E64B
+ 97DC9083C62034BF7FBCD193830F8FEC3589673B864E50EF7AF4DEE046BD26041E2925
+ 170EB7B6DC6060E78309CC8A136AE9CE44D3B4EBDEE4479482464D0D23C13529184021
+ 795557323D353A70CC710EC2A79C66E860095C082E40724867A9ABBFD3407B2F92CB2A
+ D0D95CC8DAC2FB2C0187B3BB09AEDF869AF1969BA641027D4D5DAA31B1DA5822D40A5A
+ 7FAD1C054C02CF8F8F692B1C45C879299C0E9D5E5A165F6C22DEEBB8C16FFB91F381C4
+ 8FCB209657A7BF9268BD34808D0A9D3D6F50F7026BC297FD3A08790B8EB5CC0291246B
+ 16E4B50A7E9630B33F59B5EA24EEA396F07AEFD0C262BE9915CB32D5F03673CBD3D20A
+ 831FDF55B5BA3D03440A8E1A331147A8AE0760EC593EDC881F5F0A04F4FCBC80C1531A
+ 4DE71D014E3612C2C679BEF3AED59F358ABA5731FF80FA15EAD2CB95AC548F6AB0FD7B
+ BBBB2CB63DFFE9E672605B7F54EEA4B4C046C4CC8036F2F76260CF068D232A40F492FF
+ 9648CC7459F0F46FEABA3D62B9F421B0F8A1BF914E41702540213848345498AA13F989
+ 49EFC2888D3720DC34D20634472FC3A194F1403C1609C38A020F7E47F3205CA5C0CB50
+ 26270083ED153BF97375407514BA15D92808A8C10F8160880F6981BE53294292E4EEE8
+ D215E7854FC79016B64984BBBAD2E99EED8D66B25575183C279E4DAFCB63F1067FA2B0
+ 0888A9C226D4846376520720FC1E947A93A1D32444F78B2F4EB836A6F8C685C1D82958
+ E31560C3FC861D2B68B889E1B5EE0476B914DFE316411F750D252F24076E53557AD5F0
+ 4050E5E839B33E5B8AF16FDD9FE033B39796A52DE8AF65375966D4DB137C85C800B5B9
+ 0E29434E4B215DE35E60C85391DFDFA572C6F9747A0EA0964236FBB3B04394D9DF0694
+ 6E4CC9CBCE352382908148D265293C6EADE7C2AED6F5AE#)(protected-at
+  "20210119T160858")))
+Created: 20210119T160837
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/AFDA8EA10E185ACF8C0D0F8885A0EF61A72ECB11.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/AFDA8EA10E185ACF8C0D0F8885A0EF61A72ECB11.asc
new file mode 100644
index 0000000..f412019
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/AFDA8EA10E185ACF8C0D0F8885A0EF61A72ECB11.asc
@@ -0,0 +1,30 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQENBF7EL8wBCADO46xh7nXn7vZ5ow2Zdrp7WTh9BlT2wtaHNKpnKvSoYHjJbbGz
+yF8Jf/qVPuXNbjx2df1lT7zT7x3evcjQoNy80deftCw8ApZB9RMOo3uUIqS2VpO+
+cS9rjTgBRFL6xDv3g4++CE9s+5dKE9gKkwleZ5/tVqUIoHPAIUEjpcPHngi5m2bi
+tSmQUYWLGcliR1E79sJMSzPt1neksqHFMJ1KTEJLAABZ0t3PiBzmycIQWThX3uU/
+lcgnZmmhWCJIqV0yRZqxl61ejUfq+zK0T7MzhAAugqe7D6BM1FRwZRNCHwDQXIvt
+/t3fczTe+x9oTy4qX4MfaP8lHM0223MwGR13ABEBAAG0H0EgVSBUaG9yIDxhLnUu
+dGhvckBleGFtcGxlLm9yZz6JAU4EEwEKADgWIQQILQAv4wNQfEJ6I/NEWemKCmiQ
++wUCXsQvzAIbAwULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRBEWemKCmiQ+xev
+CACZSWh4xjTgafwGMP9RnReOhubVmfHS+XGlidDQzJDtshDQddPZ3oQwyTe3OgkW
+ZgOrzjrHGsZp3WZmGUZejrKt2Brqp+h+VRujFVcKk4N9A52BkM6OeT9lzBabOpuA
+UaDsNMSFsMcGTTYpB16+sDcyui8LW1jGi1y+8aQa+u1lIk/vVycq8o4htn2Af8xZ
+rAT8peapsjoNjETEs8OQ0al3Q0UX9amW6Rq1zZZ0XtoXDCPTI01EfczDMN+AZoFk
+UYHwSREDFLSh+c+q1HhYp4TqP+2a5Rayna//n7zci1PmSX7zD3iWzV1jEQ3Jm8U3
+DY+P/WLezQdSJIBVCFpCualquQENBF7EL8wBCAC+ef+vNvfu1jl9BXpu6K9PG0I5
+DQfrNtcdPq90O32ipvsYvqGOJX9MHoTyxBPLew+e5UsYb3ex62JyJqdAaqSwYXEN
+MBESZx7yBqBMUvildfh8dowbJeblxCf5KsE4C9uNfg4ApWGD7PjVsUCh47V8VcfG
+ymCxxq80r+4GfFtt/HC+l9fPUnDLuXpAWEM2GPUzcauUoEXxZK6nhstYCRlKlQcK
+Tn+LtCC7SGpYlqvwWBzAnOYP9+eZfSJ897g0AiTEhK0JsBlDAb3UAWHYHkAkVa1+
+oU/UedhPC4j2Q7RzPQFMun6aGkaDrntCxvT7IFiMplPG7iy0JDd6ubrWSzivABEB
+AAGJATYEGAEKACAWIQQILQAv4wNQfEJ6I/NEWemKCmiQ+wUCXsQvzAIbDAAKCRBE
+WemKCmiQ+xoBB/9BAmlHQUmVl/bkwszAcyXkR5HsyA4htMJt+6GKlqftuhLP0SGK
+Il+7GeK6NqNdQXxXG5Wj6dn7ZqWalQRA0evEa6VLH+74zrn0llWfzTPIcP1bHW7l
+uYaOzZ1z/q4FoEGNJxp/jdToZ4970OXLzqY/G/QlMJIlXWCC0EXNYbKCEpOE9uvW
+h4kWe5xeGOmhZylYbzurTDzqEtKy+LZ9f2xNYn6ElcWtwxsxwSY7L9B3eNcCYE46
+Np6uqzPffB9s7PHW46yEL1lQs6ME+9hBGyjeVop+Wg9qkh3YCrp+KY5Vkmdndwkn
+Th4FnTpcCiS06fCVHHC5kelh+H6TgRA+XQ/V
+=WGUq
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/AFDA8EA10E185ACF8C0D0F8885A0EF61A72ECB11.key b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/AFDA8EA10E185ACF8C0D0F8885A0EF61A72ECB11.key
new file mode 100644
index 0000000..b8765aa
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/AFDA8EA10E185ACF8C0D0F8885A0EF61A72ECB11.key
Binary files differ
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/F727FAB884DA3BD402B6E0F5472E108D21033124.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/F727FAB884DA3BD402B6E0F5472E108D21033124.asc
new file mode 100644
index 0000000..c6e0408
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/F727FAB884DA3BD402B6E0F5472E108D21033124.asc
@@ -0,0 +1,30 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQENBGAHViwBCADaE67a5U8oqNjqg//SmlNLd+MrFIccHsg+pkSDhF6ipjZEXdFu
+oRQ116tH/qY1SzsHw/TMLujYeTBW0KwQ5E2+TWagckL8pJpDt7ZC08CTK6u0Xvjy
+BSqy/t29NPTuQxxxqRx5gq91mtuo8v00fQmqkbFUgkVfEOKOv4qe2tlaR5pTvpmV
+VboXOls87RPgP/X665kamHjsywrsDpZ5FbvPS8E2kKdYXqeHaiEU4i0Bizjx3diK
+ilPEIxxl8zgDsROXyKagCy0KOOajBqhFhStQH1soIzvk8aG/9eItKmTa2v1BD2mV
+UlZNQ9ZfsnXx3QIBLmA3jugH69rkcekHRCWPABEBAAG0HVRlc3RlcjQgPHRlc3Rl
+cjRAZXhhbXBsZS5vcmc+iQFOBBMBCgA4FiEEJJx/+EvV3v35cJ+Jx5r/T8UxegwF
+AmAHViwCGwMFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AACgkQx5r/T8Uxegx+hQgA
+pIy+E58aWh9FIHW/POqLB/y3v/GbYdIbzk9ro0FAXQ2tQsoGQbsuLckJVIlyja7n
+oQX23OmWTOc2tj/Kpy9lZ2ButW43FaMSiLh1G/VtM5pqJ9yHFdb1z7Q+LHMhhB7w
+RKOoNSEgkwtxv4LAkKz5t/BrDU0hvDPxWPqCSRvSAEE6qIY0fa3mLf9ijy3gLlCd
+hBayUC53W0tL7gLHgprTM/fX7b1pDab8beorroPHs5XzcYUBleaCGmEYbtV2eXPQ
+5irOXOC/D/E8vOfOZwhOhFOZk9b4UnhFK4OCfpKIzIooc6tlboVPhdx7jb5DkXQo
+rozfavEvAPx8INi9KNmdBrkBDQRgB1YsAQgA6q/O6mAPB0kj3pnpuIdJC8EumgKm
+7W8rv+ZfRGePg+IEEm5DeFKtfWl70YH33nGmwnWB95wO5412JCNC174z5LKDBbz5
+PWT/yTNnmjooxj6G4p/YVwXYJkvfaDP+kQnYgJAybpeqTa30tES0eqvI0J9aQo1h
+GSMRCkE6QMV45IMj6gH9rptQv9e8U6gbnwBPxWPG2FH5rsGIGQGzIEmGxmKRyxXm
+YDU4f7oWPHSg1ikQqCzAxxCBxeCOaid3acLK8//TOwF/Do8GPJbcupEDqsgbFNGM
+BDWtmkmxjrLntlU+dvIPcsBxdBUrrADiJ/k7EfFv3kHfLfdAonSdKZL85wARAQAB
+iQE2BBgBCgAgFiEEJJx/+EvV3v35cJ+Jx5r/T8UxegwFAmAHViwCGwwACgkQx5r/
+T8Uxegy4+AgA1bzFKpsqkwrjZKDCCT759xeuUbxnYE9kBJgFSVuhn7fUbB4MoHx4
+shBptx7iBOdxxT7yC0oaDPhbiIkttb/c5W0f6JuLr08JpjkFfkrWF+dMcVrtXwPx
+i/30ccV98qWJDCBunyeCwBNie1Ck+qXMxm3FYy4qIbftMQ7mG6KKN6eFlbxu8B6M
+p93DFUvycGH9CWz0yJcho7KT0NSSyoLZhJz2uxRe1BwGMV20O9AG9yicsU0/uJxY
+a2Hble8NkH54XDuZkrsBaAb/o8UsWP7AJdYYsb904UZDIZNRfjWapOmODnlnK8Ta
+Q8pyYRGS5of1SapatMfpQZF6hdsamnTH6A==
+=guSE
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/F727FAB884DA3BD402B6E0F5472E108D21033124.key b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/F727FAB884DA3BD402B6E0F5472E108D21033124.key
new file mode 100644
index 0000000..63617c0
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/F727FAB884DA3BD402B6E0F5472E108D21033124.key
@@ -0,0 +1,32 @@
+Key: (protected-private-key (rsa (n #00DA13AEDAE54F28A8D8EA83FFD29A534B
+ 77E32B14871C1EC83EA64483845EA2A636445DD16EA11435D7AB47FEA6354B3B07C3F4
+ CC2EE8D8793056D0AC10E44DBE4D66A07242FCA49A43B7B642D3C0932BABB45EF8F205
+ 2AB2FEDDBD34F4EE431C71A91C7982AF759ADBA8F2FD347D09AA91B15482455F10E28E
+ BF8A9EDAD95A479A53BE999555BA173A5B3CED13E03FF5FAEB991A9878ECCB0AEC0E96
+ 7915BBCF4BC13690A7585EA7876A2114E22D018B38F1DDD88A8A53C4231C65F33803B1
+ 1397C8A6A00B2D0A38E6A306A845852B501F5B28233BE4F1A1BFF5E22D2A64DADAFD41
+ 0F699552564D43D65FB275F1DD02012E60378EE807EBDAE471E90744258F#)(e
+  #010001#)(protected openpgp-s2k3-ocb-aes ((sha1 #3E87FF0806B054D6#
+  "26420224")#7E8282B83522F91C53D76805#)#70B1997D514FF5800155A90FD785E7
+ 7DC2D782C48FC9BE44D0192C0AD56804468C910A202191EAD077B5542C95FE72BCC450
+ 0C2A8E8313C0CBD6C881236AC13E0BE893663946B5AABBDA57FFE4BA49973D547FA5DD
+ 1236DEF9FA5A9CE52F7AF1947F42A6C3502A47E8EF7E8CEFDDD44D0BFE090EA3220C2B
+ 52E11776DE36DD6C72D3B39A56F5D7295D26A69DB8CDAD1ABDBE1B21C1B754C9184E65
+ 2CAE169E2F492FA0EE5908AC5CB3BE5F4C7F6CD9F41314D1BD9B1DE713A4E6C7DFB11D
+ 2E64000ECFBBC89326B1322A8A227ECE7B919408C9187B5C9D53FC3985833E76D72164
+ 40B7386569E4DE270C3616ABD2A91A657AC58AA872704CB3DD4DF08C77D03D8E3CEDB5
+ 0D83BC3837FFE45D64B457AFE9A6ABF680637C51F80CB54691233BC4DE640026ACDAAC
+ 3FC0749FA8353F6EAD5D362A63C1CF25ACA73A9CF3290B54C18DB3214AF078D918682E
+ 513C434EFA06D9045571B1734CAE42990A1BE962D6E2A45846169EAAF2CDBD520813C2
+ D4DE97FFFABE582A02CA893F91EAF0EBCDCEB70B35850FDDF56EEA60C845A7E5C052C4
+ 33344776E7A4C787690CC0E13F32373EE425CA10520C251D045C0AE73EE7A0CA83C858
+ E2E528CDBD117BC022ED3F5DDE40CED0128B761E29B11F422C8E7C4281BF94F6F75D07
+ 0EE58426137548ABA38019A34DF1A66F700C29EF5545AC88BED75B5036801F0D8D4DB9
+ C6CCEA83D9DE3D626A04A80F218EFE9C74C173412A8A86786AB4A85403E8F8292CFED5
+ B8BA72FB5CE1BDD094AD9D633FD482F8FDBFA540DD2224149786ADA8DB6310A7C0C6E5
+ 9167815B2CEF34E7C458C41B5C56A79414BA57073E9B06D28CA08C56ED5E685EEA2BA5
+ DD112F87B253A0D02AC7CF93EDE93F48A80B2DB57B254937EA80E9AC1CEBD36FD297EB
+ C8A3B42CBC3D2CA732891B49457F3F15AA3F9BF93553968A07CB1A834B392F27B2D152
+ 47D93E46A6338694EA53CA0F5968109B4FAC9A#)(protected-at
+  "20210119T215925")))
+Created: 20210119T215908
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/brainpool256.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/brainpool256.asc
new file mode 100644
index 0000000..8427cfc
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/brainpool256.asc
@@ -0,0 +1,14 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mFMEWsODvRMJKyQDAwIIAQEHAgMEQLOxiiHZ/V6v3kvrhbnRtTp+oOPVpuvDKOiy
+gJOCZ7EWMVAwTr4syaSh8W8hdRgZ85Evv/1PYNFovYb6vzgVr7QJZWNjLWJwMjU2
+iJQEExMIADwCGwMFCwkIBwIDIgIBBhUKCQgLAgQWAgMBAh4DAheAFiEEBjPF9yoZ
+j1HmUOSr0Mij2vngY0oFAlxVsKIACgkQ0Mij2vngY0pARAD/RozGDidH/0aFlxeU
+VWNJKjPiax6vdHqur5dqBS/RhhIA/1sPUnyAIvAXXID1uhK6oIBRKi7WJ5rI7vSy
+rBR5MlNJuFcEWsODvRIJKyQDAwIIAQEHAgMEE9Vd8dIjHJkmRs/8MLz4Krfwz5BK
+hunq1T0xnp65OEZJd00VxA+VUXdEUHfaDehtSv7izCpq4lbXGCkEGFN7QwMBCAeI
+eAQYEwgAIAIbDBYhBAYzxfcqGY9R5lDkq9DIo9r54GNKBQJcVbCpAAoJENDIo9r5
+4GNK0MYA/2p5cq5smjSvKD/EGkosQwfcqkeygsQuEpDDLeEdsv8vAP9j+RHKX2tl
+W08zbayxGB0E+aCHuKCF8iLPeI4eroi/fw==
+=vsa4
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/brainpool384.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/brainpool384.asc
new file mode 100644
index 0000000..bdb20fe
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/brainpool384.asc
@@ -0,0 +1,17 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mHMEWsOEUBMJKyQDAwIIAQELAwMEivcvlPJsPmivhJcrfHx+ORxyum57GtRhWM49
+Yr8fJ48gyFqj9cLYOBdhEVvcfceyBPXmyt0TozWtjkGzgbF4LIvN1EB0DW0Rlsdn
+p72/hf0gnXvWZdD8euArX4RaAYuQtAllY2MtYnAzODSItAQTEwkAPAIbAwULCQgH
+AgMiAgEGFQoJCAsCBBYCAwECHgMCF4AWIQRbiiVMgjztmN7NEO1s8tzoVZmtogUC
+XFWwugAKCRBs8tzoVZmtoj1yAX9P1UV7FYpGUIP13aPP0d5Bx8HdQDAoexdXz3WW
+WPL/7OhSjPde23Q8TfgWyO21M2wBf1oWjOsDSjO5mDLCr7ypAFF6IJAgx76tSUe9
+Qmy7sL94OWDQ4+1Dccnc9GGiHLtRI7h3BFrDhFASCSskAwMCCAEBCwMDBETUkqGr
+7p8kX2dm38jzzxXRh1+OL7nmY168Zeo9yfwDbnyx8BoihP9ZgPWjGXmefT78GSfw
+ZDaYgC2NFQOcI/b8agh3PcjrXgZaFCZbUR9v2DnLUpCF8ZbxDJwEqweNTAMBCQmI
+mAQYEwkAIAIbDBYhBFuKJUyCPO2Y3s0Q7Wzy3OhVma2iBQJcVbDCAAoJEGzy3OhV
+ma2ig1IBfifduIiwdAlD45MOolSpHMX0AT7KoJHpt9ZFvWnjQkq9ZGEA/RA9vx7Z
+sLb7IsG1GgF/Sn+gtf/JIteXaZMnOhEOZ2oFUufij6o8gII8/9s8mkIjkrIICy//
+0n3q82ndFg0c
+=fcpz
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/brainpool512.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/brainpool512.asc
new file mode 100644
index 0000000..5b4bca2
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/brainpool512.asc
@@ -0,0 +1,19 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mJMEWsOEhxMJKyQDAwIIAQENBAMEA28ylDnn3LR7t6EQow5DszCpmUA+yup03LsT
+9o0Tw4/asi8nAz+1tlRY5HD49j53PziOlsGzKYa/jxGWjhVESgqLrJp/Eo65zK9v
+yDhX+iCkSYQ15WGKr3QaRUmBOUbX9PqE6dY+DDGQ1kewI93QIGCB1gn+OSmyKPm3
+YaVIbo60CWVjYy1icDUxMojUBBMTCgA8AhsDBQsJCAcCAyICAQYVCgkICwIEFgID
+AQIeAwIXgBYhBExZq5JyqmofYLhb0KpcWNFPe49IBQJcVbDYAAoJEKpcWNFPe49I
+F8UB/i8DwypbNusdbAqTbu1Twpn/QFMaVKHn8Ysgzqpimv+6hRq7uzekCvEOPOjl
+Oke5yLp8bpTTMPRKyfjNatQhdn8B/2+54qtXJuQd9oTSz7f2eFYvA8ZsMQgApYNl
+ksvKSw6dhSNX/DXK7JYIlgZXx7UGTkP4h3FQSiyCUJhVpClVVGa4lwRaw4SHEgkr
+JAMDAggBAQ0EAwRCtEqQkEgzQDxNGCj0duj0aGvnH+DHKlP4V6p9LJVIL0TuF1uZ
+BzP04efRvZT2vzCTcvvdE/G6G/txEZsR/989OchbkVWOPM/oCVktkaA02rBMcefh
+k9wKD+O9E3oHEN+tBt3yhmsv0MIR9IfPwi1GCsu55p4WUI//+ysB2T0YaQMBCgmI
+uAQYEwoAIAIbDBYhBExZq5JyqmofYLhb0KpcWNFPe49IBQJcVbDgAAoJEKpcWNFP
+e49IZQUB/R4U4aWBMimZSL8kyaK+/Y8NcInIGqRzrm5zPnTSHrgQeH55SVKahzsq
+j57D1Ec1HnUd4ctISVocOxpUfnJq5NAB/1fzbh+1RN2ZyNW6tAJlA/Irkwzzbil9
+6fAIvRolwwaGsUZNMEiCF3rTcFaenJg9UhQvX6BoqXCdwawqTZCRN6E=
+=h+On
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/dsa-elgamal.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/dsa-elgamal.asc
new file mode 100644
index 0000000..db06732
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/dsa-elgamal.asc
@@ -0,0 +1,44 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQMuBFrDf8YRCACHbPXT8jG3RNWdNms9xvdaiLrY+Iui1Gq2WGLSajPEZVASEWN+
+JuuX8k9d05rb+F2VAqLnW3CQreDW6unVNeRf52tdM8J4eXmeu/Bkk8y1Qx/HbGca
+sAGSIEKg34TuV5Ly5m4Z07bs3HPYUUQbmu0uclGfnX/ArZ+4Jp+uypC9bErdiXM0
+cM7d52tb9IvOlXNu23rzHDbgVP6qF/AxLSRD8SQPvshu3/5b0bvdBkHVk+dHoLO0
+fC5j476ibHGGZcnPMrTwqEIAxUCy5wQ3Lb/2/G31kuV55bAZ41tUNEvfzbiRN1L5
+1uiO+XX96bRqLN13t0Coaba9fq1aN5Zr6piXAQCuNzvj8aaLXAOEXVRej6a2k+/C
+Jny91MgjSM701twUDQf/RMWHwQuFPe6zSDQs4pWlxkHwXJw3AVidkoWg/DCwv2pJ
+5VYQxBXRwND2OhcZvmeDT94UzPws0dFbprWyymtA49ZXitPGzFARAFWHWxk/IsOf
+Idc6w5eHXDMHxLhiPFqfjKeNpibzO2P7LXP2bUKzwybkKZarz1N6pfanDXAtC4DU
+SC3qWNqywYlfINAGCdwsPu5qFUNSnkjTYxe/MiHb4kL1p/z8qFNWrvg6GryXygp5
+cLdqckjPaUHlR+B9wQZIVRzVdlFAbMDJ0EERLFG7FbIuY8dzy5x7n+oBOgRxee2I
+ytUpGVMLIJuecARLXNKsMXviCMYVE7Tj5hiSoM0TIgf8CwLLFsSa0EDm/wlXYZMj
+2gg3Z8iCz6ycxvFD9PXNt+8jyELO8CwS2pWu7ptBgaugkinqd40EQslQoP76CcHq
+bGQEohm4SnmfGsV8dicuziMVVKkVrYgbGvZ5cQ/ONGTTnSJuiTPN19oztwh8JOEc
+Jd4l+wFuVSm8OS1mj5eexeX1Tz3NfWQMT4deKh+jiTLe9Sw/57sSjxiw/8IczqhN
+Fu3YIy40d3Bv+OF6i8I+94WLbJPiX1ban1wqcA0bMaps1aYVtTRZ+mP0b3M9W7qa
+383/SLCBjUzQ7zm6PX/7uAXFyZOQfcyLaJ8Hc34yOE0git1DWmRS7U16Zv54v1Uh
+HbQGZHNhLWVniJQEExEIADwCGwMFCwkIBwIDIgIBBhUKCQgLAgQWAgMBAh4DAheA
+FiEECRxEzpz7w/9+x6ZNyKEKfXgnPhAFAlxVr2sACgkQyKEKfXgnPhABkgD7BfEd
+jhB+ApC9icNLs893i2jiHbAxZGSOQMRhCaJ7AzoBAIipcSIsBa3LJ4eTec1esiCY
+a8xzxquCTA+oANNoX7p6uQMNBFrDf8YQDADMPZ6+/YAIjXMLfQKX80jz6FZ4Kdfx
+Dc60m4O+ZElMv7eXtQJC2L/xOh4Th1fZUQIhSdtFiwaCSkCD8occfJwyt+lH3Dj0
+Qrh3mIycAfPrjj0Rgxz8nRQbBLDbLF1QGPimt0zP69ByJ3opLujVVi5ixwgwza9S
+eGffKwGdyb9uFcB9MVnC997zfLvx/uNV44BwLnCH6Tp68Lynf+FpuvSX+Rsj4li3
+UiLoVxEIbBZ/5Bn3ygc7aW4fM4bR4hKjWwJR0Hh1y/kt6A7dEAypVKBfSqAtAu2A
+zYAq3USsbtq1X1FaGEsmvcJY8IGa+aLTArq7dkhXzcv7K3EVdqOawS1zS/ARuG+B
+k6kct3zzyj1EitiTvdMAkGOoyk16qKVzUcbFRVC1HsZtxYj6OxU4Eazvh0LjvZ0A
++eft/XO/ZmN6vyRaF1/10z+uHPfj1FLMpS8Zn4SN6x7Qtsx3iLL1n9cKBDFRXCqD
+HDaxLVC3N4zAI2hMMmZid+fbTuhsqYbSX2cAAwUL/j/H4/9Ml7PUUCXoozX2V4K+
+gi6WEYmY+pXN/we9NuFulW4aURo7jK4wRYBu0BS3K9e8f8WUMAV5V6ShPWHXcobt
+iuSjLYJwdBJkgHbnKFWPZUozJ3Ftyp0Lh1M5bN7/ECofAxLHbRpCVrcOP2LC7vAU
+AeMgdiFDqEiLCnr/aGvqUOxbGO6Isi4jvaM/ZUfGjGe/Z6yVoqm6wEsNM7+9cFGQ
+QR1lRPeCPKcLeasCdbM5EIt1aLFNijZigWuDRLIgG5PuzA8Kpdk/u/UuCUeUFwJN
+ym8MEv2JJDiWHmb8IcgFMp40VenUs0fte0LWwrMjWVPpLsHKmkraRjQ1UtarRhT0
+ANYilGjZWCnCb11xGKhlM7r5IkLGY/L/Eh4vjLgg9T5rGwOF8p1jSgx9mA8SpHV0
+O0BoKNX1ApWEHayTLcyayCnTYbY/e4axnSKodixAI/NghOnJHqGr4LeZeKk/Q0mm
+GlljzFv3EAdoru4DVowWGFBmrwBy7o+GLgHs6K/+yIh4BBgRCAAgAhsMFiEECRxE
+zpz7w/9+x6ZNyKEKfXgnPhAFAlxVr64ACgkQyKEKfXgnPhCETQEApruWUqCwfibQ
+vyI/OZohPzljlvIoioj3rFjYNpufQD8A/RTaYtnPiEvsPynEZCj9zTV/SuHiKbHS
+v5BhpoOOm+jM
+=PnGk
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/ed25519.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/ed25519.asc
new file mode 100644
index 0000000..636a5a9
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/ed25519.asc
@@ -0,0 +1,9 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mDMEWsN6MBYJKwYBBAHaRw8BAQdAAS+nkv9BdVi0JX7g6d+O201bdKhdowbielOo
+ugCpCfi0CWVjYy0yNTUxOYiUBBMWCAA8AhsDBQsJCAcCAyICAQYVCgkICwIEFgID
+AQIeAwIXgBYhBCH8aCdKrjtd45pCd8x4YniYGwcoBQJcVa/NAAoJEMx4YniYGwco
+lFAA/jMt3RUUb5xt63JW6HFcrYq0RrDAcYMsXAY73iZpPsEcAQDmKbH21LkwoClU
+9RrUJSYZnMla/pQdgOxd7/PjRCpbCg==
+=miZp
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/faked.key b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/faked.key
new file mode 100644
index 0000000..405afad
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/faked.key
@@ -0,0 +1,23 @@
+Meta-Description: Example from GPG file 'keyformat.txt'.
+Description: Key to sign all GnuPG released tarballs.
+  The key is actually stored on a smart card.
+Use-for-ssh: yes
+OpenSSH-cert: long base64 encoded string wrapped so that this
+  key file can be easily edited with a standard editor.
+Token: D2760001240102000005000011730000 OPENPGP.1
+Token: FF020001008A77C1 PIV.9C
+Key: (shadowed-private-key
+  (rsa
+  (n #00AA1AD2A55FD8C8FDE9E1941772D9CC903FA43B268CB1B5A1BAFDC900
+  2961D8AEA153424DC851EF13B83AC64FBE365C59DC1BD3E83017C90D4365B4
+  83E02859FC13DB5842A00E969480DB96CE6F7D1C03600392B8E08EF0C01FC7
+  19F9F9086B25AD39B4F1C2A2DF3E2BE317110CFFF21D4A11455508FE407997
+  601260816C8422297C0637BB291C3A079B9CB38A92CE9E551F80AA0EBF4F0E
+  72C3F250461E4D31F23A7087857FC8438324A013634563D34EFDDCBF2EA80D
+  F9662C9CCD4BEF2522D8BDFED24CEF78DC6B309317407EAC576D889F88ADA0
+  8C4FFB480981FB68C5C6CA27503381D41018E6CDC52AAAE46B166BDC10637A
+  E186A02BA2497FDC5D1221#)
+  (e #00010001#)
+  (shadowed t1-v1
+   (#D2760001240102000005000011730000# OPENPGP.1)
+  )))
\ No newline at end of file
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/nistp256.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/nistp256.asc
new file mode 100644
index 0000000..fd1509e
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/nistp256.asc
@@ -0,0 +1,14 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mFIEWsOCNRMIKoZIzj0DAQcCAwQS5G6mn5dhamZ6678SXE1azavqf8BItWO9Qv8V
+dS1vEEoD14urr5OQKTLuHhDRjvSQdaxRtkf0sI51T7230sT3tAhlY2MtcDI1NoiU
+BBMTCAA8AhsDBQsJCAcCAyICAQYVCgkICwIEFgIDAQIeAwIXgBYhBLVP3ru2c0I6
+XQqlRCNnTyGyRBUnBQJcVa/nAAoJECNnTyGyRBUn1ycA+wVg9sEfHDBaGtLqlUSB
+WdGKURrHN7CJe2UTz1/7oQCBAQDDi4RQyLHs+TfOrBNSbLEswCu1oEh8VmHt/SN7
++mqNLbhWBFrDgjUSCCqGSM49AwEHAgMELDOArLIG85ABQu1IwgQMpiIuUwj+N7ib
+gGenTRck5dkBpX48eK3lbjovXn4YkBneA7z14iez3+Sdg6UFAMFV2QMBCAeIeAQY
+EwgAIAIbDBYhBLVP3ru2c0I6XQqlRCNnTyGyRBUnBQJcVa/vAAoJECNnTyGyRBUn
+ZKoBAJ64gv3w27nFBERvIsRqufvR6xcimqS7Gif+WehBU+P5AQC5bqoISh0oSQid
+adI84f60RuOaozpjvR3B1bPZiR6u7w==
+=H2xn
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/nistp384.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/nistp384.asc
new file mode 100644
index 0000000..b2b5995
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/nistp384.asc
@@ -0,0 +1,16 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mG8EWsOCnBMFK4EEACIDAwTRTCLBHlq6SUTiXZfWR0vbUh/0VAlrePaqHVIE4LEK
+0UBhPCIQOGuGL4JIufc8UzBWhiMLJ0z7KRjBWufsMZR2+rqj+unOK2lLu7sc9or8
+X6B74hhP3Ili24PgGFAeAG+0CGVjYy1wMzg0iLQEExMJADwCGwMFCwkIBwIDIgIB
+BhUKCQgLAgQWAgMBAh4DAheAFiEEqyXLoELdkkw6zD7TJCo6peqF9EoFAlxVsBEA
+CgkQJCo6peqF9EooJQF7BPZelriXwZ/kJzaamImHBddkLFc7d2WbuSfDxEZQ+Mfw
+BAP3+QYUaFtfeqApjY69AX4w6LhTUgI2kl4O0Vc7ZOlqZBlwAc8CMV08TTfOEio2
+b51SItvhLdDrFRJ2K4jiO+a4cwRaw4KcEgUrgQQAIgMDBORWqhYflSrYzF04SK8q
+8Om+DYTvwRtUlr3Aoq44+gm5yBcmJmgT3TKrp/bx5Jg/zwzIASFn0agbxkqKpQqH
+sHeelWsSBROQzy98HXdCp3nVmghI2aDk8zdD6AV4m7c2ewMBCQmImAQYEwkAIAIb
+DBYhBKsly6BC3ZJMOsw+0yQqOqXqhfRKBQJcVbAZAAoJECQqOqXqhfRKgAIBf3Wk
+TsqUA1JXkPGetA9sjHglIICN+DZY5k+PwTJUxaW2zrkiPJ3BYEnKbmmBLzA7BgGA
+4RYatyl2WOUYh/poRLgu7JpE4oRqdmNA+QOpCILMId1AeXfj4W01RKFWaKeH+3Yy
+=2H/0
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/nistp521.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/nistp521.asc
new file mode 100644
index 0000000..db18f81
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/nistp521.asc
@@ -0,0 +1,19 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mJMEWsODGxMFK4EEACMEIwQA8OZCJ8Iv4Qr2oRr0kqez0nPSW/vNxYBZRpCJ9ab8
+kVaRhW7+5vEsecm5XugZSePbAmERmk3oEiSgu35r6aovowcAGrOBfBm9fyIVqaoX
+veTS3yRHH6NEf044+pC+uBaaFukkrDmVTecdRvYr3Yrdc5ifyOve053znlpQ6a4n
+9bh4GGy0CGVjYy1wNTIxiNYEExMKADwCGwMFCwkIBwIDIgIBBhUKCQgLAgQWAgMB
+Ah4DAheAFiEET7Of9vpIV6S9fvW0IJLKgyQmO2oFAlxVsCkACgkQIJLKgyQmO2oK
+DwIGO72zo6otVkbHfeI9hWx/8FAOXh4MT4YtDicF/sj8QbHzdbEBHcLCByLYAnph
+8VVoCxpPcBLmNSHbNyreoksjEE0CB10P5kPrd/bYkdNx/HTu+1i8f7a448+Nr2rF
+PwdI9tOsghkT41qobZavjjnBlT/xv5DqXldJkEfaeiJxPHOKvMhWuJcEWsODGxIF
+K4EEACMEIwQBAY7ZCAjks1MWWxibg/EVaz5t6iEKJTwu8mGGKWdPZAQRKKNtNpf0
+pZAMV3I8ue/WQMsYKRYv5AGq1PnjV19DmLsA0aGw4MDM260coctkcn/2MAJQMC9+
+3Z+BJS3hqzwDuZ+LS13r0RLpgnt3ks+3ucG4II38ZZ1lTwKoIc+w/OuhsOIDAQoJ
+iLsEGBMKACACGwwWIQRPs5/2+khXpL1+9bQgksqDJCY7agUCXFWwLgAKCRAgksqD
+JCY7ahqbAgkBiXYtiBlp5dmSYnbc4JoIYWcxTBQ+/dGHyU6ZEfC5VQz2mrdJetK1
+bIID0rFSsd24/8IzAqM3L+nY9h9bULWroroCBjTohh0j2EbW+hFOrRqL01osnlY+
+1/G8e44blB5JqsPI9FqOZOUj6IzsUuV1N9gJbm1RHu/hSpm52d6rX4nOTbqt
+=3jnl
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/rsa.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/rsa.asc
new file mode 100644
index 0000000..e74df7a
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/rsa.asc
@@ -0,0 +1,40 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQGNBFrDgZ4BDACxg83nNkYvIAz6Nk4Np4BscWDrrL3tyiiQSz1yfCotxO8zUtVl
+JorSlqRurNdAYU2XJLakMqpQHE7VVIMI/WdXCC8CrQbULOBxIf/LGiQf0VDo8ukg
+iFFd5vUeMRRILWKnMc/GCmFkFOUHd1Y60h96oe5f/d286fRZQnCO8PGS8CgB1mDJ
+GBY8U1DCCkt6g9O6bfFkfcwetr1+kB2cBIY7uDzN1Sm8dz2VrkqPqtqt/F02giRN
+hD2GxX9HVYCkCKEE9DFsB+MDKR9z5lXrI3SAsL/3htXK/ukWgBe4DIFjTXbrzgP+
+nuWb4s1NxwSD7yjlnqVD7mZTGAwMsQbCjhwIeY4t5onsCJ4/40zm1jIZ5TJsfQ/b
+5gA7iu9kMKzxO0bPI2loJEB/K9aH7qsyQHgtt7G3+G8JrixLBUobtreY9V2QvhtC
+Q4OAHRO5nIKYIazDuKv9bxautZ0WuLOk/qmWMMoqFAn5bzQeVTTBD6kvr6l8/+MZ
+zaij9YPeUbeKJuMAEQEAAbQHcnNhLXJzYYkB0gQTAQIAPAIbAwULCQgHAgMiAgEG
+FQoJCAsCBBYCAwECHgMCF4AWIQRrwEpaPds1dmuaQNgvuReRGImOiwUCXFWwhwAK
+CRAvuReRGImOi1NiC/0RPjbQTWMw4/GxIMkRb9kmmsSUe7kCgqBCqZTxcI7rxZdn
+JFDbP5c6DAS/11bRQJ9OsoUjbDx0d81UuBlXB/mNsb9nCcXOrqAUHRqgWoNSDk4g
+9Oa1Kx77OM9BvRJbJGch2YW5Wcch5vcqQNu+6x3VGt7ipljYEJSQ6Dre+dgxYjXK
+60x63/ulFk2XImPQYjQ8VHbW/HDg/+DLf++phjVy9l58U1sUKSSdO8uuYoW6dBv2
+xRg18Sn3DWOU+mrkV8Ld95+NRRE1cSHTQv5hu4ELqrV+YdGNmv9DgQAMJOl3xy8i
+vOz4cpKaOBasm423wr5Y56nOTzLFN+dxnYR8tbqswLkCldRY6fvL1NsS77rj0yZp
+pecCyi0E6RAcmSiZJqpnOpcuI76AkZuWSDEP3Y3x5QBf5fu2uiQQsPXYN8ie6xcC
+zeYtXsHyNxF0oBh2c26po8fo4E4T70RSO8Oqs1XzXnjIIle8pKU9M5U5ISbWS3Hj
+vtOn5ZrLC5KYnVRna3G5AY0EWsOBngEMALmXpJoPC1m4THYrfHibtt2/OwAlDm20
+3xn+Klw69bkeXdc71wsLOAHVL3+7gXpip+IYmN7CBIyqlOCtsluu+gwP3MczPJZX
+vk1uXMMfLKiXl9Kodx/Fqq0Y26Tqse5PPMlagPStIvKyT0WTa3RCD28uVklapLuy
+1w1k4G5hIDPt6uKyxXq/HzneRSGWafmqoCWOmXQZzfOMG249bMXNOcPMJhOejPRS
+jREnnntbpvZ8DU/38+JFtqCUkPwuqYQkvGCKReSBifMiG3XAhHWOGzXPzdW1XdAi
+aA+NQP/kMUs45jS3hDdp4EObllYRBsQwtFpKPMNmwaVuOmVlbrXTP0YsDYGndkE6
+5nJ46/2xPhl8+nIgDLg3SBBzQdOiPOGtHYjs0bRKdwXTeAq4fDq0vCQXMJF2fwAQ
+LEYWs7kabKhcPpWzTtoCG78WzR3TgldEPhPjE0offvVQO56x1XDqMBctoiDWkWkS
+bdi03GhbFdK5A7uYBTJYEoo61Yp/2/MjyQARAQABiQG2BBgBAgAgAhsMFiEEa8BK
+Wj3bNXZrmkDYL7kXkRiJjosFAlxVsI8ACgkQL7kXkRiJjoumjwv/c6a9G1bi3sh7
+wRFhpsrFUoFfEBDI4eyI/haWhCIfI8n7p3lCSIy8lmf9yvUs75d5M3EQW08NQjIs
+/o8FcFoUBnKQv2whWSHTpx/BkuhcNVY+NIwyBKomU0WkFSm3+80ix0uh97KSlRlW
+Q5nMVExNxZ4mRFAhDQrJ2/pZ2DaddeO+4uZ7Twquaix+PMxpNKvkj2+757L23YjF
+QmHdk6E8burofpSCfBTB84eUSDvzs6Eb/34/KlbBZhKMYdffMDCSAZIMfIav6YVJ
+UDzT40kmS0vRW6bDIetSbpBM+GD1cSq0wKdlt+Giur9ZiaiyHIEqbPgr6WgdND25
+Vx/i23Ik2o8wMb0Ub8cKD9wjdGAk+Rt2r7d2RzyO/R3ThKbUOGkQX6acAAZAjhPs
+UGxt1dDojmQ3nF4l2hZ9PcsyD3pz226wUUPT4JA1eE6tdoVjzY2J7EhfNaVcQQlb
+bQJQ+BQcO4oP1mPRCx1GiSmB+jRNQ4npxVJxLO/j7T27CrSZbhT7
+=aibx
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/secp256k1.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/secp256k1.asc
new file mode 100644
index 0000000..837f8a8
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/secp256k1.asc
@@ -0,0 +1,14 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mE8EWsOE8xMFK4EEAAoCAwQVHqFZWqedXUIkNFs82PsQB3bsCDhrL/73xZca3+vo
+kB4T7jHcACThuMZYuUqUo9NzNTJioluOvZG+UdYXPdfdtAplY2MtcDI1NmsxiJQE
+ExMIADwCGwMFCwkIBwIDIgIBBhUKCQgLAgQWAgMBAh4DAheAFiEEgfdytX1Ov+cA
+CmYjPqW7b5aSwaAFAlxVsQ0ACgkQPqW7b5aSwaD2tQD/R4d15NBuSJ6IB1brH0E9
+nEWkqo892PaAY5akdCO/i9EBAMsjE5NPxBnCs03c+VHFU200k27ixdrWpUa+HZEI
+A5wSuFMEWsOE8xIFK4EEAAoCAwSUWwe7CaaOYRANiKet2evLiOumefIHuvRpyOSK
+hyRdclIWpBUCAWEnmalkEL/8cEM5fjtILtCOKXqCOBsPv45HAwEIB4h4BBgTCAAg
+AhsMFiEEgfdytX1Ov+cACmYjPqW7b5aSwaAFAlxVsRUACgkQPqW7b5aSwaCETgD/
+YXzCMYMbPGAU2oTitjAno8hDWmgTeaFWeCmqf6l9mP8BAKvpewWeFGZfWGAQcWPi
+E+jv7vadvEt1yMA8rmT041F5
+=mDCI
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/x25519.asc b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/x25519.asc
new file mode 100644
index 0000000..d531d7a
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst-rsrc/org/eclipse/jgit/gpg/bc/internal/keys/x25519.asc
@@ -0,0 +1,13 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mDMEW8SVGhYJKwYBBAHaRw8BAQdA9SMZ2uw0YugMFcl5TpEZeBRAGniEk9a42XNs
+7QA4Tky0DGVkZHNhLXgyNTUxOYiQBBMWCAA4FiEETJc4pvK+Thp5bJt7lBgioPwb
+MKUFAlvElRoCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQlBgioPwbMKUi
+1wEAgMq3X7o17OJBPfY3He/exDR6LhWwAAXrVQR/WdRiHkEBALd1Mj0BlZZLoKTr
+uJ4MD5CYZLicXTRwOv6e52F/DHwJuDgEW8SVGhIKKwYBBAGXVQEFAQEHQA0Lh2mG
+lB1O4xDYgztm/aX7+8AdHEGaMsCF1RQ6wVUeAwEIB4h4BBgWCAAgFiEETJc4pvK+
+Thp5bJt7lBgioPwbMKUFAlvElRoCGwwACgkQlBgioPwbMKXmlQD+KxVg2dGL8lRW
+rQajwzmuwMrJX1lvJylg5Ozk6SGrBeABANZrdt8bmArEqeRVxFO2F4P7btyIpf1w
+5aNpqqtvkRcB
+=EYfV
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgKeyLocatorTest.java b/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgKeyLocatorTest.java
index 7446201..5f43378 100644
--- a/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgKeyLocatorTest.java
+++ b/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgKeyLocatorTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019, Thomas Wolf <thomas.wolf@paranor.ch> and others
+ * Copyright (C) 2019, 2020 Thomas Wolf <thomas.wolf@paranor.ch> 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
@@ -53,7 +53,7 @@ public void testFullEmail() throws Exception {
 		assertFalse(match(USER_ID, "<heinrichh>"));
 		assertFalse(match(USER_ID, "<uni-duesseldorf>"));
 		assertFalse(match(USER_ID, "<h@u>"));
-		assertFalse(match(USER_ID, "<HeinrichH@uni-duesseldorf.de>"));
+		assertTrue(match(USER_ID, "<HeinrichH@uni-duesseldorf.de>"));
 		assertFalse(match(USER_ID.substring(0, USER_ID.length() - 1),
 				"<heinrichh@uni-duesseldorf.de>"));
 		assertFalse(match("", "<>"));
@@ -72,8 +72,8 @@ public void testPartialEmail() throws Exception {
 		assertFalse(match(USER_ID, "@ "));
 		assertFalse(match(USER_ID, "@"));
 		assertFalse(match(USER_ID, "@Heine"));
-		assertFalse(match(USER_ID, "@HeinrichH"));
-		assertFalse(match(USER_ID, "@Heinrich"));
+		assertTrue(match(USER_ID, "@HeinrichH"));
+		assertTrue(match(USER_ID, "@Heinrich"));
 		assertFalse(match("", "@"));
 		assertFalse(match("", "@h"));
 	}
@@ -110,6 +110,7 @@ public void testSubstringAsterisk() throws Exception {
 	public void testExplicitFingerprint() throws Exception {
 		assertFalse(match("John Fade <j.fade@example.com>", "0xfade"));
 		assertFalse(match("John Fade <0xfade@example.com>", "0xfade"));
+		assertFalse(match("John Fade <0xfade@example.com>", "0xFADE"));
 		assertFalse(match("", "0xfade"));
 	}
 
@@ -128,7 +129,7 @@ public void testZeroX() throws Exception {
 		assertTrue(match("John Fade <0xfade@example.com>", "*0xfade"));
 		assertTrue(match("John Fade <0xfade@example.com>", "*0xFADE"));
 		assertTrue(match("John Fade <0xfade@example.com>", "@0xfade"));
-		assertFalse(match("John Fade <0xfade@example.com>", "@0xFADE"));
+		assertTrue(match("John Fade <0xfade@example.com>", "@0xFADE"));
 		assertFalse(match("", "0x"));
 	}
 }
diff --git a/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/keys/KeyGrip25519Test.java b/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/keys/KeyGrip25519Test.java
new file mode 100644
index 0000000..e300802
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/keys/KeyGrip25519Test.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2021, Thomas Wolf <thomas.wolf@paranor.ch> 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
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.gpg.bc.internal.keys;
+
+import static org.junit.Assert.assertEquals;
+
+import java.math.BigInteger;
+import java.util.Locale;
+
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.util.encoders.Hex;
+import org.eclipse.jgit.util.sha1.SHA1;
+import org.junit.Test;
+
+public class KeyGrip25519Test {
+
+	interface Hash {
+		byte[] hash(SHA1 sha, BigInteger q) throws PGPException;
+	}
+
+	private void assertKeyGrip(String key, String expectedKeyGrip, Hash hash)
+			throws Exception {
+		SHA1 grip = SHA1.newInstance();
+		grip.setDetectCollision(false);
+		BigInteger pk = new BigInteger(key, 16);
+		byte[] keyGrip = hash.hash(grip, pk);
+		assertEquals("Keygrip should match", expectedKeyGrip,
+				Hex.toHexString(keyGrip).toUpperCase(Locale.ROOT));
+	}
+
+	@Test
+	public void testCompressed() throws Exception {
+		assertKeyGrip("40"
+				+ "773E72848C1FD5F9652B29E2E7AF79571A04990E96F2016BF4E0EC1890C2B7DB",
+				"9DB6C64A38830F4960701789475520BE8C821F47",
+				KeyGrip::hashEd25519);
+	}
+
+	@Test
+	public void testCompressedNoPrefix() throws Exception {
+		assertKeyGrip(
+				"773E72848C1FD5F9652B29E2E7AF79571A04990E96F2016BF4E0EC1890C2B7DB",
+				"9DB6C64A38830F4960701789475520BE8C821F47",
+				KeyGrip::hashEd25519);
+	}
+
+	@Test
+	public void testCurve25519() throws Exception {
+		assertKeyGrip("40"
+				+ "918C1733127F6BF2646FAE3D081A18AE77111C903B906310B077505EFFF12740",
+				"0F89A565D3EA187CE839332398F5D480677DF49C",
+				KeyGrip::hashCurve25519);
+	}
+}
diff --git a/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/keys/KeyGripTest.java b/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/keys/KeyGripTest.java
new file mode 100644
index 0000000..a4aaf40
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/keys/KeyGripTest.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2021, Thomas Wolf <thomas.wolf@paranor.ch> 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
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.gpg.bc.internal.keys;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.Security;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.function.Consumer;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPPublicKey;
+import org.bouncycastle.openpgp.PGPPublicKeyRing;
+import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
+import org.bouncycastle.openpgp.PGPUtil;
+import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
+import org.bouncycastle.util.encoders.Hex;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class KeyGripTest {
+
+	@BeforeClass
+	public static void ensureBC() {
+		if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
+			Security.addProvider(new BouncyCastleProvider());
+		}
+	}
+
+	protected static class TestData {
+
+		String filename;
+
+		String[] expectedKeyGrips;
+
+		TestData(String filename, String... keyGrips) {
+			this.filename = filename;
+			this.expectedKeyGrips = keyGrips;
+		}
+
+		@Override
+		public String toString() {
+			return filename;
+		}
+	}
+
+	@Parameters(name = "{0}")
+	public static TestData[] initTestData() {
+		return new TestData[] {
+				new TestData("rsa.asc",
+						"D148210FAF36468055B83D0F5A6DEB83FBC8E864",
+						"A5E4CD2CBBE44A16E4D6EC05C2E3C3A599DC763C"),
+				new TestData("dsa-elgamal.asc",
+						"552286BEB2999F0A9E26A50385B90D9724001187",
+						"CED7034A8EB5F4CE90DF99147EC33D86FCD3296C"),
+				new TestData("brainpool256.asc",
+						"A01BAA22A72F09A0FF0A1D4CBCE70844DD52DDD7",
+						"C1678B7DE5F144C93B89468D5F9764ACE182ED36"),
+				new TestData("brainpool384.asc",
+						"2F25DB025DEBF3EA2715350209B985829B04F50A",
+						"B6BD8B81F75AF914163D97DF8DE8F6FC64C283F8"),
+				new TestData("brainpool512.asc",
+						"5A484F56AB4B8B6583B6365034999F6543FAE1AE",
+						"9133E4A7E8FC8515518DF444C3F2F247EEBBADEC"),
+				new TestData("nistp256.asc",
+						"FC81AECE90BCE6E54D0D637D266109783AC8DAC0",
+						"A56DC8DB8355747A809037459B4258B8A743EAB5"),
+				new TestData("nistp384.asc",
+						"A1338230AED1C9C125663518470B49056C9D1733",
+						"797A83FE041FFE06A7F4B1D32C6F4AE0F6D87ADF"),
+				new TestData("nistp521.asc",
+						"D91B789603EC9138AA20342A2B6DC86C81B70F5D",
+						"FD048B2CA1919CB241DC8A2C7FA3E742EF343DCA"),
+				new TestData("secp256k1.asc",
+						"498B89C485489BA16B40755C0EBA580166393074",
+						"48FFED40D018747363BDEFFDD404D1F4870F8064"),
+				new TestData("ed25519.asc",
+						"940D97D75C306D737A59A98EAFF1272832CEDC0B"),
+				new TestData("x25519.asc",
+						"A77DC8173DA6BEE126F5BD6F5A14E01200B52FCE",
+						"636C983EDB558527BA82780B52CB5DAE011BE46B")
+		};
+	}
+
+	// Injected by JUnit
+	@Parameter
+	public TestData data;
+
+	private void readAsc(InputStream in, Consumer<PGPPublicKey> process)
+			throws IOException, PGPException {
+		PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(
+			PGPUtil.getDecoderStream(in), new JcaKeyFingerprintCalculator());
+
+		Iterator<PGPPublicKeyRing> keyRings = pgpPub.getKeyRings();
+		while (keyRings.hasNext()) {
+			PGPPublicKeyRing keyRing = keyRings.next();
+
+			Iterator<PGPPublicKey> keys = keyRing.getPublicKeys();
+			while (keys.hasNext()) {
+				process.accept(keys.next());
+			}
+		}
+	}
+
+	@Test
+	public void testGrip() throws Exception {
+		try (InputStream in = this.getClass()
+				.getResourceAsStream(data.filename)) {
+			int index[] = { 0 };
+			readAsc(in, key -> {
+				byte[] keyGrip = null;
+				try {
+					keyGrip = KeyGrip.getKeyGrip(key);
+				} catch (PGPException e) {
+					throw new RuntimeException(e);
+				}
+				assertTrue("More keys than expected",
+						index[0] < data.expectedKeyGrips.length);
+				assertEquals("Wrong keygrip", data.expectedKeyGrips[index[0]++],
+						Hex.toHexString(keyGrip).toUpperCase(Locale.ROOT));
+			});
+			assertEquals("Missing keys", data.expectedKeyGrips.length,
+					index[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
new file mode 100644
index 0000000..5e5e303
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeysTest.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2021 Thomas Wolf <thomas.wolf@paranor.ch> 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
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+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;
+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;
+import org.bouncycastle.openpgp.PGPPublicKeyRing;
+import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
+import org.bouncycastle.openpgp.PGPSecretKey;
+import org.bouncycastle.openpgp.PGPUtil;
+import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider;
+import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
+import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class SecretKeysTest {
+
+	@BeforeClass
+	public static void ensureBC() {
+		if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
+			Security.addProvider(new BouncyCastleProvider());
+		}
+	}
+
+	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) {
+			this.name = name;
+			this.encrypted = encrypted;
+			this.keyValue = keyValue;
+		}
+
+		@Override
+		public String toString() {
+			return name;
+		}
+	}
+
+	@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("faked", false, true) };
+	}
+
+	private static byte[] readTestKey(String filename) throws Exception {
+		try (InputStream in = new BufferedInputStream(
+				SecretKeysTest.class.getResourceAsStream(filename))) {
+			return SecretKeys.keyFromNameValueFormat(in);
+		}
+	}
+
+	private static PGPPublicKey readAsc(InputStream in)
+			throws IOException, PGPException {
+		PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(
+			PGPUtil.getDecoderStream(in), new JcaKeyFingerprintCalculator());
+
+		Iterator<PGPPublicKeyRing> keyRings = pgpPub.getKeyRings();
+		while (keyRings.hasNext()) {
+			PGPPublicKeyRing keyRing = keyRings.next();
+
+			Iterator<PGPPublicKey> keys = keyRing.getPublicKeys();
+			if (keys.hasNext()) {
+				return keys.next();
+			}
+		}
+		return null;
+	}
+
+	// Injected by JUnit
+	@Parameter
+	public TestData data;
+
+	@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) {
+				PGPPublicKey publicKey = readAsc(pubIn);
+				// Do a full test trying to load the secret key.
+				PGPDigestCalculatorProvider calculatorProvider = new JcaPGPDigestCalculatorProviderBuilder()
+						.build();
+				try (InputStream in = new BufferedInputStream(this.getClass()
+						.getResourceAsStream(data.name + ".key"))) {
+					PGPSecretKey secretKey = SecretKeys.readSecretKey(in,
+							calculatorProvider,
+							data.encrypted ? () -> "nonsense".toCharArray()
+									: null,
+							publicKey);
+					assertNotNull(secretKey);
+				} catch (PGPException e) {
+					// Currently we may not be able to load OCB-encrypted keys.
+					assertTrue(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 a75778f..3fbdb2a 100644
--- a/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF
@@ -3,27 +3,35 @@
 Bundle-Name: %Bundle-Name
 Automatic-Module-Name: org.eclipse.jgit.gpg.bc
 Bundle-SymbolicName: org.eclipse.jgit.gpg.bc;singleton:=true
-Fragment-Host: org.eclipse.jgit;bundle-version="[5.10.1,5.11.0)"
+Fragment-Host: org.eclipse.jgit;bundle-version="[5.11.2,5.12.0)"
 Bundle-Vendor: %Bundle-Vendor
 Bundle-Localization: plugin
-Bundle-Version: 5.10.1.qualifier
+Bundle-Version: 5.11.2.qualifier
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.bouncycastle.bcpg;version="[1.65.0,2.0.0)",
+Import-Package: org.bouncycastle.asn1;version="[1.65.0,2.0.0)",
+ org.bouncycastle.asn1.cryptlib;version="[1.65.0,2.0.0)",
+ org.bouncycastle.asn1.x9;version="[1.65.0,2.0.0)",
+ org.bouncycastle.bcpg;version="[1.65.0,2.0.0)",
+ org.bouncycastle.bcpg.sig;version="[1.65.0,2.0.0)",
+ org.bouncycastle.crypto.ec;version="[1.65.0,2.0.0)",
  org.bouncycastle.gpg;version="[1.65.0,2.0.0)",
  org.bouncycastle.gpg.keybox;version="[1.65.0,2.0.0)",
  org.bouncycastle.gpg.keybox.jcajce;version="[1.65.0,2.0.0)",
+ org.bouncycastle.jcajce.interfaces;version="[1.65.0,2.0.0)",
+ org.bouncycastle.jcajce.util;version="[1.65.0,2.0.0)",
  org.bouncycastle.jce.provider;version="[1.65.0,2.0.0)",
+ org.bouncycastle.math.ec;version="[1.65.0,2.0.0)",
+ org.bouncycastle.math.field;version="[1.65.0,2.0.0)",
  org.bouncycastle.openpgp;version="[1.65.0,2.0.0)",
+ org.bouncycastle.openpgp.jcajce;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;version="[1.65.0,2.0.0)",
  org.bouncycastle.util.encoders;version="[1.65.0,2.0.0)",
- org.eclipse.jgit.annotations;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.api.errors;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.errors;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lib;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.nls;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.transport;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.util;version="[5.10.1,5.11.0)",
+ org.bouncycastle.util.io;version="[1.65.0,2.0.0)",
+ org.eclipse.jgit.annotations;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.api.errors;version="[5.11.2,5.12.0)",
  org.slf4j;version="[1.7.0,2.0.0)"
-Export-Package: org.eclipse.jgit.gpg.bc.internal;version="5.10.1";
-  x-friends:="org.eclipse.jgit.gpg.bc.test"
+Export-Package: org.eclipse.jgit.gpg.bc;version="5.11.2",
+ org.eclipse.jgit.gpg.bc.internal;version="5.11.2";x-friends:="org.eclipse.jgit.gpg.bc.test",
+ org.eclipse.jgit.gpg.bc.internal.keys;version="5.11.2";x-friends:="org.eclipse.jgit.gpg.bc.test"
diff --git a/org.eclipse.jgit.gpg.bc/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.gpg.bc/META-INF/SOURCE-MANIFEST.MF
index 96e71c7..dde429d 100644
--- a/org.eclipse.jgit.gpg.bc/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.gpg.bc/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
 Bundle-Name: org.eclipse.jgit.gpg.bc - Sources
 Bundle-SymbolicName: org.eclipse.jgit.gpg.bc.source
 Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 5.10.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.gpg.bc;version="5.10.1.qualifier";roots="."
+Bundle-Version: 5.11.2.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.gpg.bc;version="5.11.2.qualifier";roots="."
diff --git a/org.eclipse.jgit.gpg.bc/about.html b/org.eclipse.jgit.gpg.bc/about.html
index f971af1..fc527d5 100644
--- a/org.eclipse.jgit.gpg.bc/about.html
+++ b/org.eclipse.jgit.gpg.bc/about.html
@@ -11,7 +11,7 @@
     margin: 0.25in 0.5in 0.25in 0.5in;
     tab-interval: 0.5in;
     }
-  p {  	
+  p {
     margin-left: auto;
     margin-top:  0.5em;
     margin-bottom: 0.5em;
@@ -36,60 +36,53 @@
 <p>Copyright (c) 2007, Eclipse Foundation, Inc. and its licensors. </p>
 
 <p>All rights reserved.</p>
-<p>Redistribution and use in source and binary forms, with or without modification, 
+<p>Redistribution and use in source and binary forms, with or without modification,
 	are permitted provided that the following conditions are met:
-<ul><li>Redistributions of source code must retain the above copyright notice, 
+<ul><li>Redistributions of source code must retain the above copyright notice,
 	this list of conditions and the following disclaimer. </li>
-<li>Redistributions in binary form must reproduce the above copyright notice, 
-	this list of conditions and the following disclaimer in the documentation 
+<li>Redistributions in binary form must reproduce the above copyright notice,
+	this list of conditions and the following disclaimer in the documentation
 	and/or other materials provided with the distribution. </li>
-<li>Neither the name of the Eclipse Foundation, Inc. nor the names of its 
-	contributors may be used to endorse or promote products derived from 
+<li>Neither the name of the Eclipse Foundation, Inc. nor the names of its
+	contributors may be used to endorse or promote products derived from
 	this software without specific prior written permission. </li></ul>
 </p>
-<p>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
-IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
-INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
-NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+<p>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.</p>
 
 <hr>
-<p><b>SHA-1 UbcCheck - MIT</b></p>
+<p><b>org.eclipse.jgit.gpg.bc.internal.keys.SExprParser - MIT</b></p>
 
-<p>Copyright (c) 2017:</p>
-<div class="ubc-name">
-Marc Stevens
-Cryptology Group
-Centrum Wiskunde & Informatica
-P.O. Box 94079, 1090 GB Amsterdam, Netherlands
-marc@marc-stevens.nl
-</div>
-<div class="ubc-name">
-Dan Shumow
-Microsoft Research
-danshu@microsoft.com
-</div>
-<p>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:
+<p>Copyright (c) 2000-2021 The Legion of the Bouncy Castle Inc.
+(<a href="https://www.bouncycastle.org">https://www.bouncycastle.org</a>)</p>
+
+<p>
+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:
 </p>
-<ul><li>The above copyright notice and this permission notice shall be included
-in all copies or substantial portions of the Software.</li></ul>
-<p>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.</p>
+<p>
+The above copyright notice and this permission notice shall be included in all copies or substantial
+portions of the Software.
+</p>
+<p>
+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.
+</p>
 
 </body>
 
diff --git a/org.eclipse.jgit.gpg.bc/pom.xml b/org.eclipse.jgit.gpg.bc/pom.xml
index ff4eeb4..c8d4ac5 100644
--- a/org.eclipse.jgit.gpg.bc/pom.xml
+++ b/org.eclipse.jgit.gpg.bc/pom.xml
@@ -17,7 +17,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.10.1-SNAPSHOT</version>
+    <version>5.11.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.gpg.bc</artifactId>
diff --git a/org.eclipse.jgit.gpg.bc/resources/META-INF/services/org.eclipse.jgit.lib.GpgSignatureVerifierFactory b/org.eclipse.jgit.gpg.bc/resources/META-INF/services/org.eclipse.jgit.lib.GpgSignatureVerifierFactory
new file mode 100644
index 0000000..17ab30f
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc/resources/META-INF/services/org.eclipse.jgit.lib.GpgSignatureVerifierFactory
@@ -0,0 +1 @@
+org.eclipse.jgit.gpg.bc.internal.BouncyCastleGpgSignatureVerifierFactory
\ No newline at end of file
diff --git a/org.eclipse.jgit.gpg.bc/resources/org/eclipse/jgit/gpg/bc/internal/BCText.properties b/org.eclipse.jgit.gpg.bc/resources/org/eclipse/jgit/gpg/bc/internal/BCText.properties
index 1441c63..e4b1bab 100644
--- a/org.eclipse.jgit.gpg.bc/resources/org/eclipse/jgit/gpg/bc/internal/BCText.properties
+++ b/org.eclipse.jgit.gpg.bc/resources/org/eclipse/jgit/gpg/bc/internal/BCText.properties
@@ -1,11 +1,36 @@
+corrupt25519Key=Ed25519/Curve25519 public key has wrong length: {0}
 credentialPassphrase=Passphrase
-gpgFailedToParseSecretKey=Failed to parse secret key file in directory: {0}. Is the entered passphrase correct?
+cryptCipherError=Cannot create cipher to decrypt: {0}
+cryptWrongDecryptedLength=Decrypted key has wrong length; expected {0} bytes, got only {1} bytes
+gpgFailedToParseSecretKey=Failed to parse secret key file {0}. Is the entered passphrase correct?
 gpgNoCredentialsProvider=missing credentials provider
+gpgNoKeygrip=Cannot find key {0}: cannot determine key grip
 gpgNoKeyring=neither pubring.kbx nor secring.gpg files found
 gpgNoKeyInLegacySecring=no matching secret key found in legacy secring.gpg for key or user id: {0}
 gpgNoPublicKeyFound=Unable to find a public-key with key or user id: {0}
 gpgNoSecretKeyForPublicKey=unable to find associated secret key for public key: {0}
+gpgNoSuchAlgorithm=Cannot decrypt encrypted secret key: encryption algorithm {0} is not available
 gpgNotASigningKey=Secret key ({0}) is not suitable for signing
 gpgKeyInfo=GPG Key (fingerprint {0})
 gpgSigningCancelled=Signing was cancelled
+nonSignatureError=Signature does not decode into a signature object
+secretKeyTooShort=Secret key file corrupt; only {0} bytes read
+sexprHexNotClosed=Hex number in s-expression not closed
+sexprHexOdd=Hex number in s-expression has an odd number of digits
+sexprStringInvalidEscape=Invalid escape {0} in s-expression
+sexprStringInvalidEscapeAtEnd=Invalid s-expression: quoted string ends with escape character
+sexprStringInvalidHexEscape=Invalid hex escape in s-expression
+sexprStringInvalidOctalEscape=Invalid octal escape in s-expression
+sexprStringNotClosed=String in s-expression not closed
+sexprUnhandled=Unhandled token {0} in s-expression
+signatureInconsistent=Inconsistent signature; key ID {0} does not match issuer fingerprint {1}
+signatureKeyLookupError=Error occurred while looking for public key
+signatureNoKeyInfo=No way to determine a public key from the signature
+signatureNoPublicKey=No public key found to verify the signature
+signatureParseError=Signature cannot be parsed
+signatureVerificationError=Signature verification failed
 unableToSignCommitNoSecretKey=Unable to sign commit. Signing key not available.
+uncompressed25519Key=Cannot handle ed25519 public key with uncompressed data: {0}
+unknownCurve=Unknown curve {0}
+unknownCurveParameters=Curve {0} does not have a prime field
+unknownKeyType=Unknown key type {0}
\ No newline at end of file
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/BouncyCastleGpgSignerFactory.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/BouncyCastleGpgSignerFactory.java
new file mode 100644
index 0000000..fdd1a2b
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/BouncyCastleGpgSignerFactory.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2021 Thomas Wolf <thomas.wolf@paranor.ch> 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
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.gpg.bc;
+
+import org.eclipse.jgit.gpg.bc.internal.BouncyCastleGpgSigner;
+import org.eclipse.jgit.lib.GpgSigner;
+
+/**
+ * Factory for creating a {@link GpgSigner} based on Bouncy Castle.
+ *
+ * @since 5.11
+ */
+public final class BouncyCastleGpgSignerFactory {
+
+	private BouncyCastleGpgSignerFactory() {
+		// No instantiation
+	}
+
+	/**
+	 * Creates a new {@link GpgSigner}.
+	 *
+	 * @return the {@link GpgSigner}
+	 */
+	public static GpgSigner create() {
+		return new BouncyCastleGpgSigner();
+	}
+}
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BCText.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BCText.java
index 1a00b0f..aedf8a5 100644
--- a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BCText.java
+++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BCText.java
@@ -1,3 +1,12 @@
+/*
+ * Copyright (C) 2018, 2021 Salesforce 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
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
 package org.eclipse.jgit.gpg.bc.internal;
 
 import org.eclipse.jgit.nls.NLS;
@@ -18,16 +27,41 @@ public static BCText get() {
 	}
 
 	// @formatter:off
+	/***/ public String corrupt25519Key;
 	/***/ public String credentialPassphrase;
+	/***/ public String cryptCipherError;
+	/***/ public String cryptWrongDecryptedLength;
 	/***/ public String gpgFailedToParseSecretKey;
 	/***/ public String gpgNoCredentialsProvider;
+	/***/ public String gpgNoKeygrip;
 	/***/ public String gpgNoKeyring;
 	/***/ public String gpgNoKeyInLegacySecring;
 	/***/ public String gpgNoPublicKeyFound;
 	/***/ public String gpgNoSecretKeyForPublicKey;
+	/***/ public String gpgNoSuchAlgorithm;
 	/***/ public String gpgNotASigningKey;
 	/***/ public String gpgKeyInfo;
 	/***/ public String gpgSigningCancelled;
+	/***/ public String nonSignatureError;
+	/***/ public String secretKeyTooShort;
+	/***/ public String sexprHexNotClosed;
+	/***/ public String sexprHexOdd;
+	/***/ public String sexprStringInvalidEscape;
+	/***/ public String sexprStringInvalidEscapeAtEnd;
+	/***/ public String sexprStringInvalidHexEscape;
+	/***/ public String sexprStringInvalidOctalEscape;
+	/***/ public String sexprStringNotClosed;
+	/***/ public String sexprUnhandled;
+	/***/ public String signatureInconsistent;
+	/***/ public String signatureKeyLookupError;
+	/***/ public String signatureNoKeyInfo;
+	/***/ public String signatureNoPublicKey;
+	/***/ public String signatureParseError;
+	/***/ public String signatureVerificationError;
 	/***/ public String unableToSignCommitNoSecretKey;
+	/***/ public String uncompressed25519Key;
+	/***/ public String unknownCurve;
+	/***/ public String unknownCurveParameters;
+	/***/ public String unknownKeyType;
 
 }
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgKeyLocator.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgKeyLocator.java
index eca4507..cf4d3d2 100644
--- a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgKeyLocator.java
+++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgKeyLocator.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018, 2020 Salesforce and others
+ * Copyright (C) 2018, 2021 Salesforce 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
@@ -14,25 +14,22 @@
 
 import java.io.BufferedInputStream;
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URISyntaxException;
 import java.nio.file.DirectoryStream;
 import java.nio.file.Files;
 import java.nio.file.InvalidPathException;
+import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.security.NoSuchAlgorithmException;
 import java.security.NoSuchProviderException;
 import java.text.MessageFormat;
-import java.util.ArrayList;
 import java.util.Iterator;
-import java.util.List;
 import java.util.Locale;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
 
-import org.bouncycastle.gpg.SExprParser;
 import org.bouncycastle.gpg.keybox.BlobType;
 import org.bouncycastle.gpg.keybox.KeyBlob;
 import org.bouncycastle.gpg.keybox.KeyBox;
@@ -50,15 +47,15 @@
 import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
 import org.bouncycastle.openpgp.PGPSignature;
 import org.bouncycastle.openpgp.PGPUtil;
-import org.bouncycastle.openpgp.operator.PBEProtectionRemoverFactory;
 import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider;
 import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
 import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
-import org.bouncycastle.openpgp.operator.jcajce.JcePBEProtectionRemoverFactory;
 import org.bouncycastle.util.encoders.Hex;
 import org.eclipse.jgit.annotations.NonNull;
 import org.eclipse.jgit.api.errors.CanceledException;
 import org.eclipse.jgit.errors.UnsupportedCredentialItem;
+import org.eclipse.jgit.gpg.bc.internal.keys.KeyGrip;
+import org.eclipse.jgit.gpg.bc.internal.keys.SecretKeys;
 import org.eclipse.jgit.util.FS;
 import org.eclipse.jgit.util.StringUtils;
 import org.eclipse.jgit.util.SystemReader;
@@ -78,17 +75,10 @@ private static class NoOpenPgpKeyException extends Exception {
 
 	}
 
-	/** Thrown if we try to read an encrypted private key without password. */
-	private static class EncryptedPgpKeyException extends RuntimeException {
-
-		private static final long serialVersionUID = 1L;
-
-	}
-
 	private static final Logger log = LoggerFactory
 			.getLogger(BouncyCastleGpgKeyLocator.class);
 
-	private static final Path GPG_DIRECTORY = findGpgDirectory();
+	static final Path GPG_DIRECTORY = findGpgDirectory();
 
 	private static final Path USER_KEYBOX_PATH = GPG_DIRECTORY
 			.resolve("pubring.kbx"); //$NON-NLS-1$
@@ -155,16 +145,13 @@ public BouncyCastleGpgKeyLocator(String signingKey,
 
 	private PGPSecretKey attemptParseSecretKey(Path keyFile,
 			PGPDigestCalculatorProvider calculatorProvider,
-			PBEProtectionRemoverFactory passphraseProvider,
-			PGPPublicKey publicKey) {
+			SecretKeys.PassphraseSupplier passphraseSupplier,
+			PGPPublicKey publicKey)
+			throws IOException, PGPException, CanceledException,
+			UnsupportedCredentialItem, URISyntaxException {
 		try (InputStream in = newInputStream(keyFile)) {
-			return new SExprParser(calculatorProvider).parseSecretKey(
-					new BufferedInputStream(in), passphraseProvider, publicKey);
-		} catch (IOException | PGPException | ClassCastException e) {
-			if (log.isDebugEnabled())
-				log.debug("Ignoring unreadable file '{}': {}", keyFile, //$NON-NLS-1$
-						e.getMessage(), e);
-			return null;
+			return SecretKeys.readSecretKey(in, calculatorProvider,
+					passphraseSupplier, publicKey);
 		}
 	}
 
@@ -219,33 +206,60 @@ static boolean containsSigningKey(String userId, String signingKeySpec) {
 			int stop = toMatch.indexOf('>');
 			return begin >= 0 && end > begin + 1 && stop > 0
 					&& userId.substring(begin + 1, end)
-							.equals(toMatch.substring(0, stop));
+							.equalsIgnoreCase(toMatch.substring(0, stop));
 		}
 		case '@': {
 			int begin = userId.indexOf('<');
 			int end = userId.indexOf('>', begin + 1);
 			return begin >= 0 && end > begin + 1
-					&& userId.substring(begin + 1, end).contains(toMatch);
+					&& containsIgnoreCase(userId.substring(begin + 1, end),
+							toMatch);
 		}
 		default:
 			if (toMatch.trim().isEmpty()) {
 				return false;
 			}
-			return userId.toLowerCase(Locale.ROOT)
-					.contains(toMatch.toLowerCase(Locale.ROOT));
+			return containsIgnoreCase(userId, toMatch);
 		}
 	}
 
-	private String toFingerprint(String keyId) {
+	private static boolean containsIgnoreCase(String a, String b) {
+		int alength = a.length();
+		int blength = b.length();
+		for (int i = 0; i + blength <= alength; i++) {
+			if (a.regionMatches(true, i, b, 0, blength)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	private static String toFingerprint(String keyId) {
 		if (keyId.startsWith("0x")) { //$NON-NLS-1$
 			return keyId.substring(2);
 		}
 		return keyId;
 	}
 
-	private PGPPublicKey findPublicKeyByKeyId(KeyBlob keyBlob)
+	static PGPPublicKey findPublicKey(String fingerprint, String keySpec)
+			throws IOException, PGPException {
+		PGPPublicKey result = findPublicKeyInPubring(USER_PGP_PUBRING_FILE,
+				fingerprint, keySpec);
+		if (result == null && exists(USER_KEYBOX_PATH)) {
+			try {
+				result = findPublicKeyInKeyBox(USER_KEYBOX_PATH, fingerprint,
+						keySpec);
+			} catch (NoSuchAlgorithmException | NoSuchProviderException
+					| IOException | NoOpenPgpKeyException e) {
+				log.error(e.getMessage(), e);
+			}
+		}
+		return result;
+	}
+
+	private static PGPPublicKey findPublicKeyByKeyId(KeyBlob keyBlob,
+			String keyId)
 			throws IOException {
-		String keyId = toFingerprint(signingKey).toLowerCase(Locale.ROOT);
 		if (keyId.isEmpty()) {
 			return null;
 		}
@@ -259,10 +273,11 @@ private PGPPublicKey findPublicKeyByKeyId(KeyBlob keyBlob)
 		return null;
 	}
 
-	private PGPPublicKey findPublicKeyByUserId(KeyBlob keyBlob)
+	private static PGPPublicKey findPublicKeyByUserId(KeyBlob keyBlob,
+			String keySpec)
 			throws IOException {
 		for (UserID userID : keyBlob.getUserIds()) {
-			if (containsSigningKey(userID.getUserIDAsString(), signingKey)) {
+			if (containsSigningKey(userID.getUserIDAsString(), keySpec)) {
 				return getSigningPublicKey(keyBlob);
 			}
 		}
@@ -274,6 +289,10 @@ private PGPPublicKey findPublicKeyByUserId(KeyBlob keyBlob)
 	 *
 	 * @param keyboxFile
 	 *            the KeyBox file
+	 * @param keyId
+	 *            to look for, may be null
+	 * @param keySpec
+	 *            to look for
 	 * @return publicKey the public key (maybe <code>null</code>)
 	 * @throws IOException
 	 *             in case of problems reading the file
@@ -282,19 +301,22 @@ private PGPPublicKey findPublicKeyByUserId(KeyBlob keyBlob)
 	 * @throws NoOpenPgpKeyException
 	 *             if the file does not contain any OpenPGP key
 	 */
-	private PGPPublicKey findPublicKeyInKeyBox(Path keyboxFile)
+	private static PGPPublicKey findPublicKeyInKeyBox(Path keyboxFile,
+			String keyId, String keySpec)
 			throws IOException, NoSuchAlgorithmException,
 			NoSuchProviderException, NoOpenPgpKeyException {
 		KeyBox keyBox = readKeyBoxFile(keyboxFile);
+		String id = keyId != null ? keyId
+				: toFingerprint(keySpec).toLowerCase(Locale.ROOT);
 		boolean hasOpenPgpKey = false;
 		for (KeyBlob keyBlob : keyBox.getKeyBlobs()) {
 			if (keyBlob.getType() == BlobType.OPEN_PGP_BLOB) {
 				hasOpenPgpKey = true;
-				PGPPublicKey key = findPublicKeyByKeyId(keyBlob);
+				PGPPublicKey key = findPublicKeyByKeyId(keyBlob, id);
 				if (key != null) {
 					return key;
 				}
-				key = findPublicKeyByUserId(keyBlob);
+				key = findPublicKeyByUserId(keyBlob, keySpec);
 				if (key != null) {
 					return key;
 				}
@@ -338,7 +360,8 @@ public BouncyCastleGpgKey findSecretKey() throws IOException,
 			// pubring.gpg also try secring.gpg to find the secret key.
 			if (exists(USER_KEYBOX_PATH)) {
 				try {
-					publicKey = findPublicKeyInKeyBox(USER_KEYBOX_PATH);
+					publicKey = findPublicKeyInKeyBox(USER_KEYBOX_PATH, null,
+							signingKey);
 					if (publicKey != null) {
 						key = findSecretKeyForKeyBoxPublicKey(publicKey,
 								USER_KEYBOX_PATH);
@@ -361,7 +384,8 @@ public BouncyCastleGpgKey findSecretKey() throws IOException,
 				}
 			}
 			if (exists(USER_PGP_PUBRING_FILE)) {
-				publicKey = findPublicKeyInPubring(USER_PGP_PUBRING_FILE);
+				publicKey = findPublicKeyInPubring(USER_PGP_PUBRING_FILE, null,
+						signingKey);
 				if (publicKey != null) {
 					// GPG < 2.1 may have both; the agent using the directory
 					// and gpg using secring.gpg. GPG >= 2.1 delegates all
@@ -433,67 +457,59 @@ private BouncyCastleGpgKey findSecretKeyForKeyBoxPublicKey(
 			PGPPublicKey publicKey, Path userKeyboxPath)
 			throws PGPException, CanceledException, UnsupportedCredentialItem,
 			URISyntaxException {
-		/*
-		 * this is somewhat brute-force but there doesn't seem to be another
-		 * way; we have to walk all private key files we find and try to open
-		 * them
-		 */
-
-		PGPDigestCalculatorProvider calculatorProvider = new JcaPGPDigestCalculatorProviderBuilder()
-				.build();
-
-		try (Stream<Path> keyFiles = Files.walk(USER_SECRET_KEY_DIR)) {
-			List<Path> allPaths = keyFiles.filter(Files::isRegularFile)
-					.collect(Collectors.toCollection(ArrayList::new));
-			if (allPaths.isEmpty()) {
-				return null;
+		byte[] keyGrip = null;
+		try {
+			keyGrip = KeyGrip.getKeyGrip(publicKey);
+		} catch (PGPException e) {
+			throw new PGPException(
+					MessageFormat.format(BCText.get().gpgNoKeygrip,
+							Hex.toHexString(publicKey.getFingerprint())),
+					e);
+		}
+		String filename = Hex.toHexString(keyGrip).toUpperCase(Locale.ROOT)
+				+ ".key"; //$NON-NLS-1$
+		Path keyFile = USER_SECRET_KEY_DIR.resolve(filename);
+		if (!Files.exists(keyFile)) {
+			return null;
+		}
+		boolean clearPrompt = false;
+		try {
+			PGPDigestCalculatorProvider calculatorProvider = new JcaPGPDigestCalculatorProviderBuilder()
+					.build();
+			clearPrompt = true;
+			PGPSecretKey secretKey = null;
+			try {
+				secretKey = attemptParseSecretKey(keyFile, calculatorProvider,
+						() -> passphrasePrompt.getPassphrase(
+								publicKey.getFingerprint(), userKeyboxPath),
+						publicKey);
+			} catch (PGPException e) {
+				throw new PGPException(MessageFormat.format(
+						BCText.get().gpgFailedToParseSecretKey,
+						keyFile.toAbsolutePath()), e);
 			}
-			PBEProtectionRemoverFactory passphraseProvider = p -> {
-				throw new EncryptedPgpKeyException();
-			};
-			for (int attempts = 0; attempts < 2; attempts++) {
-				// Second pass will traverse only the encrypted keys with a real
-				// passphrase provider.
-				Iterator<Path> pathIterator = allPaths.iterator();
-				while (pathIterator.hasNext()) {
-					Path keyFile = pathIterator.next();
-					try {
-						PGPSecretKey secretKey = attemptParseSecretKey(keyFile,
-								calculatorProvider, passphraseProvider,
-								publicKey);
-						pathIterator.remove();
-						if (secretKey != null) {
-							if (!secretKey.isSigningKey()) {
-								throw new PGPException(MessageFormat.format(
-										BCText.get().gpgNotASigningKey,
-										signingKey));
-							}
-							return new BouncyCastleGpgKey(secretKey,
-									userKeyboxPath);
-						}
-					} catch (EncryptedPgpKeyException e) {
-						// Ignore; we'll try again.
-					}
+			if (secretKey != null) {
+				if (!secretKey.isSigningKey()) {
+					throw new PGPException(MessageFormat.format(
+							BCText.get().gpgNotASigningKey, signingKey));
 				}
-				if (attempts > 0 || allPaths.isEmpty()) {
-					break;
-				}
-				// allPaths contains only the encrypted keys now.
-				passphraseProvider = new JcePBEProtectionRemoverFactory(
-						passphrasePrompt.getPassphrase(
-								publicKey.getFingerprint(), userKeyboxPath));
+				clearPrompt = false;
+				return new BouncyCastleGpgKey(secretKey, userKeyboxPath);
 			}
-
-			passphrasePrompt.clear();
 			return null;
 		} catch (RuntimeException e) {
-			passphrasePrompt.clear();
 			throw e;
+		} catch (FileNotFoundException | NoSuchFileException e) {
+			clearPrompt = false;
+			return null;
 		} catch (IOException e) {
-			passphrasePrompt.clear();
 			throw new PGPException(MessageFormat.format(
 					BCText.get().gpgFailedToParseSecretKey,
-					USER_SECRET_KEY_DIR.toAbsolutePath()), e);
+					keyFile.toAbsolutePath()), e);
+		} finally {
+			if (clearPrompt) {
+				passphrasePrompt.clear();
+			}
 		}
 	}
 
@@ -551,6 +567,11 @@ private PGPSecretKey findSecretKeyInLegacySecring(String signingkey,
 	 * Return the first public key matching the key id ({@link #signingKey}.
 	 *
 	 * @param pubringFile
+	 *            to search
+	 * @param keyId
+	 *            to look for, may be null
+	 * @param keySpec
+	 *            to look for
 	 *
 	 * @return the PGP public key, or {@code null} if none found
 	 * @throws IOException
@@ -558,14 +579,16 @@ private PGPSecretKey findSecretKeyInLegacySecring(String signingkey,
 	 * @throws PGPException
 	 *             on BouncyCastle errors
 	 */
-	private PGPPublicKey findPublicKeyInPubring(Path pubringFile)
+	private static PGPPublicKey findPublicKeyInPubring(Path pubringFile,
+			String keyId, String keySpec)
 			throws IOException, PGPException {
 		try (InputStream in = newInputStream(pubringFile)) {
 			PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(
 					new BufferedInputStream(in),
 					new JcaKeyFingerprintCalculator());
 
-			String keyId = toFingerprint(signingKey).toLowerCase(Locale.ROOT);
+			String id = keyId != null ? keyId
+					: toFingerprint(keySpec).toLowerCase(Locale.ROOT);
 			Iterator<PGPPublicKeyRing> keyrings = pgpPub.getKeyRings();
 			while (keyrings.hasNext()) {
 				PGPPublicKeyRing keyRing = keyrings.next();
@@ -575,30 +598,33 @@ private PGPPublicKey findPublicKeyInPubring(Path pubringFile)
 					// try key id
 					String fingerprint = Hex.toHexString(key.getFingerprint())
 							.toLowerCase(Locale.ROOT);
-					if (fingerprint.endsWith(keyId)) {
+					if (fingerprint.endsWith(id)) {
 						return key;
 					}
 					// try user id
 					Iterator<String> userIDs = key.getUserIDs();
 					while (userIDs.hasNext()) {
 						String userId = userIDs.next();
-						if (containsSigningKey(userId, signingKey)) {
+						if (containsSigningKey(userId, keySpec)) {
 							return key;
 						}
 					}
 				}
 			}
+		} catch (FileNotFoundException | NoSuchFileException e) {
+			// Ignore and return null
 		}
 		return null;
 	}
 
-	private PGPPublicKey getPublicKey(KeyBlob blob, byte[] fingerprint)
+	private static PGPPublicKey getPublicKey(KeyBlob blob, byte[] fingerprint)
 			throws IOException {
 		return ((PublicKeyRingBlob) blob).getPGPPublicKeyRing()
 				.getPublicKey(fingerprint);
 	}
 
-	private PGPPublicKey getSigningPublicKey(KeyBlob blob) throws IOException {
+	private static PGPPublicKey getSigningPublicKey(KeyBlob blob)
+			throws IOException {
 		PGPPublicKey masterKey = null;
 		Iterator<PGPPublicKey> keys = ((PublicKeyRingBlob) blob)
 				.getPGPPublicKeyRing().getPublicKeys();
@@ -618,7 +644,7 @@ private PGPPublicKey getSigningPublicKey(KeyBlob blob) throws IOException {
 		return masterKey;
 	}
 
-	private boolean isSigningKey(PGPPublicKey key) {
+	private static boolean isSigningKey(PGPPublicKey key) {
 		Iterator signatures = key.getSignatures();
 		while (signatures.hasNext()) {
 			PGPSignature sig = (PGPSignature) signatures.next();
@@ -630,7 +656,7 @@ private boolean isSigningKey(PGPPublicKey key) {
 		return false;
 	}
 
-	private KeyBox readKeyBoxFile(Path keyboxFile) throws IOException,
+	private static KeyBox readKeyBoxFile(Path keyboxFile) throws IOException,
 			NoSuchAlgorithmException, NoSuchProviderException,
 			NoOpenPgpKeyException {
 		if (keyboxFile.toFile().length() == 0) {
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgKeyPassphrasePrompt.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgKeyPassphrasePrompt.java
index e47f64f..6144195 100644
--- a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgKeyPassphrasePrompt.java
+++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgKeyPassphrasePrompt.java
@@ -17,8 +17,8 @@
 import org.bouncycastle.util.encoders.Hex;
 import org.eclipse.jgit.api.errors.CanceledException;
 import org.eclipse.jgit.errors.UnsupportedCredentialItem;
-import org.eclipse.jgit.transport.CredentialItem.CharArrayType;
 import org.eclipse.jgit.transport.CredentialItem.InformationalMessage;
+import org.eclipse.jgit.transport.CredentialItem.Password;
 import org.eclipse.jgit.transport.CredentialsProvider;
 import org.eclipse.jgit.transport.URIish;
 
@@ -31,7 +31,7 @@
  */
 class BouncyCastleGpgKeyPassphrasePrompt implements AutoCloseable {
 
-	private CharArrayType passphrase;
+	private Password passphrase;
 
 	private CredentialsProvider credentialsProvider;
 
@@ -78,8 +78,7 @@ private URIish createURI(Path keyLocation) throws URISyntaxException {
 			throws PGPException, CanceledException, UnsupportedCredentialItem,
 			URISyntaxException {
 		if (passphrase == null) {
-			passphrase = new CharArrayType(BCText.get().credentialPassphrase,
-					true);
+			passphrase = new Password(BCText.get().credentialPassphrase);
 		}
 
 		if (credentialsProvider == null) {
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSignatureVerifier.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSignatureVerifier.java
new file mode 100644
index 0000000..7161895
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSignatureVerifier.java
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2021, Thomas Wolf <thomas.wolf@paranor.ch> 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
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.gpg.bc.internal;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.Security;
+import java.text.MessageFormat;
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Locale;
+
+import org.bouncycastle.bcpg.sig.IssuerFingerprint;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.openpgp.PGPCompressedData;
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPPublicKey;
+import org.bouncycastle.openpgp.PGPSignature;
+import org.bouncycastle.openpgp.PGPSignatureList;
+import org.bouncycastle.openpgp.PGPSignatureSubpacketVector;
+import org.bouncycastle.openpgp.PGPUtil;
+import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory;
+import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
+import org.bouncycastle.util.encoders.Hex;
+import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.lib.GpgConfig;
+import org.eclipse.jgit.lib.GpgSignatureVerifier;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevObject;
+import org.eclipse.jgit.revwalk.RevTag;
+import org.eclipse.jgit.util.LRUMap;
+import org.eclipse.jgit.util.RawParseUtils;
+import org.eclipse.jgit.util.StringUtils;
+
+/**
+ * A {@link GpgSignatureVerifier} to verify GPG signatures using BouncyCastle.
+ */
+public class BouncyCastleGpgSignatureVerifier implements GpgSignatureVerifier {
+
+	private static void registerBouncyCastleProviderIfNecessary() {
+		if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
+			Security.addProvider(new BouncyCastleProvider());
+		}
+	}
+
+	/**
+	 * Creates a new instance and registers the BouncyCastle security provider
+	 * if needed.
+	 */
+	public BouncyCastleGpgSignatureVerifier() {
+		registerBouncyCastleProviderIfNecessary();
+	}
+
+	// To support more efficient signature verification of multiple objects we
+	// cache public keys once found in a LRU cache.
+
+	private static final Object NO_KEY = new Object();
+
+	private LRUMap<String, Object> byFingerprint = new LRUMap<>(16, 200);
+
+	private LRUMap<String, Object> bySigner = new LRUMap<>(16, 200);
+
+	@Override
+	public String getName() {
+		return "bc"; //$NON-NLS-1$
+	}
+
+	@Override
+	@Nullable
+	public SignatureVerification verifySignature(@NonNull RevObject object,
+			@NonNull GpgConfig config) throws IOException {
+		if (object instanceof RevCommit) {
+			RevCommit commit = (RevCommit) object;
+			byte[] signatureData = commit.getRawGpgSignature();
+			if (signatureData == null) {
+				return null;
+			}
+			byte[] raw = commit.getRawBuffer();
+			// Now remove the GPG signature
+			byte[] header = { 'g', 'p', 'g', 's', 'i', 'g' };
+			int start = RawParseUtils.headerStart(header, raw, 0);
+			if (start < 0) {
+				return null;
+			}
+			int end = RawParseUtils.headerEnd(raw, start);
+			// start is at the beginning of the header's content
+			start -= header.length + 1;
+			// end is on the terminating LF; we need to skip that, too
+			if (end < raw.length) {
+				end++;
+			}
+			byte[] data = new byte[raw.length - (end - start)];
+			System.arraycopy(raw, 0, data, 0, start);
+			System.arraycopy(raw, end, data, start, raw.length - end);
+			return verify(data, signatureData);
+		} else if (object instanceof RevTag) {
+			RevTag tag = (RevTag) object;
+			byte[] signatureData = tag.getRawGpgSignature();
+			if (signatureData == null) {
+				return null;
+			}
+			byte[] raw = tag.getRawBuffer();
+			// The signature is just tacked onto the end of the message, which
+			// is last in the buffer.
+			byte[] data = Arrays.copyOfRange(raw, 0,
+					raw.length - signatureData.length);
+			return verify(data, signatureData);
+		}
+		return null;
+	}
+
+	static PGPSignature parseSignature(InputStream in)
+			throws IOException, PGPException {
+		try (InputStream sigIn = PGPUtil.getDecoderStream(in)) {
+			JcaPGPObjectFactory pgpFactory = new JcaPGPObjectFactory(sigIn);
+			Object obj = pgpFactory.nextObject();
+			if (obj instanceof PGPCompressedData) {
+				obj = new JcaPGPObjectFactory(
+						((PGPCompressedData) obj).getDataStream()).nextObject();
+			}
+			if (obj instanceof PGPSignatureList) {
+				return ((PGPSignatureList) obj).get(0);
+			}
+			return null;
+		}
+	}
+
+	@Override
+	public SignatureVerification verify(byte[] data, byte[] signatureData)
+			throws IOException {
+		PGPSignature signature = null;
+		String fingerprint = null;
+		String signer = null;
+		String keyId = null;
+		try (InputStream sigIn = new ByteArrayInputStream(signatureData)) {
+			signature = parseSignature(sigIn);
+			if (signature != null) {
+				// Try to figure out something to find the public key with.
+				if (signature.hasSubpackets()) {
+					PGPSignatureSubpacketVector packets = signature
+							.getHashedSubPackets();
+					IssuerFingerprint fingerprintPacket = packets
+							.getIssuerFingerprint();
+					if (fingerprintPacket != null) {
+						fingerprint = Hex
+								.toHexString(fingerprintPacket.getFingerprint())
+								.toLowerCase(Locale.ROOT);
+					}
+					signer = packets.getSignerUserID();
+					if (signer != null) {
+						signer = BouncyCastleGpgSigner.extractSignerId(signer);
+					}
+				}
+				keyId = Long.toUnsignedString(signature.getKeyID(), 16)
+						.toLowerCase(Locale.ROOT);
+			} else {
+				throw new JGitInternalException(BCText.get().nonSignatureError);
+			}
+		} catch (PGPException e) {
+			throw new JGitInternalException(BCText.get().signatureParseError,
+					e);
+		}
+		Date signatureCreatedAt = signature.getCreationTime();
+		if (fingerprint == null && signer == null && keyId == null) {
+			return new VerificationResult(signatureCreatedAt, null, null, null,
+					false, false, TrustLevel.UNKNOWN,
+					BCText.get().signatureNoKeyInfo);
+		}
+		if (fingerprint != null && keyId != null
+				&& !fingerprint.endsWith(keyId)) {
+			return new VerificationResult(signatureCreatedAt, signer, fingerprint,
+					null, false, false, TrustLevel.UNKNOWN,
+					MessageFormat.format(BCText.get().signatureInconsistent,
+							keyId, fingerprint));
+		}
+		if (fingerprint == null && keyId != null) {
+			fingerprint = keyId;
+		}
+		// Try to find the public key
+		String keySpec = '<' + signer + '>';
+		Object cached = null;
+		PGPPublicKey publicKey = null;
+		try {
+			cached = byFingerprint.get(fingerprint);
+			if (cached != null) {
+				if (cached instanceof PGPPublicKey) {
+					publicKey = (PGPPublicKey) cached;
+				}
+			} else if (!StringUtils.isEmptyOrNull(signer)) {
+				cached = bySigner.get(signer);
+				if (cached != null) {
+					if (cached instanceof PGPPublicKey) {
+						publicKey = (PGPPublicKey) cached;
+					}
+				}
+			}
+			if (cached == null) {
+				publicKey = BouncyCastleGpgKeyLocator.findPublicKey(fingerprint,
+						keySpec);
+			}
+		} catch (IOException | PGPException e) {
+			throw new JGitInternalException(
+					BCText.get().signatureKeyLookupError, e);
+		}
+		if (publicKey == null) {
+			if (cached == null) {
+				byFingerprint.put(fingerprint, NO_KEY);
+				byFingerprint.put(keyId, NO_KEY);
+				if (signer != null) {
+					bySigner.put(signer, NO_KEY);
+				}
+			}
+			return new VerificationResult(signatureCreatedAt, signer,
+					fingerprint, null, false, false, TrustLevel.UNKNOWN,
+					BCText.get().signatureNoPublicKey);
+		}
+		if (cached == null) {
+			byFingerprint.put(fingerprint, publicKey);
+			byFingerprint.put(keyId, publicKey);
+			if (signer != null) {
+				bySigner.put(signer, publicKey);
+			}
+		}
+		String user = null;
+		Iterator<String> userIds = publicKey.getUserIDs();
+		if (!StringUtils.isEmptyOrNull(signer)) {
+			while (userIds.hasNext()) {
+				String userId = userIds.next();
+				if (BouncyCastleGpgKeyLocator.containsSigningKey(userId,
+						keySpec)) {
+					user = userId;
+					break;
+				}
+			}
+		}
+		if (user == null) {
+			userIds = publicKey.getUserIDs();
+			if (userIds.hasNext()) {
+				user = userIds.next();
+			}
+		}
+		boolean expired = false;
+		long validFor = publicKey.getValidSeconds();
+		if (validFor > 0 && signatureCreatedAt != null) {
+			Instant expiredAt = publicKey.getCreationTime().toInstant()
+					.plusSeconds(validFor);
+			expired = expiredAt.isBefore(signatureCreatedAt.toInstant());
+		}
+		// Trust data is not defined in OpenPGP; the format is implementation
+		// specific. We don't use the GPG trustdb but simply the trust packet
+		// on the public key, if present. Even if present, it may or may not
+		// be set.
+		byte[] trustData = publicKey.getTrustData();
+		TrustLevel trust = parseGpgTrustPacket(trustData);
+		boolean verified = false;
+		try {
+			signature.init(
+					new JcaPGPContentVerifierBuilderProvider()
+							.setProvider(BouncyCastleProvider.PROVIDER_NAME),
+					publicKey);
+			signature.update(data);
+			verified = signature.verify();
+		} catch (PGPException e) {
+			throw new JGitInternalException(
+					BCText.get().signatureVerificationError, e);
+		}
+		return new VerificationResult(signatureCreatedAt, signer, fingerprint, user,
+				verified, expired, trust, null);
+	}
+
+	private TrustLevel parseGpgTrustPacket(byte[] packet) {
+		if (packet == null || packet.length < 6) {
+			// A GPG trust packet has at least 6 bytes.
+			return TrustLevel.UNKNOWN;
+		}
+		if (packet[2] != 'g' || packet[3] != 'p' || packet[4] != 'g') {
+			// Not a GPG trust packet
+			return TrustLevel.UNKNOWN;
+		}
+		int trust = packet[0] & 0x0F;
+		switch (trust) {
+		case 0: // No determined/set
+		case 1: // Trust expired; i.e., calculation outdated or key expired
+		case 2: // Undefined: not enough information to set
+			return TrustLevel.UNKNOWN;
+		case 3:
+			return TrustLevel.NEVER;
+		case 4:
+			return TrustLevel.MARGINAL;
+		case 5:
+			return TrustLevel.FULL;
+		case 6:
+			return TrustLevel.ULTIMATE;
+		default:
+			return TrustLevel.UNKNOWN;
+		}
+	}
+
+	@Override
+	public void clear() {
+		byFingerprint.clear();
+		bySigner.clear();
+	}
+
+	private static class VerificationResult implements SignatureVerification {
+
+		private final Date creationDate;
+
+		private final String signer;
+
+		private final String keyUser;
+
+		private final String fingerprint;
+
+		private final boolean verified;
+
+		private final boolean expired;
+
+		private final @NonNull TrustLevel trustLevel;
+
+		private final String message;
+
+		public VerificationResult(Date creationDate, String signer,
+				String fingerprint, String user, boolean verified,
+				boolean expired, @NonNull TrustLevel trust, String message) {
+			this.creationDate = creationDate;
+			this.signer = signer;
+			this.fingerprint = fingerprint;
+			this.keyUser = user;
+			this.verified = verified;
+			this.expired = expired;
+			this.trustLevel = trust;
+			this.message = message;
+		}
+
+		@Override
+		public Date getCreationDate() {
+			return creationDate;
+		}
+
+		@Override
+		public String getSigner() {
+			return signer;
+		}
+
+		@Override
+		public String getKeyUser() {
+			return keyUser;
+		}
+
+		@Override
+		public String getKeyFingerprint() {
+			return fingerprint;
+		}
+
+		@Override
+		public boolean isExpired() {
+			return expired;
+		}
+
+		@Override
+		public TrustLevel getTrustLevel() {
+			return trustLevel;
+		}
+
+		@Override
+		public String getMessage() {
+			return message;
+		}
+
+		@Override
+		public boolean getVerified() {
+			return verified;
+		}
+	}
+}
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSignatureVerifierFactory.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSignatureVerifierFactory.java
new file mode 100644
index 0000000..ae82b75
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSignatureVerifierFactory.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2021, Thomas Wolf <thomas.wolf@paranor.ch> 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
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.gpg.bc.internal;
+
+import org.eclipse.jgit.lib.GpgSignatureVerifier;
+import org.eclipse.jgit.lib.GpgSignatureVerifierFactory;
+
+/**
+ * A {@link GpgSignatureVerifierFactory} that creates
+ * {@link GpgSignatureVerifier} instances that verify GPG signatures using
+ * BouncyCastle and that do cache public keys.
+ */
+public final class BouncyCastleGpgSignatureVerifierFactory
+		extends GpgSignatureVerifierFactory {
+
+	@Override
+	public GpgSignatureVerifier getVerifier() {
+		return new BouncyCastleGpgSignatureVerifier();
+	}
+
+}
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSigner.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSigner.java
index ea159c5..211bd7b 100644
--- a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSigner.java
+++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSigner.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018, 2020, Salesforce and others
+ * Copyright (C) 2018, 2021, Salesforce 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
@@ -34,18 +34,25 @@
 import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.api.errors.CanceledException;
 import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.api.errors.UnsupportedSigningFormatException;
 import org.eclipse.jgit.errors.UnsupportedCredentialItem;
+import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.GpgConfig;
+import org.eclipse.jgit.lib.GpgObjectSigner;
 import org.eclipse.jgit.lib.GpgSignature;
 import org.eclipse.jgit.lib.GpgSigner;
+import org.eclipse.jgit.lib.ObjectBuilder;
 import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.GpgConfig.GpgFormat;
 import org.eclipse.jgit.transport.CredentialsProvider;
 import org.eclipse.jgit.util.StringUtils;
 
 /**
- * GPG Signer using BouncyCastle library
+ * GPG Signer using the BouncyCastle library.
  */
-public class BouncyCastleGpgSigner extends GpgSigner {
+public class BouncyCastleGpgSigner extends GpgSigner
+		implements GpgObjectSigner {
 
 	private static void registerBouncyCastleProviderIfNecessary() {
 		if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
@@ -67,13 +74,32 @@ public BouncyCastleGpgSigner() {
 	public boolean canLocateSigningKey(@Nullable String gpgSigningKey,
 			PersonIdent committer, CredentialsProvider credentialsProvider)
 			throws CanceledException {
+		try {
+			return canLocateSigningKey(gpgSigningKey, committer,
+					credentialsProvider, null);
+		} catch (UnsupportedSigningFormatException e) {
+			// Cannot occur with a null config
+			return false;
+		}
+	}
+
+	@Override
+	public boolean canLocateSigningKey(@Nullable String gpgSigningKey,
+			PersonIdent committer, CredentialsProvider credentialsProvider,
+			GpgConfig config)
+			throws CanceledException, UnsupportedSigningFormatException {
+		if (config != null && config.getKeyFormat() != GpgFormat.OPENPGP) {
+			throw new UnsupportedSigningFormatException(
+					JGitText.get().onlyOpenPgpSupportedForSigning);
+		}
 		try (BouncyCastleGpgKeyPassphrasePrompt passphrasePrompt = new BouncyCastleGpgKeyPassphrasePrompt(
 				credentialsProvider)) {
 			BouncyCastleGpgKey gpgKey = locateSigningKey(gpgSigningKey,
 					committer, passphrasePrompt);
 			return gpgKey != null;
-		} catch (PGPException | IOException | NoSuchAlgorithmException
-				| NoSuchProviderException | URISyntaxException e) {
+		} catch (CanceledException e) {
+			throw e;
+		} catch (Exception e) {
 			return false;
 		}
 	}
@@ -98,10 +124,28 @@ private BouncyCastleGpgKey locateSigningKey(@Nullable String gpgSigningKey,
 	public void sign(@NonNull CommitBuilder commit,
 			@Nullable String gpgSigningKey, @NonNull PersonIdent committer,
 			CredentialsProvider credentialsProvider) throws CanceledException {
+		try {
+			signObject(commit, gpgSigningKey, committer, credentialsProvider,
+					null);
+		} catch (UnsupportedSigningFormatException e) {
+			// Cannot occur with a null config
+		}
+	}
+
+	@Override
+	public void signObject(@NonNull ObjectBuilder object,
+			@Nullable String gpgSigningKey, @NonNull PersonIdent committer,
+			CredentialsProvider credentialsProvider, GpgConfig config)
+			throws CanceledException, UnsupportedSigningFormatException {
+		if (config != null && config.getKeyFormat() != GpgFormat.OPENPGP) {
+			throw new UnsupportedSigningFormatException(
+					JGitText.get().onlyOpenPgpSupportedForSigning);
+		}
 		try (BouncyCastleGpgKeyPassphrasePrompt passphrasePrompt = new BouncyCastleGpgKeyPassphrasePrompt(
 				credentialsProvider)) {
 			BouncyCastleGpgKey gpgKey = locateSigningKey(gpgSigningKey,
-					committer, passphrasePrompt);
+					committer,
+						passphrasePrompt);
 			PGPSecretKey secretKey = gpgKey.getSecretKey();
 			if (secretKey == null) {
 				throw new JGitInternalException(
@@ -158,17 +202,17 @@ public void sign(@NonNull CommitBuilder commit,
 			ByteArrayOutputStream buffer = new ByteArrayOutputStream();
 			try (BCPGOutputStream out = new BCPGOutputStream(
 					new ArmoredOutputStream(buffer))) {
-				signatureGenerator.update(commit.build());
+				signatureGenerator.update(object.build());
 				signatureGenerator.generate().encode(out);
 			}
-			commit.setGpgSignature(new GpgSignature(buffer.toByteArray()));
+			object.setGpgSignature(new GpgSignature(buffer.toByteArray()));
 		} catch (PGPException | IOException | NoSuchAlgorithmException
 				| NoSuchProviderException | URISyntaxException e) {
 			throw new JGitInternalException(e.getMessage(), e);
 		}
 	}
 
-	private String extractSignerId(String pgpUserId) {
+	static String extractSignerId(String pgpUserId) {
 		int from = pgpUserId.indexOf('<');
 		if (from >= 0) {
 			int to = pgpUserId.indexOf('>', from + 1);
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/KeyGrip.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/KeyGrip.java
new file mode 100644
index 0000000..b1d4446
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/KeyGrip.java
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2021, Thomas Wolf <thomas.wolf@paranor.ch> 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
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.gpg.bc.internal.keys;
+
+import java.math.BigInteger;
+import java.nio.charset.StandardCharsets;
+import java.text.MessageFormat;
+import java.util.Arrays;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.cryptlib.CryptlibObjectIdentifiers;
+import org.bouncycastle.asn1.x9.ECNamedCurveTable;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.bcpg.DSAPublicBCPGKey;
+import org.bouncycastle.bcpg.ECPublicBCPGKey;
+import org.bouncycastle.bcpg.ElGamalPublicBCPGKey;
+import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
+import org.bouncycastle.bcpg.RSAPublicBCPGKey;
+import org.bouncycastle.crypto.ec.CustomNamedCurves;
+import org.bouncycastle.math.ec.ECAlgorithms;
+import org.bouncycastle.math.field.FiniteField;
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPPublicKey;
+import org.bouncycastle.util.encoders.Hex;
+import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.gpg.bc.internal.BCText;
+import org.eclipse.jgit.util.sha1.SHA1;
+
+/**
+ * Utilities to compute the <em>keygrip</em> of a key. A keygrip is a SHA1 hash
+ * over the public key parameters and is used internally by the gpg-agent to
+ * find the secret key belonging to a public key: the secret key is stored in a
+ * file under ~/.gnupg/private-keys-v1.d/ with a name "&lt;keygrip>.key". While
+ * this storage organization is an implementation detail of GPG, the way
+ * keygrips are computed is not; they are computed by libgcrypt and their
+ * definition is stable.
+ */
+public final class KeyGrip {
+
+	// Some OIDs apparently unknown to BouncyCastle.
+
+	private static String OID_OPENPGP_ED25519 = "1.3.6.1.4.1.11591.15.1"; //$NON-NLS-1$
+
+	private static String OID_RFC8410_CURVE25519 = "1.3.101.110"; //$NON-NLS-1$
+
+	private static String OID_RFC8410_ED25519 = "1.3.101.112"; //$NON-NLS-1$
+
+	private KeyGrip() {
+		// No instantiation
+	}
+
+	/**
+	 * Computes the keygrip for a {@link PGPPublicKey}.
+	 *
+	 * @param publicKey
+	 *            to get the keygrip of
+	 * @return the keygrip
+	 * @throws PGPException
+	 *             if an unknown key type is encountered.
+	 */
+	@NonNull
+	public static byte[] getKeyGrip(PGPPublicKey publicKey)
+			throws PGPException {
+		SHA1 grip = SHA1.newInstance();
+		grip.setDetectCollision(false);
+
+		switch (publicKey.getAlgorithm()) {
+		case PublicKeyAlgorithmTags.RSA_GENERAL:
+		case PublicKeyAlgorithmTags.RSA_ENCRYPT:
+		case PublicKeyAlgorithmTags.RSA_SIGN:
+			BigInteger modulus = ((RSAPublicBCPGKey) publicKey
+					.getPublicKeyPacket().getKey()).getModulus();
+			hash(grip, modulus.toByteArray());
+			break;
+		case PublicKeyAlgorithmTags.DSA:
+			DSAPublicBCPGKey dsa = (DSAPublicBCPGKey) publicKey
+					.getPublicKeyPacket().getKey();
+			hash(grip, dsa.getP().toByteArray(), 'p', true);
+			hash(grip, dsa.getQ().toByteArray(), 'q', true);
+			hash(grip, dsa.getG().toByteArray(), 'g', true);
+			hash(grip, dsa.getY().toByteArray(), 'y', true);
+			break;
+		case PublicKeyAlgorithmTags.ELGAMAL_GENERAL:
+		case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT:
+			ElGamalPublicBCPGKey eg = (ElGamalPublicBCPGKey) publicKey
+					.getPublicKeyPacket().getKey();
+			hash(grip, eg.getP().toByteArray(), 'p', true);
+			hash(grip, eg.getG().toByteArray(), 'g', true);
+			hash(grip, eg.getY().toByteArray(), 'y', true);
+			break;
+		case PublicKeyAlgorithmTags.ECDH:
+		case PublicKeyAlgorithmTags.ECDSA:
+		case PublicKeyAlgorithmTags.EDDSA:
+			ECPublicBCPGKey ec = (ECPublicBCPGKey) publicKey
+					.getPublicKeyPacket().getKey();
+			ASN1ObjectIdentifier curveOID = ec.getCurveOID();
+			// BC doesn't know these OIDs.
+			if (OID_OPENPGP_ED25519.equals(curveOID.getId())
+					|| OID_RFC8410_ED25519.equals(curveOID.getId())) {
+				return hashEd25519(grip, ec.getEncodedPoint());
+			} else if (CryptlibObjectIdentifiers.curvey25519.equals(curveOID)
+					|| OID_RFC8410_CURVE25519.equals(curveOID.getId())) {
+				// curvey25519 actually is the OpenPGP OID for Curve25519 and is
+				// known to BC, but the parameters are for the short Weierstrass
+				// form. See https://github.com/bcgit/bc-java/issues/399 .
+				// libgcrypt uses Montgomery form.
+				return hashCurve25519(grip, ec.getEncodedPoint());
+			}
+			X9ECParameters params = getX9Parameters(curveOID);
+			if (params == null) {
+				throw new PGPException(MessageFormat
+						.format(BCText.get().unknownCurve, curveOID.getId()));
+			}
+			// Need to write p, a, b, g, n, q
+			BigInteger q = ec.getEncodedPoint();
+			byte[] g = params.getG().getEncoded(false);
+			BigInteger a = params.getCurve().getA().toBigInteger();
+			BigInteger b = params.getCurve().getB().toBigInteger();
+			BigInteger n = params.getN();
+			BigInteger p = null;
+			FiniteField field = params.getCurve().getField();
+			if (ECAlgorithms.isFpField(field)) {
+				p = field.getCharacteristic();
+			}
+			if (p == null) {
+				// Don't know...
+				throw new PGPException(MessageFormat.format(
+						BCText.get().unknownCurveParameters, curveOID.getId()));
+			}
+			hash(grip, p.toByteArray(), 'p', false);
+			hash(grip, a.toByteArray(), 'a', false);
+			hash(grip, b.toByteArray(), 'b', false);
+			hash(grip, g, 'g', false);
+			hash(grip, n.toByteArray(), 'n', false);
+			if (publicKey.getAlgorithm() == PublicKeyAlgorithmTags.EDDSA) {
+				hashQ25519(grip, q);
+			} else {
+				hash(grip, q.toByteArray(), 'q', false);
+			}
+			break;
+		default:
+			throw new PGPException(
+					MessageFormat.format(BCText.get().unknownKeyType,
+							Integer.toString(publicKey.getAlgorithm())));
+		}
+		return grip.digest();
+	}
+
+	private static void hash(SHA1 grip, byte[] data) {
+		// Need to skip leading zero bytes
+		int i = 0;
+		while (i < data.length && data[i] == 0) {
+			i++;
+		}
+		int length = data.length - i;
+		if (i < data.length) {
+			if ((data[i] & 0x80) != 0) {
+				grip.update((byte) 0);
+			}
+			grip.update(data, i, length);
+		}
+	}
+
+	private static void hash(SHA1 grip, byte[] data, char id, boolean zeroPad) {
+		// Need to skip leading zero bytes
+		int i = 0;
+		while (i < data.length && data[i] == 0) {
+			i++;
+		}
+		int length = data.length - i;
+		boolean addZero = false;
+		if (i < data.length && zeroPad && (data[i] & 0x80) != 0) {
+			addZero = true;
+		}
+		// libgcrypt includes an SExp in the hash
+		String prefix = "(1:" + id + (addZero ? length + 1 : length) + ':'; //$NON-NLS-1$
+		grip.update(prefix.getBytes(StandardCharsets.US_ASCII));
+		// For some items, gcrypt prepends a zero byte if the high bit is set
+		if (addZero) {
+			grip.update((byte) 0);
+		}
+		if (i < data.length) {
+			grip.update(data, i, length);
+		}
+		grip.update((byte) ')');
+	}
+
+	private static void hashQ25519(SHA1 grip, BigInteger q)
+			throws PGPException {
+		byte[] data = q.toByteArray();
+		switch (data[0]) {
+		case 0x04:
+			if (data.length != 65) {
+				throw new PGPException(MessageFormat.format(
+						BCText.get().corrupt25519Key, Hex.toHexString(data)));
+			}
+			// Uncompressed: should not occur with ed25519 or curve25519
+			throw new PGPException(MessageFormat.format(
+					BCText.get().uncompressed25519Key, Hex.toHexString(data)));
+		case 0x40:
+			if (data.length != 33) {
+				throw new PGPException(MessageFormat.format(
+						BCText.get().corrupt25519Key, Hex.toHexString(data)));
+			}
+			// Compressed; normal case. Skip prefix.
+			hash(grip, Arrays.copyOfRange(data, 1, data.length), 'q', false);
+			break;
+		default:
+			if (data.length != 32) {
+				throw new PGPException(MessageFormat.format(
+						BCText.get().corrupt25519Key, Hex.toHexString(data)));
+			}
+			// Compressed format without prefix. Should not occur?
+			hash(grip, data, 'q', false);
+			break;
+		}
+	}
+
+	/**
+	 * Computes the keygrip for an ed25519 public key.
+	 * <p>
+	 * Package-visible for tests only.
+	 * </p>
+	 *
+	 * @param grip
+	 *            initialized {@link SHA1}
+	 * @param q
+	 *            the public key's EC point
+	 * @return the keygrip
+	 * @throws PGPException
+	 *             if q indicates uncompressed format
+	 */
+	@SuppressWarnings("nls")
+	static byte[] hashEd25519(SHA1 grip, BigInteger q) throws PGPException {
+		// For the values, see RFC 7748: https://tools.ietf.org/html/rfc7748
+		// p = 2^255 - 19
+		hash(grip, Hex.decodeStrict(
+				"7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED"),
+				'p', false);
+		// Field: a = 1
+		hash(grip, new byte[] { 0x01 }, 'a', false);
+		// Field: b = 121665/121666 (mod p)
+		// See Berstein et.al., "Twisted Edwards Curves",
+		// https://doi.org/10.1007/978-3-540-68164-9_26
+		hash(grip, Hex.decodeStrict(
+				"2DFC9311D490018C7338BF8688861767FF8FF5B2BEBE27548A14B235ECA6874A"),
+				'b', false);
+		// Generator point with affine X,Y
+		// @formatter:off
+		// X(P) = 15112221349535400772501151409588531511454012693041857206046113283949847762202
+		// Y(P) = 46316835694926478169428394003475163141307993866256225615783033603165251855960
+		// the "04" signifies uncompressed format.
+		// @formatter:on
+		hash(grip, Hex.decodeStrict("04"
+				+ "216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A"
+				+ "6666666666666666666666666666666666666666666666666666666666666658"),
+				'g', false);
+		// order = 2^252 + 0x14def9dea2f79cd65812631a5cf5d3ed
+		hash(grip, Hex.decodeStrict(
+				"1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED"),
+				'n', false);
+		hashQ25519(grip, q);
+		return grip.digest();
+	}
+
+	/**
+	 * Computes the keygrip for a curve25519 public key.
+	 * <p>
+	 * Package-visible for tests only.
+	 * </p>
+	 *
+	 * @param grip
+	 *            initialized {@link SHA1}
+	 * @param q
+	 *            the public key's EC point
+	 * @return the keygrip
+	 * @throws PGPException
+	 *             if q indicates uncompressed format
+	 */
+	@SuppressWarnings("nls")
+	static byte[] hashCurve25519(SHA1 grip, BigInteger q) throws PGPException {
+		hash(grip, Hex.decodeStrict(
+				"7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED"),
+				'p', false);
+		// Unclear: RFC 7748 says A = 486662. This value here is (A-2)/4 =
+		// 121665. Compare ecc-curves.c in libgcrypt:
+		// https://github.com/gpg/libgcrypt/blob/361a058/cipher/ecc-curves.c#L146
+		hash(grip, new byte[] { 0x01, (byte) 0xDB, 0x41 }, 'a', false);
+		hash(grip, new byte[] { 0x01 }, 'b', false);
+		// libgcrypt uses the old g.y value before the erratum to RFC 7748 for
+		// the keygrip. The new value would be
+		// 5F51E65E475F794B1FE122D388B72EB36DC2B28192839E4DD6163A5D81312C14. See
+		// https://www.rfc-editor.org/errata/eid4730 and
+		// https://github.com/gpg/libgcrypt/commit/f67b6492e0b0
+		hash(grip, Hex.decodeStrict("04"
+				+ "0000000000000000000000000000000000000000000000000000000000000009"
+				+ "20AE19A1B8A086B4E01EDD2C7748D14C923D4D7E6D7C61B229E9C5A27ECED3D9"),
+				'g', false);
+		hash(grip, Hex.decodeStrict(
+				"1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED"),
+				'n', false);
+		hashQ25519(grip, q);
+		return grip.digest();
+	}
+
+	private static X9ECParameters getX9Parameters(
+			ASN1ObjectIdentifier curveOID) {
+		X9ECParameters params = CustomNamedCurves.getByOID(curveOID);
+		if (params == null) {
+			params = ECNamedCurveTable.getByOID(curveOID);
+		}
+		return params;
+	}
+
+}
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/OCBPBEProtectionRemoverFactory.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/OCBPBEProtectionRemoverFactory.java
new file mode 100644
index 0000000..68f8a45
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/OCBPBEProtectionRemoverFactory.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2021 Thomas Wolf <thomas.wolf@paranor.ch> 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
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.gpg.bc.internal.keys;
+
+import java.security.NoSuchAlgorithmException;
+import java.text.MessageFormat;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPUtil;
+import org.bouncycastle.openpgp.operator.PBEProtectionRemoverFactory;
+import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
+import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider;
+import org.bouncycastle.util.Arrays;
+import org.eclipse.jgit.gpg.bc.internal.BCText;
+
+/**
+ * A {@link PBEProtectionRemoverFactory} using AES/OCB/NoPadding for decryption.
+ * It accepts an AAD in the factory's constructor, so the factory can be used to
+ * create a {@link PBESecretKeyDecryptor} only for a particular input.
+ * <p>
+ * For JGit's needs, this is sufficient, but for a general upstream
+ * implementation that limitation might not be acceptable.
+ * </p>
+ */
+class OCBPBEProtectionRemoverFactory
+		implements PBEProtectionRemoverFactory {
+
+	private final PGPDigestCalculatorProvider calculatorProvider;
+
+	private final char[] passphrase;
+
+	private final byte[] aad;
+
+	/**
+	 * Creates a new factory instance with the given parameters.
+	 * <p>
+	 * Because the AAD is given at factory level, the {@link PBESecretKeyDecryptor}s
+	 * created by the factory can be used to decrypt only a particular input
+	 * matching this AAD.
+	 * </p>
+	 *
+	 * @param passphrase         to use for secret key derivation
+	 * @param calculatorProvider for computing digests
+	 * @param aad                for the OCB decryption
+	 */
+	OCBPBEProtectionRemoverFactory(char[] passphrase,
+			PGPDigestCalculatorProvider calculatorProvider, byte[] aad) {
+		this.calculatorProvider = calculatorProvider;
+		this.passphrase = passphrase;
+		this.aad = aad;
+	}
+
+	@Override
+	public PBESecretKeyDecryptor createDecryptor(String protection)
+			throws PGPException {
+		return new PBESecretKeyDecryptor(passphrase, calculatorProvider) {
+
+			@Override
+			public byte[] recoverKeyData(int encAlgorithm, byte[] key,
+					byte[] iv, byte[] encrypted, int encryptedOffset,
+					int encryptedLength) throws PGPException {
+				String algorithmName = PGPUtil
+						.getSymmetricCipherName(encAlgorithm);
+				byte[] decrypted = null;
+				try {
+					Cipher c = Cipher
+							.getInstance(algorithmName + "/OCB/NoPadding"); //$NON-NLS-1$
+					SecretKey secretKey = new SecretKeySpec(key, algorithmName);
+					c.init(Cipher.DECRYPT_MODE, secretKey,
+							new IvParameterSpec(iv));
+					c.updateAAD(aad);
+					decrypted = new byte[c.getOutputSize(encryptedLength)];
+					int decryptedLength = c.update(encrypted, encryptedOffset,
+							encryptedLength, decrypted);
+					// doFinal() for OCB will check the MAC and throw an
+					// exception if it doesn't match
+					decryptedLength += c.doFinal(decrypted, decryptedLength);
+					if (decryptedLength != decrypted.length) {
+						throw new PGPException(MessageFormat.format(
+								BCText.get().cryptWrongDecryptedLength,
+								Integer.valueOf(decryptedLength),
+								Integer.valueOf(decrypted.length)));
+					}
+					byte[] result = decrypted;
+					decrypted = null; // Don't clear in finally
+					return result;
+				} catch (NoClassDefFoundError e) {
+					String msg = MessageFormat.format(
+							BCText.get().gpgNoSuchAlgorithm,
+							algorithmName + "/OCB"); //$NON-NLS-1$
+					throw new PGPException(msg,
+							new NoSuchAlgorithmException(msg, e));
+				} catch (PGPException e) {
+					throw e;
+				} catch (Exception e) {
+					throw new PGPException(
+							MessageFormat.format(BCText.get().cryptCipherError,
+									e.getLocalizedMessage()),
+							e);
+				} finally {
+					if (decrypted != null) {
+						// Prevent halfway decrypted data leaking.
+						Arrays.fill(decrypted, (byte) 0);
+					}
+				}
+			}
+		};
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SExprParser.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SExprParser.java
new file mode 100644
index 0000000..a9bb22c
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SExprParser.java
@@ -0,0 +1,826 @@
+/*
+ * Copyright (c) 2000-2021 The Legion of the Bouncy Castle Inc. (https://www.bouncycastle.org)
+ * <p>
+ * 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:
+ * </p>
+ * <p>
+ * The above copyright notice and this permission notice shall be included in all copies or substantial
+ * portions of the Software.
+ * </p>
+ * <p>
+ * 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.
+ * </p>
+ */
+package org.eclipse.jgit.gpg.bc.internal.keys;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.util.Date;
+
+import org.bouncycastle.asn1.x9.ECNamedCurveTable;
+import org.bouncycastle.bcpg.DSAPublicBCPGKey;
+import org.bouncycastle.bcpg.DSASecretBCPGKey;
+import org.bouncycastle.bcpg.ECDSAPublicBCPGKey;
+import org.bouncycastle.bcpg.ECPublicBCPGKey;
+import org.bouncycastle.bcpg.ECSecretBCPGKey;
+import org.bouncycastle.bcpg.ElGamalPublicBCPGKey;
+import org.bouncycastle.bcpg.ElGamalSecretBCPGKey;
+import org.bouncycastle.bcpg.HashAlgorithmTags;
+import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
+import org.bouncycastle.bcpg.PublicKeyPacket;
+import org.bouncycastle.bcpg.RSAPublicBCPGKey;
+import org.bouncycastle.bcpg.RSASecretBCPGKey;
+import org.bouncycastle.bcpg.S2K;
+import org.bouncycastle.bcpg.SecretKeyPacket;
+import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPPublicKey;
+import org.bouncycastle.openpgp.PGPSecretKey;
+import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator;
+import org.bouncycastle.openpgp.operator.PBEProtectionRemoverFactory;
+import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
+import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
+import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+
+/**
+ * A parser for secret keys stored in s-expressions. Original BouncyCastle code
+ * modified by the JGit team to:
+ * <ul>
+ * <li>handle unencrypted DSA, EC, and ElGamal keys (upstream only handles
+ * unencrypted RSA), and</li>
+ * <li>handle secret keys using AES/OCB as encryption (those don't have a
+ * hash).</li>
+ * </ul>
+ */
+@SuppressWarnings("nls")
+public class SExprParser {
+	private final PGPDigestCalculatorProvider digestProvider;
+
+	/**
+	 * Base constructor.
+	 *
+	 * @param digestProvider
+	 *            a provider for digest calculations. Used to confirm key
+	 *            protection hashes.
+	 */
+	public SExprParser(PGPDigestCalculatorProvider digestProvider) {
+		this.digestProvider = digestProvider;
+	}
+
+	/**
+	 * Parse a secret key from one of the GPG S expression keys associating it
+	 * with the passed in public key.
+	 *
+	 * @param inputStream
+	 *            to read from
+	 * @param keyProtectionRemoverFactory
+	 *            for decrypting encrypted keys
+	 * @param pubKey
+	 *            the private key should belong to
+	 *
+	 * @return a secret key object.
+	 * @throws IOException
+	 * @throws PGPException
+	 */
+	public PGPSecretKey parseSecretKey(InputStream inputStream,
+			PBEProtectionRemoverFactory keyProtectionRemoverFactory,
+			PGPPublicKey pubKey) throws IOException, PGPException {
+		SXprUtils.skipOpenParenthesis(inputStream);
+
+		String type;
+
+		type = SXprUtils.readString(inputStream, inputStream.read());
+		if (type.equals("protected-private-key")
+				|| type.equals("private-key")) {
+			SXprUtils.skipOpenParenthesis(inputStream);
+
+			String keyType = SXprUtils.readString(inputStream,
+					inputStream.read());
+			if (keyType.equals("ecc")) {
+				SXprUtils.skipOpenParenthesis(inputStream);
+
+				String curveID = SXprUtils.readString(inputStream,
+						inputStream.read());
+				String curveName = SXprUtils.readString(inputStream,
+						inputStream.read());
+
+				SXprUtils.skipCloseParenthesis(inputStream);
+
+				byte[] qVal;
+
+				SXprUtils.skipOpenParenthesis(inputStream);
+
+				type = SXprUtils.readString(inputStream, inputStream.read());
+				if (type.equals("q")) {
+					qVal = SXprUtils.readBytes(inputStream, inputStream.read());
+				} else {
+					throw new PGPException("no q value found");
+				}
+
+				SXprUtils.skipCloseParenthesis(inputStream);
+
+				BigInteger d = processECSecretKey(inputStream, curveID,
+						curveName, qVal, keyProtectionRemoverFactory);
+
+				if (curveName.startsWith("NIST ")) {
+					curveName = curveName.substring("NIST ".length());
+				}
+
+				ECPublicBCPGKey basePubKey = new ECDSAPublicBCPGKey(
+						ECNamedCurveTable.getOID(curveName),
+						new BigInteger(1, qVal));
+				ECPublicBCPGKey assocPubKey = (ECPublicBCPGKey) pubKey
+						.getPublicKeyPacket().getKey();
+				if (!basePubKey.getCurveOID().equals(assocPubKey.getCurveOID())
+						|| !basePubKey.getEncodedPoint()
+								.equals(assocPubKey.getEncodedPoint())) {
+					throw new PGPException(
+							"passed in public key does not match secret key");
+				}
+
+				return new PGPSecretKey(
+						new SecretKeyPacket(pubKey.getPublicKeyPacket(),
+								SymmetricKeyAlgorithmTags.NULL, null, null,
+								new ECSecretBCPGKey(d).getEncoded()),
+						pubKey);
+			} else if (keyType.equals("dsa")) {
+				BigInteger p = readBigInteger("p", inputStream);
+				BigInteger q = readBigInteger("q", inputStream);
+				BigInteger g = readBigInteger("g", inputStream);
+
+				BigInteger y = readBigInteger("y", inputStream);
+
+				BigInteger x = processDSASecretKey(inputStream, p, q, g, y,
+						keyProtectionRemoverFactory);
+
+				DSAPublicBCPGKey basePubKey = new DSAPublicBCPGKey(p, q, g, y);
+				DSAPublicBCPGKey assocPubKey = (DSAPublicBCPGKey) pubKey
+						.getPublicKeyPacket().getKey();
+				if (!basePubKey.getP().equals(assocPubKey.getP())
+						|| !basePubKey.getQ().equals(assocPubKey.getQ())
+						|| !basePubKey.getG().equals(assocPubKey.getG())
+						|| !basePubKey.getY().equals(assocPubKey.getY())) {
+					throw new PGPException(
+							"passed in public key does not match secret key");
+				}
+				return new PGPSecretKey(
+						new SecretKeyPacket(pubKey.getPublicKeyPacket(),
+								SymmetricKeyAlgorithmTags.NULL, null, null,
+								new DSASecretBCPGKey(x).getEncoded()),
+						pubKey);
+			} else if (keyType.equals("elg")) {
+				BigInteger p = readBigInteger("p", inputStream);
+				BigInteger g = readBigInteger("g", inputStream);
+
+				BigInteger y = readBigInteger("y", inputStream);
+
+				BigInteger x = processElGamalSecretKey(inputStream, p, g, y,
+						keyProtectionRemoverFactory);
+
+				ElGamalPublicBCPGKey basePubKey = new ElGamalPublicBCPGKey(p, g,
+						y);
+				ElGamalPublicBCPGKey assocPubKey = (ElGamalPublicBCPGKey) pubKey
+						.getPublicKeyPacket().getKey();
+				if (!basePubKey.getP().equals(assocPubKey.getP())
+						|| !basePubKey.getG().equals(assocPubKey.getG())
+						|| !basePubKey.getY().equals(assocPubKey.getY())) {
+					throw new PGPException(
+							"passed in public key does not match secret key");
+				}
+
+				return new PGPSecretKey(
+						new SecretKeyPacket(pubKey.getPublicKeyPacket(),
+								SymmetricKeyAlgorithmTags.NULL, null, null,
+								new ElGamalSecretBCPGKey(x).getEncoded()),
+						pubKey);
+			} else if (keyType.equals("rsa")) {
+				BigInteger n = readBigInteger("n", inputStream);
+				BigInteger e = readBigInteger("e", inputStream);
+
+				BigInteger[] values = processRSASecretKey(inputStream, n, e,
+						keyProtectionRemoverFactory);
+
+				// TODO: type of RSA key?
+				RSAPublicBCPGKey basePubKey = new RSAPublicBCPGKey(n, e);
+				RSAPublicBCPGKey assocPubKey = (RSAPublicBCPGKey) pubKey
+						.getPublicKeyPacket().getKey();
+				if (!basePubKey.getModulus().equals(assocPubKey.getModulus())
+						|| !basePubKey.getPublicExponent()
+								.equals(assocPubKey.getPublicExponent())) {
+					throw new PGPException(
+							"passed in public key does not match secret key");
+				}
+
+				return new PGPSecretKey(new SecretKeyPacket(
+						pubKey.getPublicKeyPacket(),
+						SymmetricKeyAlgorithmTags.NULL, null, null,
+						new RSASecretBCPGKey(values[0], values[1], values[2])
+								.getEncoded()),
+						pubKey);
+			} else {
+				throw new PGPException("unknown key type: " + keyType);
+			}
+		}
+
+		throw new PGPException("unknown key type found");
+	}
+
+	/**
+	 * Parse a secret key from one of the GPG S expression keys.
+	 *
+	 * @param inputStream
+	 *            to read from
+	 * @param keyProtectionRemoverFactory
+	 *            for decrypting encrypted keys
+	 * @param fingerPrintCalculator
+	 *            for calculating key fingerprints
+	 *
+	 * @return a secret key object.
+	 * @throws IOException
+	 * @throws PGPException
+	 */
+	public PGPSecretKey parseSecretKey(InputStream inputStream,
+			PBEProtectionRemoverFactory keyProtectionRemoverFactory,
+			KeyFingerPrintCalculator fingerPrintCalculator)
+			throws IOException, PGPException {
+		SXprUtils.skipOpenParenthesis(inputStream);
+
+		String type;
+
+		type = SXprUtils.readString(inputStream, inputStream.read());
+		if (type.equals("protected-private-key")
+				|| type.equals("private-key")) {
+			SXprUtils.skipOpenParenthesis(inputStream);
+
+			String keyType = SXprUtils.readString(inputStream,
+					inputStream.read());
+			if (keyType.equals("ecc")) {
+				SXprUtils.skipOpenParenthesis(inputStream);
+
+				String curveID = SXprUtils.readString(inputStream,
+						inputStream.read());
+				String curveName = SXprUtils.readString(inputStream,
+						inputStream.read());
+
+				if (curveName.startsWith("NIST ")) {
+					curveName = curveName.substring("NIST ".length());
+				}
+
+				SXprUtils.skipCloseParenthesis(inputStream);
+
+				byte[] qVal;
+
+				SXprUtils.skipOpenParenthesis(inputStream);
+
+				type = SXprUtils.readString(inputStream, inputStream.read());
+				if (type.equals("q")) {
+					qVal = SXprUtils.readBytes(inputStream, inputStream.read());
+				} else {
+					throw new PGPException("no q value found");
+				}
+
+				PublicKeyPacket pubPacket = new PublicKeyPacket(
+						PublicKeyAlgorithmTags.ECDSA, new Date(),
+						new ECDSAPublicBCPGKey(
+								ECNamedCurveTable.getOID(curveName),
+								new BigInteger(1, qVal)));
+
+				SXprUtils.skipCloseParenthesis(inputStream);
+
+				BigInteger d = processECSecretKey(inputStream, curveID,
+						curveName, qVal, keyProtectionRemoverFactory);
+
+				return new PGPSecretKey(
+						new SecretKeyPacket(pubPacket,
+								SymmetricKeyAlgorithmTags.NULL, null, null,
+								new ECSecretBCPGKey(d).getEncoded()),
+						new PGPPublicKey(pubPacket, fingerPrintCalculator));
+			} else if (keyType.equals("dsa")) {
+				BigInteger p = readBigInteger("p", inputStream);
+				BigInteger q = readBigInteger("q", inputStream);
+				BigInteger g = readBigInteger("g", inputStream);
+
+				BigInteger y = readBigInteger("y", inputStream);
+
+				BigInteger x = processDSASecretKey(inputStream, p, q, g, y,
+						keyProtectionRemoverFactory);
+
+				PublicKeyPacket pubPacket = new PublicKeyPacket(
+						PublicKeyAlgorithmTags.DSA, new Date(),
+						new DSAPublicBCPGKey(p, q, g, y));
+
+				return new PGPSecretKey(
+						new SecretKeyPacket(pubPacket,
+								SymmetricKeyAlgorithmTags.NULL, null, null,
+								new DSASecretBCPGKey(x).getEncoded()),
+						new PGPPublicKey(pubPacket, fingerPrintCalculator));
+			} else if (keyType.equals("elg")) {
+				BigInteger p = readBigInteger("p", inputStream);
+				BigInteger g = readBigInteger("g", inputStream);
+
+				BigInteger y = readBigInteger("y", inputStream);
+
+				BigInteger x = processElGamalSecretKey(inputStream, p, g, y,
+						keyProtectionRemoverFactory);
+
+				PublicKeyPacket pubPacket = new PublicKeyPacket(
+						PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT, new Date(),
+						new ElGamalPublicBCPGKey(p, g, y));
+
+				return new PGPSecretKey(
+						new SecretKeyPacket(pubPacket,
+								SymmetricKeyAlgorithmTags.NULL, null, null,
+								new ElGamalSecretBCPGKey(x).getEncoded()),
+						new PGPPublicKey(pubPacket, fingerPrintCalculator));
+			} else if (keyType.equals("rsa")) {
+				BigInteger n = readBigInteger("n", inputStream);
+				BigInteger e = readBigInteger("e", inputStream);
+
+				BigInteger[] values = processRSASecretKey(inputStream, n, e,
+						keyProtectionRemoverFactory);
+
+				// TODO: type of RSA key?
+				PublicKeyPacket pubPacket = new PublicKeyPacket(
+						PublicKeyAlgorithmTags.RSA_GENERAL, new Date(),
+						new RSAPublicBCPGKey(n, e));
+
+				return new PGPSecretKey(
+						new SecretKeyPacket(pubPacket,
+								SymmetricKeyAlgorithmTags.NULL, null, null,
+								new RSASecretBCPGKey(values[0], values[1],
+										values[2]).getEncoded()),
+						new PGPPublicKey(pubPacket, fingerPrintCalculator));
+			} else {
+				throw new PGPException("unknown key type: " + keyType);
+			}
+		}
+
+		throw new PGPException("unknown key type found");
+	}
+
+	private BigInteger readBigInteger(String expectedType,
+			InputStream inputStream) throws IOException, PGPException {
+		SXprUtils.skipOpenParenthesis(inputStream);
+
+		String type = SXprUtils.readString(inputStream, inputStream.read());
+		if (!type.equals(expectedType)) {
+			throw new PGPException(expectedType + " value expected");
+		}
+
+		byte[] nBytes = SXprUtils.readBytes(inputStream, inputStream.read());
+		BigInteger v = new BigInteger(1, nBytes);
+
+		SXprUtils.skipCloseParenthesis(inputStream);
+
+		return v;
+	}
+
+	private static byte[][] extractData(InputStream inputStream,
+			PBEProtectionRemoverFactory keyProtectionRemoverFactory)
+			throws PGPException, IOException {
+		byte[] data;
+		byte[] protectedAt = null;
+
+		SXprUtils.skipOpenParenthesis(inputStream);
+
+		String type = SXprUtils.readString(inputStream, inputStream.read());
+		if (type.equals("protected")) {
+			String protection = SXprUtils.readString(inputStream,
+					inputStream.read());
+
+			SXprUtils.skipOpenParenthesis(inputStream);
+
+			S2K s2k = SXprUtils.parseS2K(inputStream);
+
+			byte[] iv = SXprUtils.readBytes(inputStream, inputStream.read());
+
+			SXprUtils.skipCloseParenthesis(inputStream);
+
+			byte[] secKeyData = SXprUtils.readBytes(inputStream,
+					inputStream.read());
+
+			SXprUtils.skipCloseParenthesis(inputStream);
+
+			PBESecretKeyDecryptor keyDecryptor = keyProtectionRemoverFactory
+					.createDecryptor(protection);
+
+			// TODO: recognise other algorithms
+			byte[] key = keyDecryptor.makeKeyFromPassPhrase(
+					SymmetricKeyAlgorithmTags.AES_128, s2k);
+
+			data = keyDecryptor.recoverKeyData(
+					SymmetricKeyAlgorithmTags.AES_128, key, iv, secKeyData, 0,
+					secKeyData.length);
+
+			// check if protected at is present
+			if (inputStream.read() == '(') {
+				ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+				bOut.write('(');
+				int ch;
+				while ((ch = inputStream.read()) >= 0 && ch != ')') {
+					bOut.write(ch);
+				}
+
+				if (ch != ')') {
+					throw new IOException("unexpected end to SExpr");
+				}
+
+				bOut.write(')');
+
+				protectedAt = bOut.toByteArray();
+			}
+
+			SXprUtils.skipCloseParenthesis(inputStream);
+			SXprUtils.skipCloseParenthesis(inputStream);
+		} else if (type.equals("d") || type.equals("x")) {
+			// JGit modification: unencrypted DSA or ECC keys can have an "x"
+			// here
+			return null;
+		} else {
+			throw new PGPException("protected block not found");
+		}
+
+		return new byte[][] { data, protectedAt };
+	}
+
+	private BigInteger processDSASecretKey(InputStream inputStream,
+			BigInteger p, BigInteger q, BigInteger g, BigInteger y,
+			PBEProtectionRemoverFactory keyProtectionRemoverFactory)
+			throws IOException, PGPException {
+		String type;
+		byte[][] basicData = extractData(inputStream,
+				keyProtectionRemoverFactory);
+
+		// JGit modification: handle unencrypted DSA keys
+		if (basicData == null) {
+			byte[] nBytes = SXprUtils.readBytes(inputStream,
+					inputStream.read());
+			BigInteger x = new BigInteger(1, nBytes);
+			SXprUtils.skipCloseParenthesis(inputStream);
+			return x;
+		}
+
+		byte[] keyData = basicData[0];
+		byte[] protectedAt = basicData[1];
+
+		//
+		// parse the secret key S-expr
+		//
+		InputStream keyIn = new ByteArrayInputStream(keyData);
+
+		SXprUtils.skipOpenParenthesis(keyIn);
+		SXprUtils.skipOpenParenthesis(keyIn);
+
+		BigInteger x = readBigInteger("x", keyIn);
+
+		SXprUtils.skipCloseParenthesis(keyIn);
+
+		// JGit modification: OCB-encrypted keys don't have and don't need a
+		// hash
+		if (keyProtectionRemoverFactory instanceof OCBPBEProtectionRemoverFactory) {
+			return x;
+		}
+
+		SXprUtils.skipOpenParenthesis(keyIn);
+		type = SXprUtils.readString(keyIn, keyIn.read());
+
+		if (!type.equals("hash")) {
+			throw new PGPException("hash keyword expected");
+		}
+		type = SXprUtils.readString(keyIn, keyIn.read());
+
+		if (!type.equals("sha1")) {
+			throw new PGPException("hash keyword expected");
+		}
+
+		byte[] hashBytes = SXprUtils.readBytes(keyIn, keyIn.read());
+
+		SXprUtils.skipCloseParenthesis(keyIn);
+
+		if (digestProvider != null) {
+			PGPDigestCalculator digestCalculator = digestProvider
+					.get(HashAlgorithmTags.SHA1);
+
+			OutputStream dOut = digestCalculator.getOutputStream();
+
+			dOut.write(Strings.toByteArray("(3:dsa"));
+			writeCanonical(dOut, "p", p);
+			writeCanonical(dOut, "q", q);
+			writeCanonical(dOut, "g", g);
+			writeCanonical(dOut, "y", y);
+			writeCanonical(dOut, "x", x);
+
+			// check protected-at
+			if (protectedAt != null) {
+				dOut.write(protectedAt);
+			}
+
+			dOut.write(Strings.toByteArray(")"));
+
+			byte[] check = digestCalculator.getDigest();
+			if (!Arrays.constantTimeAreEqual(check, hashBytes)) {
+				throw new PGPException(
+						"checksum on protected data failed in SExpr");
+			}
+		}
+
+		return x;
+	}
+
+	private BigInteger processElGamalSecretKey(InputStream inputStream,
+			BigInteger p, BigInteger g, BigInteger y,
+			PBEProtectionRemoverFactory keyProtectionRemoverFactory)
+			throws IOException, PGPException {
+		String type;
+		byte[][] basicData = extractData(inputStream,
+				keyProtectionRemoverFactory);
+
+		// JGit modification: handle unencrypted EC keys
+		if (basicData == null) {
+			byte[] nBytes = SXprUtils.readBytes(inputStream,
+					inputStream.read());
+			BigInteger x = new BigInteger(1, nBytes);
+			SXprUtils.skipCloseParenthesis(inputStream);
+			return x;
+		}
+
+		byte[] keyData = basicData[0];
+		byte[] protectedAt = basicData[1];
+
+		//
+		// parse the secret key S-expr
+		//
+		InputStream keyIn = new ByteArrayInputStream(keyData);
+
+		SXprUtils.skipOpenParenthesis(keyIn);
+		SXprUtils.skipOpenParenthesis(keyIn);
+
+		BigInteger x = readBigInteger("x", keyIn);
+
+		SXprUtils.skipCloseParenthesis(keyIn);
+
+		// JGit modification: OCB-encrypted keys don't have and don't need a
+		// hash
+		if (keyProtectionRemoverFactory instanceof OCBPBEProtectionRemoverFactory) {
+			return x;
+		}
+
+		SXprUtils.skipOpenParenthesis(keyIn);
+		type = SXprUtils.readString(keyIn, keyIn.read());
+
+		if (!type.equals("hash")) {
+			throw new PGPException("hash keyword expected");
+		}
+		type = SXprUtils.readString(keyIn, keyIn.read());
+
+		if (!type.equals("sha1")) {
+			throw new PGPException("hash keyword expected");
+		}
+
+		byte[] hashBytes = SXprUtils.readBytes(keyIn, keyIn.read());
+
+		SXprUtils.skipCloseParenthesis(keyIn);
+
+		if (digestProvider != null) {
+			PGPDigestCalculator digestCalculator = digestProvider
+					.get(HashAlgorithmTags.SHA1);
+
+			OutputStream dOut = digestCalculator.getOutputStream();
+
+			dOut.write(Strings.toByteArray("(3:elg"));
+			writeCanonical(dOut, "p", p);
+			writeCanonical(dOut, "g", g);
+			writeCanonical(dOut, "y", y);
+			writeCanonical(dOut, "x", x);
+
+			// check protected-at
+			if (protectedAt != null) {
+				dOut.write(protectedAt);
+			}
+
+			dOut.write(Strings.toByteArray(")"));
+
+			byte[] check = digestCalculator.getDigest();
+			if (!Arrays.constantTimeAreEqual(check, hashBytes)) {
+				throw new PGPException(
+						"checksum on protected data failed in SExpr");
+			}
+		}
+
+		return x;
+	}
+
+	private BigInteger processECSecretKey(InputStream inputStream,
+			String curveID, String curveName, byte[] qVal,
+			PBEProtectionRemoverFactory keyProtectionRemoverFactory)
+			throws IOException, PGPException {
+		String type;
+
+		byte[][] basicData = extractData(inputStream,
+				keyProtectionRemoverFactory);
+
+		// JGit modification: handle unencrypted EC keys
+		if (basicData == null) {
+			byte[] nBytes = SXprUtils.readBytes(inputStream,
+					inputStream.read());
+			BigInteger d = new BigInteger(1, nBytes);
+			SXprUtils.skipCloseParenthesis(inputStream);
+			return d;
+		}
+
+		byte[] keyData = basicData[0];
+		byte[] protectedAt = basicData[1];
+
+		//
+		// parse the secret key S-expr
+		//
+		InputStream keyIn = new ByteArrayInputStream(keyData);
+
+		SXprUtils.skipOpenParenthesis(keyIn);
+		SXprUtils.skipOpenParenthesis(keyIn);
+		BigInteger d = readBigInteger("d", keyIn);
+		SXprUtils.skipCloseParenthesis(keyIn);
+
+		// JGit modification: OCB-encrypted keys don't have and don't need a
+		// hash
+		if (keyProtectionRemoverFactory instanceof OCBPBEProtectionRemoverFactory) {
+			return d;
+		}
+
+		SXprUtils.skipOpenParenthesis(keyIn);
+
+		type = SXprUtils.readString(keyIn, keyIn.read());
+
+		if (!type.equals("hash")) {
+			throw new PGPException("hash keyword expected");
+		}
+		type = SXprUtils.readString(keyIn, keyIn.read());
+
+		if (!type.equals("sha1")) {
+			throw new PGPException("hash keyword expected");
+		}
+
+		byte[] hashBytes = SXprUtils.readBytes(keyIn, keyIn.read());
+
+		SXprUtils.skipCloseParenthesis(keyIn);
+
+		if (digestProvider != null) {
+			PGPDigestCalculator digestCalculator = digestProvider
+					.get(HashAlgorithmTags.SHA1);
+
+			OutputStream dOut = digestCalculator.getOutputStream();
+
+			dOut.write(Strings.toByteArray("(3:ecc"));
+
+			dOut.write(Strings.toByteArray("(" + curveID.length() + ":"
+					+ curveID + curveName.length() + ":" + curveName + ")"));
+
+			writeCanonical(dOut, "q", qVal);
+			writeCanonical(dOut, "d", d);
+
+			// check protected-at
+			if (protectedAt != null) {
+				dOut.write(protectedAt);
+			}
+
+			dOut.write(Strings.toByteArray(")"));
+
+			byte[] check = digestCalculator.getDigest();
+
+			if (!Arrays.constantTimeAreEqual(check, hashBytes)) {
+				throw new PGPException(
+						"checksum on protected data failed in SExpr");
+			}
+		}
+
+		return d;
+	}
+
+	private BigInteger[] processRSASecretKey(InputStream inputStream,
+			BigInteger n, BigInteger e,
+			PBEProtectionRemoverFactory keyProtectionRemoverFactory)
+			throws IOException, PGPException {
+		String type;
+		byte[][] basicData = extractData(inputStream,
+				keyProtectionRemoverFactory);
+
+		byte[] keyData;
+		byte[] protectedAt = null;
+
+		InputStream keyIn;
+		BigInteger d;
+
+		if (basicData == null) {
+			keyIn = inputStream;
+			byte[] nBytes = SXprUtils.readBytes(inputStream,
+					inputStream.read());
+			d = new BigInteger(1, nBytes);
+
+			SXprUtils.skipCloseParenthesis(inputStream);
+
+		} else {
+			keyData = basicData[0];
+			protectedAt = basicData[1];
+
+			keyIn = new ByteArrayInputStream(keyData);
+
+			SXprUtils.skipOpenParenthesis(keyIn);
+			SXprUtils.skipOpenParenthesis(keyIn);
+			d = readBigInteger("d", keyIn);
+		}
+
+		//
+		// parse the secret key S-expr
+		//
+
+		BigInteger p = readBigInteger("p", keyIn);
+		BigInteger q = readBigInteger("q", keyIn);
+		BigInteger u = readBigInteger("u", keyIn);
+
+		// JGit modification: OCB-encrypted keys don't have and don't need a
+		// hash
+		if (basicData == null
+				|| keyProtectionRemoverFactory instanceof OCBPBEProtectionRemoverFactory) {
+			return new BigInteger[] { d, p, q, u };
+		}
+
+		SXprUtils.skipCloseParenthesis(keyIn);
+
+		SXprUtils.skipOpenParenthesis(keyIn);
+		type = SXprUtils.readString(keyIn, keyIn.read());
+
+		if (!type.equals("hash")) {
+			throw new PGPException("hash keyword expected");
+		}
+		type = SXprUtils.readString(keyIn, keyIn.read());
+
+		if (!type.equals("sha1")) {
+			throw new PGPException("hash keyword expected");
+		}
+
+		byte[] hashBytes = SXprUtils.readBytes(keyIn, keyIn.read());
+
+		SXprUtils.skipCloseParenthesis(keyIn);
+
+		if (digestProvider != null) {
+			PGPDigestCalculator digestCalculator = digestProvider
+					.get(HashAlgorithmTags.SHA1);
+
+			OutputStream dOut = digestCalculator.getOutputStream();
+
+			dOut.write(Strings.toByteArray("(3:rsa"));
+
+			writeCanonical(dOut, "n", n);
+			writeCanonical(dOut, "e", e);
+			writeCanonical(dOut, "d", d);
+			writeCanonical(dOut, "p", p);
+			writeCanonical(dOut, "q", q);
+			writeCanonical(dOut, "u", u);
+
+			// check protected-at
+			if (protectedAt != null) {
+				dOut.write(protectedAt);
+			}
+
+			dOut.write(Strings.toByteArray(")"));
+
+			byte[] check = digestCalculator.getDigest();
+
+			if (!Arrays.constantTimeAreEqual(check, hashBytes)) {
+				throw new PGPException(
+						"checksum on protected data failed in SExpr");
+			}
+		}
+
+		return new BigInteger[] { d, p, q, u };
+	}
+
+	private void writeCanonical(OutputStream dOut, String label, BigInteger i)
+			throws IOException {
+		writeCanonical(dOut, label, i.toByteArray());
+	}
+
+	private void writeCanonical(OutputStream dOut, String label, byte[] data)
+			throws IOException {
+		dOut.write(Strings.toByteArray(
+				"(" + label.length() + ":" + label + data.length + ":"));
+		dOut.write(data);
+		dOut.write(Strings.toByteArray(")"));
+	}
+}
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SXprUtils.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SXprUtils.java
new file mode 100644
index 0000000..220aa28
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SXprUtils.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2000-2021 The Legion of the Bouncy Castle Inc. (https://www.bouncycastle.org)
+ * <p>
+ * 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:
+ * </p>
+ * <p>
+ * The above copyright notice and this permission notice shall be included in all copies or substantial
+ * portions of the Software.
+ * </p>
+ * <p>
+ * 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.
+ * </p>
+ */
+package org.eclipse.jgit.gpg.bc.internal.keys;
+
+// This class is an unmodified copy from Bouncy Castle; needed because it's package-visible only and used by SExprParser.
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.bouncycastle.bcpg.HashAlgorithmTags;
+import org.bouncycastle.bcpg.S2K;
+import org.bouncycastle.util.io.Streams;
+
+/**
+ * Utility functions for looking a S-expression keys. This class will move when
+ * it finds a better home!
+ * <p>
+ * Format documented here:
+ * http://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=agent/keyformat.txt;h=42c4b1f06faf1bbe71ffadc2fee0fad6bec91a97;hb=refs/heads/master
+ * </p>
+ */
+class SXprUtils {
+	private static int readLength(InputStream in, int ch) throws IOException {
+		int len = ch - '0';
+
+		while ((ch = in.read()) >= 0 && ch != ':') {
+			len = len * 10 + ch - '0';
+		}
+
+		return len;
+	}
+
+	static String readString(InputStream in, int ch) throws IOException {
+		int len = readLength(in, ch);
+
+		char[] chars = new char[len];
+
+		for (int i = 0; i != chars.length; i++) {
+			chars[i] = (char) in.read();
+		}
+
+		return new String(chars);
+	}
+
+	static byte[] readBytes(InputStream in, int ch) throws IOException {
+		int len = readLength(in, ch);
+
+		byte[] data = new byte[len];
+
+		Streams.readFully(in, data);
+
+		return data;
+	}
+
+	static S2K parseS2K(InputStream in) throws IOException {
+		skipOpenParenthesis(in);
+
+		// Algorithm is hard-coded to SHA1 below anyway.
+		readString(in, in.read());
+		byte[] iv = readBytes(in, in.read());
+		final long iterationCount = Long.parseLong(readString(in, in.read()));
+
+		skipCloseParenthesis(in);
+
+		// we have to return the actual iteration count provided.
+		S2K s2k = new S2K(HashAlgorithmTags.SHA1, iv, (int) iterationCount) {
+			@Override
+			public long getIterationCount() {
+				return iterationCount;
+			}
+		};
+
+		return s2k;
+	}
+
+	static void skipOpenParenthesis(InputStream in) throws IOException {
+		int ch = in.read();
+		if (ch != '(') {
+			throw new IOException(
+					"unknown character encountered: " + (char) ch); //$NON-NLS-1$
+		}
+	}
+
+	static void skipCloseParenthesis(InputStream in) throws IOException {
+		int ch = in.read();
+		if (ch != ')') {
+			throw new IOException("unknown character encountered"); //$NON-NLS-1$
+		}
+	}
+}
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeys.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeys.java
new file mode 100644
index 0000000..269a1ba
--- /dev/null
+++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeys.java
@@ -0,0 +1,597 @@
+/*
+ * Copyright (C) 2021 Thomas Wolf <thomas.wolf@paranor.ch> 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
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.gpg.bc.internal.keys;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StreamCorruptedException;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+import java.text.MessageFormat;
+import java.util.Arrays;
+
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPPublicKey;
+import org.bouncycastle.openpgp.PGPSecretKey;
+import org.bouncycastle.openpgp.operator.PBEProtectionRemoverFactory;
+import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider;
+import org.bouncycastle.openpgp.operator.jcajce.JcePBEProtectionRemoverFactory;
+import org.bouncycastle.util.io.Streams;
+import org.eclipse.jgit.api.errors.CanceledException;
+import org.eclipse.jgit.errors.UnsupportedCredentialItem;
+import org.eclipse.jgit.gpg.bc.internal.BCText;
+import org.eclipse.jgit.util.RawParseUtils;
+
+/**
+ * Utilities for reading GPG secret keys from a gpg-agent key file.
+ */
+public final class SecretKeys {
+
+	private SecretKeys() {
+		// No instantiation.
+	}
+
+	/**
+	 * Something that can supply a passphrase to decrypt an encrypted secret
+	 * key.
+	 */
+	public interface PassphraseSupplier {
+
+		/**
+		 * Supplies a passphrase.
+		 *
+		 * @return the passphrase
+		 * @throws PGPException
+		 *             if no passphrase can be obtained
+		 * @throws CanceledException
+		 *             if the user canceled passphrase entry
+		 * @throws UnsupportedCredentialItem
+		 *             if an internal error occurred
+		 * @throws URISyntaxException
+		 *             if an internal error occurred
+		 */
+		char[] getPassphrase() throws PGPException, CanceledException,
+				UnsupportedCredentialItem, URISyntaxException;
+	}
+
+	private static final byte[] PROTECTED_KEY = "protected-private-key" //$NON-NLS-1$
+			.getBytes(StandardCharsets.US_ASCII);
+
+	private static final byte[] OCB_PROTECTED = "openpgp-s2k3-ocb-aes" //$NON-NLS-1$
+			.getBytes(StandardCharsets.US_ASCII);
+
+	/**
+	 * Reads a GPG secret key from the given stream.
+	 *
+	 * @param in
+	 *            {@link InputStream} to read from, doesn't need to be buffered
+	 * @param calculatorProvider
+	 *            for checking digests
+	 * @param passphraseSupplier
+	 *            for decrypting encrypted keys
+	 * @param publicKey
+	 *            the secret key should be for
+	 * @return the secret key
+	 * @throws IOException
+	 *             if the stream cannot be parsed
+	 * @throws PGPException
+	 *             if thrown by the underlying S-Expression parser, for instance
+	 *             when the passphrase is wrong
+	 * @throws CanceledException
+	 *             if thrown by the {@code passphraseSupplier}
+	 * @throws UnsupportedCredentialItem
+	 *             if thrown by the {@code passphraseSupplier}
+	 * @throws URISyntaxException
+	 *             if thrown by the {@code passphraseSupplier}
+	 */
+	public static PGPSecretKey readSecretKey(InputStream in,
+			PGPDigestCalculatorProvider calculatorProvider,
+			PassphraseSupplier passphraseSupplier, PGPPublicKey publicKey)
+			throws IOException, PGPException, CanceledException,
+			UnsupportedCredentialItem, URISyntaxException {
+		byte[] data = Streams.readAll(in);
+		if (data.length == 0) {
+			throw new EOFException();
+		} else if (data.length < 4 + PROTECTED_KEY.length) {
+			// +4 for "(21:" for a binary protected key
+			throw new IOException(
+					MessageFormat.format(BCText.get().secretKeyTooShort,
+							Integer.toUnsignedString(data.length)));
+		}
+		SExprParser parser = new SExprParser(calculatorProvider);
+		byte firstChar = data[0];
+		try {
+			if (firstChar == '(') {
+				// Binary format.
+				PBEProtectionRemoverFactory decryptor = null;
+				if (matches(data, 4, PROTECTED_KEY)) {
+					// AES/CBC encrypted.
+					decryptor = new JcePBEProtectionRemoverFactory(
+							passphraseSupplier.getPassphrase(),
+							calculatorProvider);
+				}
+				try (InputStream sIn = new ByteArrayInputStream(data)) {
+					return parser.parseSecretKey(sIn, decryptor, publicKey);
+				}
+			}
+			// Assume it's the new key-value format.
+			try (ByteArrayInputStream keyIn = new ByteArrayInputStream(data)) {
+				byte[] rawData = keyFromNameValueFormat(keyIn);
+				if (!matches(rawData, 1, PROTECTED_KEY)) {
+					// Not encrypted human-readable format.
+					try (InputStream sIn = new ByteArrayInputStream(
+							convertSexpression(rawData))) {
+						return parser.parseSecretKey(sIn, null, publicKey);
+					}
+				}
+				// An encrypted key from a key-value file. Most likely AES/OCB
+				// encrypted.
+				boolean isOCB[] = { false };
+				byte[] sExp = convertSexpression(rawData, isOCB);
+				PBEProtectionRemoverFactory decryptor;
+				if (isOCB[0]) {
+					decryptor = new OCBPBEProtectionRemoverFactory(
+							passphraseSupplier.getPassphrase(),
+							calculatorProvider, getAad(sExp));
+				} else {
+					decryptor = new JcePBEProtectionRemoverFactory(
+							passphraseSupplier.getPassphrase(),
+							calculatorProvider);
+				}
+				try (InputStream sIn = new ByteArrayInputStream(sExp)) {
+					return parser.parseSecretKey(sIn, decryptor, publicKey);
+				}
+			}
+		} catch (IOException e) {
+			throw new PGPException(e.getLocalizedMessage(), e);
+		}
+	}
+
+	/**
+	 * Extract the AAD for the OCB decryption from an s-expression.
+	 *
+	 * @param sExp
+	 *            buffer containing a valid binary s-expression
+	 * @return the AAD
+	 */
+	private static byte[] getAad(byte[] sExp) {
+		// Given a key
+		// @formatter:off
+		// (protected-private-key (rsa ... (protected openpgp-s2k3-ocb-aes ... )(protected-at ...)))
+		//                        A        B                                    C                  D
+		// The AAD is [A..B)[C..D). (From the binary serialized form.)
+		// @formatter:on
+		int i = 1; // Skip initial '('
+		while (sExp[i] != '(') {
+			i++;
+		}
+		int aadStart = i++;
+		int aadEnd = skip(sExp, aadStart);
+		byte[] protectedPrefix = "(9:protected" //$NON-NLS-1$
+				.getBytes(StandardCharsets.US_ASCII);
+		while (!matches(sExp, i, protectedPrefix)) {
+			i++;
+		}
+		int protectedStart = i;
+		int protectedEnd = skip(sExp, protectedStart);
+		byte[] aadData = new byte[aadEnd - aadStart
+				- (protectedEnd - protectedStart)];
+		System.arraycopy(sExp, aadStart, aadData, 0, protectedStart - aadStart);
+		System.arraycopy(sExp, protectedEnd, aadData, protectedStart - aadStart,
+				aadEnd - protectedEnd);
+		return aadData;
+	}
+
+	/**
+	 * Skips a list including nested lists.
+	 *
+	 * @param sExp
+	 *            buffer containing valid binary s-expression data
+	 * @param start
+	 *            index of the opening '(' of the list to skip
+	 * @return the index after the closing ')' of the skipped list
+	 */
+	private static int skip(byte[] sExp, int start) {
+		int i = start + 1;
+		int depth = 1;
+		while (depth > 0) {
+			switch (sExp[i]) {
+			case '(':
+				depth++;
+				break;
+			case ')':
+				depth--;
+				break;
+			default:
+				// We must be on a length
+				int j = i;
+				while (sExp[j] >= '0' && sExp[j] <= '9') {
+					j++;
+				}
+				// j is on the colon
+				int length = Integer.parseInt(
+						new String(sExp, i, j - i, StandardCharsets.US_ASCII));
+				i = j + length;
+			}
+			i++;
+		}
+		return i;
+	}
+
+	/**
+	 * Checks whether the {@code needle} matches {@code src} at offset
+	 * {@code from}.
+	 *
+	 * @param src
+	 *            to match against {@code needle}
+	 * @param from
+	 *            position in {@code src} to start matching
+	 * @param needle
+	 *            to match against
+	 * @return {@code true} if {@code src} contains {@code needle} at position
+	 *         {@code from}, {@code false} otherwise
+	 */
+	private static boolean matches(byte[] src, int from, byte[] needle) {
+		if (from < 0 || from + needle.length > src.length) {
+			return false;
+		}
+		return org.bouncycastle.util.Arrays.constantTimeAreEqual(needle.length,
+				src, from, needle, 0);
+	}
+
+	/**
+	 * Converts a human-readable serialized s-expression into a binary
+	 * serialized s-expression.
+	 *
+	 * @param humanForm
+	 *            to convert
+	 * @return the converted s-expression
+	 * @throws IOException
+	 *             if the conversion fails
+	 */
+	private static byte[] convertSexpression(byte[] humanForm)
+			throws IOException {
+		boolean[] isOCB = { false };
+		return convertSexpression(humanForm, isOCB);
+	}
+
+	/**
+	 * Converts a human-readable serialized s-expression into a binary
+	 * serialized s-expression.
+	 *
+	 * @param humanForm
+	 *            to convert
+	 * @param isOCB
+	 *            returns whether the s-expression specified AES/OCB encryption
+	 * @return the converted s-expression
+	 * @throws IOException
+	 *             if the conversion fails
+	 */
+	private static byte[] convertSexpression(byte[] humanForm, boolean[] isOCB)
+			throws IOException {
+		int pos = 0;
+		try (ByteArrayOutputStream out = new ByteArrayOutputStream(
+				humanForm.length)) {
+			while (pos < humanForm.length) {
+				byte b = humanForm[pos];
+				if (b == '(' || b == ')') {
+					out.write(b);
+					pos++;
+				} else if (isGpgSpace(b)) {
+					pos++;
+				} else if (b == '#') {
+					// Hex value follows up to the next #
+					int i = ++pos;
+					while (i < humanForm.length && isHex(humanForm[i])) {
+						i++;
+					}
+					if (i == pos || humanForm[i] != '#') {
+						throw new StreamCorruptedException(
+								BCText.get().sexprHexNotClosed);
+					}
+					if ((i - pos) % 2 != 0) {
+						throw new StreamCorruptedException(
+								BCText.get().sexprHexOdd);
+					}
+					int l = (i - pos) / 2;
+					out.write(Integer.toString(l)
+							.getBytes(StandardCharsets.US_ASCII));
+					out.write(':');
+					while (pos < i) {
+						int x = (nibble(humanForm[pos]) << 4)
+								| nibble(humanForm[pos + 1]);
+						pos += 2;
+						out.write(x);
+					}
+					pos = i + 1;
+				} else if (isTokenChar(b)) {
+					// Scan the token
+					int start = pos++;
+					while (pos < humanForm.length
+							&& isTokenChar(humanForm[pos])) {
+						pos++;
+					}
+					int l = pos - start;
+					if (pos - start == OCB_PROTECTED.length
+							&& matches(humanForm, start, OCB_PROTECTED)) {
+						isOCB[0] = true;
+					}
+					out.write(Integer.toString(l)
+							.getBytes(StandardCharsets.US_ASCII));
+					out.write(':');
+					out.write(humanForm, start, pos - start);
+				} else if (b == '"') {
+					// Potentially quoted string.
+					int start = ++pos;
+					boolean escaped = false;
+					while (pos < humanForm.length
+							&& (escaped || humanForm[pos] != '"')) {
+						int ch = humanForm[pos++];
+						escaped = !escaped && ch == '\\';
+					}
+					if (pos >= humanForm.length) {
+						throw new StreamCorruptedException(
+								BCText.get().sexprStringNotClosed);
+					}
+					// start is on the first character of the string, pos on the
+					// closing quote.
+					byte[] dq = dequote(humanForm, start, pos);
+					out.write(Integer.toString(dq.length)
+							.getBytes(StandardCharsets.US_ASCII));
+					out.write(':');
+					out.write(dq);
+					pos++;
+				} else {
+					throw new StreamCorruptedException(
+							MessageFormat.format(BCText.get().sexprUnhandled,
+									Integer.toHexString(b & 0xFF)));
+				}
+			}
+			return out.toByteArray();
+		}
+	}
+
+	/**
+	 * GPG-style string de-quoting, which is basically C-style, with some
+	 * literal CR/LF escaping.
+	 *
+	 * @param in
+	 *            buffer containing the quoted string
+	 * @param from
+	 *            index after the opening quote in {@code in}
+	 * @param to
+	 *            index of the closing quote in {@code in}
+	 * @return the dequoted raw string value
+	 * @throws StreamCorruptedException
+	 */
+	private static byte[] dequote(byte[] in, int from, int to)
+			throws StreamCorruptedException {
+		// Result must be shorter or have the same length
+		byte[] out = new byte[to - from];
+		int j = 0;
+		int i = from;
+		while (i < to) {
+			byte b = in[i++];
+			if (b != '\\') {
+				out[j++] = b;
+				continue;
+			}
+			if (i == to) {
+				throw new StreamCorruptedException(
+						BCText.get().sexprStringInvalidEscapeAtEnd);
+			}
+			b = in[i++];
+			switch (b) {
+			case 'b':
+				out[j++] = '\b';
+				break;
+			case 'f':
+				out[j++] = '\f';
+				break;
+			case 'n':
+				out[j++] = '\n';
+				break;
+			case 'r':
+				out[j++] = '\r';
+				break;
+			case 't':
+				out[j++] = '\t';
+				break;
+			case 'v':
+				out[j++] = 0x0B;
+				break;
+			case '"':
+			case '\'':
+			case '\\':
+				out[j++] = b;
+				break;
+			case '\r':
+				// Escaped literal line end. If an LF is following, skip that,
+				// too.
+				if (i < to && in[i] == '\n') {
+					i++;
+				}
+				break;
+			case '\n':
+				// Same for LF possibly followed by CR.
+				if (i < to && in[i] == '\r') {
+					i++;
+				}
+				break;
+			case 'x':
+				if (i + 1 >= to || !isHex(in[i]) || !isHex(in[i + 1])) {
+					throw new StreamCorruptedException(
+							BCText.get().sexprStringInvalidHexEscape);
+				}
+				out[j++] = (byte) ((nibble(in[i]) << 4) | nibble(in[i + 1]));
+				i += 2;
+				break;
+			case '0':
+			case '1':
+			case '2':
+			case '3':
+				if (i + 2 >= to || !isOctal(in[i]) || !isOctal(in[i + 1])
+						|| !isOctal(in[i + 2])) {
+					throw new StreamCorruptedException(
+							BCText.get().sexprStringInvalidOctalEscape);
+				}
+				out[j++] = (byte) (((((in[i] - '0') << 3)
+						| (in[i + 1] - '0')) << 3) | (in[i + 2] - '0'));
+				i += 3;
+				break;
+			default:
+				throw new StreamCorruptedException(MessageFormat.format(
+						BCText.get().sexprStringInvalidEscape,
+						Integer.toHexString(b & 0xFF)));
+			}
+		}
+		return Arrays.copyOf(out, j);
+	}
+
+	/**
+	 * Extracts the key from a GPG name-value-pair key file.
+	 * <p>
+	 * Package-visible for tests only.
+	 * </p>
+	 *
+	 * @param in
+	 *            {@link InputStream} to read from; should be buffered
+	 * @return the raw key data as extracted from the file
+	 * @throws IOException
+	 *             if the {@code in} stream cannot be read or does not contain a
+	 *             key
+	 */
+	static byte[] keyFromNameValueFormat(InputStream in) throws IOException {
+		// It would be nice if we could use RawParseUtils here, but GPG compares
+		// names case-insensitively. We're only interested in the "Key:"
+		// name-value pair.
+		int[] nameLow = { 'k', 'e', 'y', ':' };
+		int[] nameCap = { 'K', 'E', 'Y', ':' };
+		int nameIdx = 0;
+		for (;;) {
+			int next = in.read();
+			if (next < 0) {
+				throw new EOFException();
+			}
+			if (next == '\n') {
+				nameIdx = 0;
+			} else if (nameIdx >= 0) {
+				if (nameLow[nameIdx] == next || nameCap[nameIdx] == next) {
+					nameIdx++;
+					if (nameIdx == nameLow.length) {
+						break;
+					}
+				} else {
+					nameIdx = -1;
+				}
+			}
+		}
+		// We're after "Key:". Read the value as continuation lines.
+		int last = ':';
+		byte[] rawData;
+		try (ByteArrayOutputStream out = new ByteArrayOutputStream(8192)) {
+			for (;;) {
+				int next = in.read();
+				if (next < 0) {
+					break;
+				}
+				if (last == '\n') {
+					if (next == ' ' || next == '\t') {
+						// Continuation line; skip this whitespace
+						last = next;
+						continue;
+					}
+					break; // Not a continuation line
+				}
+				out.write(next);
+				last = next;
+			}
+			rawData = out.toByteArray();
+		}
+		// GPG trims off trailing whitespace, and a line having only whitespace
+		// is a single LF.
+		try (ByteArrayOutputStream out = new ByteArrayOutputStream(
+				rawData.length)) {
+			int lineStart = 0;
+			boolean trimLeading = true;
+			while (lineStart < rawData.length) {
+				int nextLineStart = RawParseUtils.nextLF(rawData, lineStart);
+				if (trimLeading) {
+					while (lineStart < nextLineStart
+							&& isGpgSpace(rawData[lineStart])) {
+						lineStart++;
+					}
+				}
+				// Trim trailing
+				int i = nextLineStart - 1;
+				while (lineStart < i && isGpgSpace(rawData[i])) {
+					i--;
+				}
+				if (i <= lineStart) {
+					// Empty line signifies LF
+					out.write('\n');
+					trimLeading = true;
+				} else {
+					out.write(rawData, lineStart, i - lineStart + 1);
+					trimLeading = false;
+				}
+				lineStart = nextLineStart;
+			}
+			return out.toByteArray();
+		}
+	}
+
+	private static boolean isGpgSpace(int ch) {
+		return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n';
+	}
+
+	private static boolean isTokenChar(int ch) {
+		switch (ch) {
+		case '-':
+		case '.':
+		case '/':
+		case '_':
+		case ':':
+		case '*':
+		case '+':
+		case '=':
+			return true;
+		default:
+			if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
+					|| (ch >= '0' && ch <= '9')) {
+				return true;
+			}
+			return false;
+		}
+	}
+
+	private static boolean isHex(int ch) {
+		return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F')
+				|| (ch >= 'a' && ch <= 'f');
+	}
+
+	private static boolean isOctal(int ch) {
+		return (ch >= '0' && ch <= '7');
+	}
+
+	private static int nibble(int ch) {
+		if (ch >= '0' && ch <= '9') {
+			return ch - '0';
+		} else if (ch >= 'A' && ch <= 'F') {
+			return ch - 'A' + 10;
+		} else if (ch >= 'a' && ch <= 'f') {
+			return ch - 'a' + 10;
+		}
+		return -1;
+	}
+}
diff --git a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
index f521697..f2bed8d 100644
--- a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
@@ -3,33 +3,33 @@
 Bundle-Name: %Bundle-Name
 Automatic-Module-Name: org.eclipse.jgit.http.apache
 Bundle-SymbolicName: org.eclipse.jgit.http.apache
-Bundle-Version: 5.10.1.qualifier
+Bundle-Version: 5.11.2.qualifier
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Bundle-Localization: plugin
 Bundle-Vendor: %Bundle-Vendor
 Bundle-ActivationPolicy: lazy
 Import-Package: org.apache.http;version="[4.3.0,5.0.0)",
- org.apache.http.client;version="[4.3.0,5.0.0)",
- org.apache.http.client.config;version="[4.3.0,5.0.0)",
- org.apache.http.client.methods;version="[4.3.0,5.0.0)",
- org.apache.http.client.params;version="[4.3.0,5.0.0)",
+ org.apache.http.client;version="[4.4.0,5.0.0)",
+ org.apache.http.client.config;version="[4.4.0,5.0.0)",
+ org.apache.http.client.methods;version="[4.4.0,5.0.0)",
+ org.apache.http.client.params;version="[4.4.0,5.0.0)",
  org.apache.http.config;version="[4.3.0,5.0.0)",
- org.apache.http.conn;version="[4.3.0,5.0.0)",
- org.apache.http.conn.params;version="[4.3.0,5.0.0)",
- org.apache.http.conn.scheme;version="[4.3.0,5.0.0)",
- org.apache.http.conn.socket;version="[4.3.0,5.0.0)",
- org.apache.http.conn.ssl;version="[4.3.0,5.0.0)",
- org.apache.http.conn.util;version="[4.3.0,5.0.0)",
+ org.apache.http.conn;version="[4.4.0,5.0.0)",
+ org.apache.http.conn.params;version="[4.4.0,5.0.0)",
+ org.apache.http.conn.scheme;version="[4.4.0,5.0.0)",
+ org.apache.http.conn.socket;version="[4.4.0,5.0.0)",
+ org.apache.http.conn.ssl;version="[4.4.0,5.0.0)",
+ org.apache.http.conn.util;version="[4.4.0,5.0.0)",
  org.apache.http.entity;version="[4.3.0,5.0.0)",
- org.apache.http.impl.client;version="[4.3.0,5.0.0)",
- org.apache.http.impl.conn;version="[4.3.0,5.0.0)",
+ org.apache.http.impl.client;version="[4.4.0,5.0.0)",
+ org.apache.http.impl.conn;version="[4.4.0,5.0.0)",
  org.apache.http.params;version="[4.3.0,5.0.0)",
  org.apache.http.ssl;version="[4.3.0,5.0.0)",
- org.eclipse.jgit.annotations;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.nls;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.transport.http;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.util;version="[5.10.1,5.11.0)"
-Export-Package: org.eclipse.jgit.transport.http.apache;version="5.10.1";
+ org.eclipse.jgit.annotations;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.nls;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.transport.http;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.util;version="[5.11.2,5.12.0)"
+Export-Package: org.eclipse.jgit.transport.http.apache;version="5.11.2";
   uses:="org.apache.http.client,
    org.eclipse.jgit.transport.http,
    org.apache.http.entity,
diff --git a/org.eclipse.jgit.http.apache/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.http.apache/META-INF/SOURCE-MANIFEST.MF
index fd37981..9ca1e9b 100644
--- a/org.eclipse.jgit.http.apache/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.http.apache/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
 Bundle-Name: org.eclipse.jgit.http.apache - Sources
 Bundle-SymbolicName: org.eclipse.jgit.http.apache.source
 Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 5.10.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.http.apache;version="5.10.1.qualifier";roots="."
+Bundle-Version: 5.11.2.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.http.apache;version="5.11.2.qualifier";roots="."
diff --git a/org.eclipse.jgit.http.apache/pom.xml b/org.eclipse.jgit.http.apache/pom.xml
index d107c3d2..631859e 100644
--- a/org.eclipse.jgit.http.apache/pom.xml
+++ b/org.eclipse.jgit.http.apache/pom.xml
@@ -15,7 +15,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.10.1-SNAPSHOT</version>
+    <version>5.11.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.http.apache</artifactId>
diff --git a/org.eclipse.jgit.http.apache/resources/org/eclipse/jgit/transport/http/apache/internal/HttpApacheText.properties b/org.eclipse.jgit.http.apache/resources/org/eclipse/jgit/transport/http/apache/internal/HttpApacheText.properties
index d2e5216..b7b9af0 100644
--- a/org.eclipse.jgit.http.apache/resources/org/eclipse/jgit/transport/http/apache/internal/HttpApacheText.properties
+++ b/org.eclipse.jgit.http.apache/resources/org/eclipse/jgit/transport/http/apache/internal/HttpApacheText.properties
@@ -1 +1,2 @@
+httpWrongConnectionType=Wrong connection type: expected {0}, got {1}.
 unexpectedSSLContextException=unexpected exception when searching for the TLS protocol
diff --git a/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java b/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java
index ed05f0a..90348f5 100644
--- a/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java
+++ b/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java
@@ -57,9 +57,7 @@
 import org.apache.http.config.RegistryBuilder;
 import org.apache.http.conn.socket.ConnectionSocketFactory;
 import org.apache.http.conn.socket.PlainConnectionSocketFactory;
-import org.apache.http.conn.ssl.DefaultHostnameVerifier;
 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
-import org.apache.http.conn.util.PublicSuffixMatcherLoader;
 import org.apache.http.impl.client.HttpClientBuilder;
 import org.apache.http.impl.client.HttpClients;
 import org.apache.http.impl.client.SystemDefaultCredentialsProvider;
@@ -103,7 +101,11 @@ public class HttpClientConnection implements HttpConnection {
 
 	private HostnameVerifier hostnameverifier;
 
-	SSLContext ctx;
+	private SSLContext ctx;
+
+	private SSLConnectionSocketFactory socketFactory;
+
+	private boolean usePooling = true;
 
 	private HttpClient getClient() {
 		if (client == null) {
@@ -125,11 +127,18 @@ private HttpClient getClient() {
 				configBuilder
 						.setRedirectsEnabled(followRedirects.booleanValue());
 			}
-			SSLConnectionSocketFactory sslConnectionFactory = getSSLSocketFactory();
+			boolean pooled = true;
+			SSLConnectionSocketFactory sslConnectionFactory;
+			if (socketFactory != null) {
+				pooled = usePooling;
+				sslConnectionFactory = socketFactory;
+			} else {
+				// Legacy implementation.
+				pooled = (hostnameverifier == null);
+				sslConnectionFactory = getSSLSocketFactory();
+			}
 			clientBuilder.setSSLSocketFactory(sslConnectionFactory);
-			if (hostnameverifier != null) {
-				// Using a custom verifier: we don't want pooled connections
-				// with this.
+			if (!pooled) {
 				Registry<ConnectionSocketFactory> registry = RegistryBuilder
 						.<ConnectionSocketFactory> create()
 						.register("https", sslConnectionFactory)
@@ -147,14 +156,19 @@ private HttpClient getClient() {
 		return client;
 	}
 
+	void setSSLSocketFactory(@NonNull SSLConnectionSocketFactory factory,
+			boolean isDefault) {
+		socketFactory = factory;
+		usePooling = isDefault;
+	}
+
 	private SSLConnectionSocketFactory getSSLSocketFactory() {
 		HostnameVerifier verifier = hostnameverifier;
 		SSLContext context;
 		if (verifier == null) {
 			// Use defaults
-			context = SSLContexts.createDefault();
-			verifier = new DefaultHostnameVerifier(
-					PublicSuffixMatcherLoader.getDefault());
+			context = SSLContexts.createSystemDefault();
+			verifier = SSLConnectionSocketFactory.getDefaultHostnameVerifier();
 		} else {
 			// Using a custom verifier. Attention: configure() must have been
 			// called already, otherwise one gets a "context not initialized"
diff --git a/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnectionFactory.java b/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnectionFactory.java
index 3c05cde..4de3e47 100644
--- a/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnectionFactory.java
+++ b/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnectionFactory.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Christian Halstrick <christian.halstrick@sap.com> and others
+ * Copyright (C) 2013, 2020 Christian Halstrick <christian.halstrick@sap.com> 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
@@ -12,27 +12,100 @@
 import java.io.IOException;
 import java.net.Proxy;
 import java.net.URL;
+import java.security.GeneralSecurityException;
+import java.text.MessageFormat;
 
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.TrustManager;
+
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
 import org.eclipse.jgit.transport.http.HttpConnection;
-import org.eclipse.jgit.transport.http.HttpConnectionFactory;
+import org.eclipse.jgit.transport.http.HttpConnectionFactory2;
+import org.eclipse.jgit.transport.http.NoCheckX509TrustManager;
+import org.eclipse.jgit.transport.http.apache.internal.HttpApacheText;
+import org.eclipse.jgit.util.HttpSupport;
 
 /**
- * A factory returning instances of
- * {@link org.eclipse.jgit.transport.http.apache.HttpClientConnection}
+ * A factory returning instances of {@link HttpClientConnection}.
  *
  * @since 3.3
  */
-public class HttpClientConnectionFactory implements HttpConnectionFactory {
-	/** {@inheritDoc} */
+public class HttpClientConnectionFactory implements HttpConnectionFactory2 {
+
 	@Override
 	public HttpConnection create(URL url) throws IOException {
 		return new HttpClientConnection(url.toString());
 	}
 
-	/** {@inheritDoc} */
 	@Override
-	public HttpConnection create(URL url, Proxy proxy)
-			throws IOException {
+	public HttpConnection create(URL url, Proxy proxy) throws IOException {
 		return new HttpClientConnection(url.toString(), proxy);
 	}
+
+	@Override
+	public GitSession newSession() {
+		return new HttpClientSession();
+	}
+
+	private static class HttpClientSession implements GitSession {
+
+		private SSLContext securityContext;
+
+		private SSLConnectionSocketFactory socketFactory;
+
+		private boolean isDefault;
+
+		@Override
+		public HttpClientConnection configure(HttpConnection connection,
+				boolean sslVerify)
+				throws IOException, GeneralSecurityException {
+			if (!(connection instanceof HttpClientConnection)) {
+				throw new IllegalArgumentException(MessageFormat.format(
+						HttpApacheText.get().httpWrongConnectionType,
+						HttpClientConnection.class.getName(),
+						connection.getClass().getName()));
+			}
+			HttpClientConnection conn = (HttpClientConnection) connection;
+			String scheme = conn.getURL().getProtocol();
+			if (!"https".equals(scheme)) { //$NON-NLS-1$
+				return conn;
+			}
+			if (securityContext == null || isDefault != sslVerify) {
+				isDefault = sslVerify;
+				HostnameVerifier verifier;
+				if (sslVerify) {
+					securityContext = SSLContext.getDefault();
+					verifier = SSLConnectionSocketFactory
+							.getDefaultHostnameVerifier();
+				} else {
+					securityContext = SSLContext.getInstance("TLS");
+					TrustManager[] trustAllCerts = {
+							new NoCheckX509TrustManager() };
+					securityContext.init(null, trustAllCerts, null);
+					verifier = (name, session) -> true;
+				}
+				socketFactory = new SSLConnectionSocketFactory(securityContext,
+						verifier) {
+
+					@Override
+					protected void prepareSocket(SSLSocket socket)
+							throws IOException {
+						super.prepareSocket(socket);
+						HttpSupport.configureTLS(socket);
+					}
+				};
+			}
+			conn.setSSLSocketFactory(socketFactory, isDefault);
+			return conn;
+		}
+
+		@Override
+		public void close() {
+			securityContext = null;
+			socketFactory = null;
+		}
+
+	}
 }
diff --git a/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/internal/HttpApacheText.java b/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/internal/HttpApacheText.java
index 907ab98..677d7d7 100644
--- a/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/internal/HttpApacheText.java
+++ b/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/internal/HttpApacheText.java
@@ -27,5 +27,6 @@ public static HttpApacheText get() {
 	}
 
 	// @formatter:off
+	/***/ public String httpWrongConnectionType;
 	/***/ public String unexpectedSSLContextException;
 }
diff --git a/org.eclipse.jgit.http.server/.settings/.api_filters b/org.eclipse.jgit.http.server/.settings/.api_filters
deleted file mode 100644
index 951a53b..0000000
--- a/org.eclipse.jgit.http.server/.settings/.api_filters
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<component id="org.eclipse.jgit.http.server" version="2">
-    <resource path="src/org/eclipse/jgit/http/server/GitServlet.java" type="org.eclipse.jgit.http.server.GitServlet">
-        <filter id="1142947843">
-            <message_arguments>
-                <message_argument value="5.9.1"/>
-                <message_argument value="setReceivePackErrorHandler(ReceivePackErrorHandler)"/>
-            </message_arguments>
-        </filter>
-        <filter id="1142947843">
-            <message_arguments>
-                <message_argument value="5.9.1"/>
-                <message_argument value="setUploadPackErrorHandler(UploadPackErrorHandler)"/>
-            </message_arguments>
-        </filter>
-    </resource>
-</component>
diff --git a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
index 0d6e5d8..8b418d4 100644
--- a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
@@ -3,13 +3,13 @@
 Bundle-Name: %Bundle-Name
 Automatic-Module-Name: org.eclipse.jgit.http.server
 Bundle-SymbolicName: org.eclipse.jgit.http.server
-Bundle-Version: 5.10.1.qualifier
+Bundle-Version: 5.11.2.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %Bundle-Vendor
-Export-Package: org.eclipse.jgit.http.server;version="5.10.1",
- org.eclipse.jgit.http.server.glue;version="5.10.1";
+Export-Package: org.eclipse.jgit.http.server;version="5.11.2",
+ org.eclipse.jgit.http.server.glue;version="5.11.2";
   uses:="javax.servlet,javax.servlet.http",
- org.eclipse.jgit.http.server.resolver;version="5.10.1";
+ org.eclipse.jgit.http.server.resolver;version="5.11.2";
   uses:="org.eclipse.jgit.transport.resolver,
    org.eclipse.jgit.lib,
    org.eclipse.jgit.transport,
@@ -18,14 +18,14 @@
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Import-Package: javax.servlet;version="[2.5.0,3.2.0)",
  javax.servlet.http;version="[2.5.0,3.2.0)",
- org.eclipse.jgit.annotations;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.errors;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.internal.storage.file;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.internal.transport.parser;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lib;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.nls;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.revwalk;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.transport;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.transport.resolver;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.util;version="[5.10.1,5.11.0)"
+ org.eclipse.jgit.annotations;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.errors;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.internal.transport.parser;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.lib;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.nls;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.revwalk;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.transport;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.transport.resolver;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.util;version="[5.11.2,5.12.0)"
diff --git a/org.eclipse.jgit.http.server/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.http.server/META-INF/SOURCE-MANIFEST.MF
index a4eabce..fbbde74 100644
--- a/org.eclipse.jgit.http.server/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.http.server/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
 Bundle-Name: org.eclipse.jgit.http.server - Sources
 Bundle-SymbolicName: org.eclipse.jgit.http.server.source
 Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 5.10.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.http.server;version="5.10.1.qualifier";roots="."
+Bundle-Version: 5.11.2.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.http.server;version="5.11.2.qualifier";roots="."
diff --git a/org.eclipse.jgit.http.server/pom.xml b/org.eclipse.jgit.http.server/pom.xml
index 9857129..2094f04 100644
--- a/org.eclipse.jgit.http.server/pom.xml
+++ b/org.eclipse.jgit.http.server/pom.xml
@@ -19,7 +19,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.10.1-SNAPSHOT</version>
+    <version>5.11.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.http.server</artifactId>
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/InfoPacksServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/InfoPacksServlet.java
index c3d7255..e90580b 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/InfoPacksServlet.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/InfoPacksServlet.java
@@ -20,7 +20,7 @@
 import javax.servlet.http.HttpServletResponse;
 
 import org.eclipse.jgit.internal.storage.file.ObjectDirectory;
-import org.eclipse.jgit.internal.storage.file.PackFile;
+import org.eclipse.jgit.internal.storage.file.Pack;
 import org.eclipse.jgit.lib.ObjectDatabase;
 
 /** Sends the current list of pack files, sorted most recent first. */
@@ -38,7 +38,7 @@ private static String packList(HttpServletRequest req) {
 		final StringBuilder out = new StringBuilder();
 		final ObjectDatabase db = getRepository(req).getObjectDatabase();
 		if (db instanceof ObjectDirectory) {
-			for (PackFile pack : ((ObjectDirectory) db).getPacks()) {
+			for (Pack pack : ((ObjectDirectory) db).getPacks()) {
 				out.append("P ");
 				out.append(pack.getPackFile().getName());
 				out.append('\n');
diff --git a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
index 05a82ac..c700271 100644
--- a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-Name: %Bundle-Name
 Automatic-Module-Name: org.eclipse.jgit.http.test
 Bundle-SymbolicName: org.eclipse.jgit.http.test
-Bundle-Version: 5.10.1.qualifier
+Bundle-Version: 5.11.2.qualifier
 Bundle-Vendor: %Bundle-Vendor
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
@@ -12,7 +12,7 @@
  org.apache.commons.codec;version="[1.6.0,2.0.0)",
  org.apache.commons.codec.binary;version="[1.6.0,2.0.0)",
  org.apache.http;version="[4.3.0,5.0.0)",
- org.apache.http.client;version="[4.3.0,5.0.0)",
+ org.apache.http.client;version="[4.4.0,5.0.0)",
  org.apache.http.message;version="[4.3.0,5.0.0)",
  org.eclipse.jetty.continuation;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.http;version="[9.4.5,10.0.0)",
@@ -28,25 +28,26 @@
  org.eclipse.jetty.util.log;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.util.security;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.util.thread;version="[9.4.5,10.0.0)",
- org.eclipse.jgit.errors;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.http.server;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.http.server.glue;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.http.server.resolver;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.internal;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.internal.storage.file;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.internal.storage.reftable;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.junit;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.junit.http;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lib;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.nls;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.revwalk;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.storage.file;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.transport;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.transport.http;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.transport.http.apache;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.transport.resolver;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.util;version="[5.10.1,5.11.0)",
+ org.eclipse.jgit.api;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.errors;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.http.server;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.http.server.glue;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.http.server.resolver;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.internal;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.internal.storage.reftable;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.junit;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.junit.http;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.lib;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.nls;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.revwalk;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.storage.file;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.transport;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.transport.http;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.transport.http.apache;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.transport.resolver;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.util;version="[5.11.2,5.12.0)",
  org.hamcrest;version="[1.1.0,2.0.0)",
  org.hamcrest.core;version="[1.1.0,2.0.0)",
  org.junit;version="[4.13,5.0.0)",
diff --git a/org.eclipse.jgit.http.test/build.properties b/org.eclipse.jgit.http.test/build.properties
index e8bacac..a909f13 100644
--- a/org.eclipse.jgit.http.test/build.properties
+++ b/org.eclipse.jgit.http.test/build.properties
@@ -4,3 +4,5 @@
 bin.includes = META-INF/,\
                .,\
                plugin.properties
+additional.bundles = org.apache.log4j,\
+                     org.slf4j.binding.log4j12
diff --git a/org.eclipse.jgit.http.test/pom.xml b/org.eclipse.jgit.http.test/pom.xml
index 68d87c5..2985051 100644
--- a/org.eclipse.jgit.http.test/pom.xml
+++ b/org.eclipse.jgit.http.test/pom.xml
@@ -18,7 +18,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.10.1-SNAPSHOT</version>
+    <version>5.11.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.http.test</artifactId>
diff --git a/org.eclipse.jgit.http.test/src/org/eclipse/jgit/http/test/RefsUnreadableInMemoryRepository.java b/org.eclipse.jgit.http.test/src/org/eclipse/jgit/http/test/RefsUnreadableInMemoryRepository.java
index 80cbe87..4167b03 100644
--- a/org.eclipse.jgit.http.test/src/org/eclipse/jgit/http/test/RefsUnreadableInMemoryRepository.java
+++ b/org.eclipse.jgit.http.test/src/org/eclipse/jgit/http/test/RefsUnreadableInMemoryRepository.java
@@ -85,6 +85,17 @@ public List<Ref> getRefsByPrefix(String prefix) throws IOException {
 
 		/** {@inheritDoc} */
 		@Override
+		public List<Ref> getRefsByPrefixWithExclusions(String include, Set<String> excludes)
+				throws IOException {
+			if (failing) {
+				throw new IOException("disk failed, no refs found");
+			}
+
+			return super.getRefsByPrefixWithExclusions(include, excludes);
+		}
+
+		/** {@inheritDoc} */
+		@Override
 		public Set<Ref> getTipsWithSha1(ObjectId id) throws IOException {
 			if (failing) {
 				throw new IOException("disk failed, no refs found");
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/AllProtocolsHttpTestCase.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/AllProtocolsHttpTestCase.java
new file mode 100644
index 0000000..c6931ad
--- /dev/null
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/AllProtocolsHttpTestCase.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2020, Thomas Wolf <thomas.wolf@paranor.ch> 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
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.http.test;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.jgit.junit.http.HttpTestCase;
+import org.eclipse.jgit.transport.HttpTransport;
+import org.eclipse.jgit.transport.http.HttpConnectionFactory;
+import org.eclipse.jgit.transport.http.JDKHttpConnectionFactory;
+import org.eclipse.jgit.transport.http.apache.HttpClientConnectionFactory;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * Abstract test base class for running HTTP-related tests with all connection
+ * factories provided in JGit and with both protocol V0 and V2.
+ */
+@Ignore
+@RunWith(Parameterized.class)
+public abstract class AllProtocolsHttpTestCase extends HttpTestCase {
+
+	protected static class TestParameters {
+
+		public final HttpConnectionFactory factory;
+
+		public final boolean enableProtocolV2;
+
+		public TestParameters(HttpConnectionFactory factory,
+				boolean enableProtocolV2) {
+			this.factory = factory;
+			this.enableProtocolV2 = enableProtocolV2;
+		}
+
+		@Override
+		public String toString() {
+			return factory.toString() + " protocol "
+					+ (enableProtocolV2 ? "V2" : "V0");
+		}
+	}
+
+	@Parameters(name = "{0}")
+	public static Collection<TestParameters> data() {
+		// run all tests with both connection factories we have
+		HttpConnectionFactory[] factories = new HttpConnectionFactory[] {
+				new JDKHttpConnectionFactory() {
+
+					@Override
+					public String toString() {
+						return this.getClass().getSuperclass().getName();
+					}
+				}, new HttpClientConnectionFactory() {
+
+					@Override
+					public String toString() {
+						return this.getClass().getSuperclass().getName();
+					}
+				} };
+		List<TestParameters> result = new ArrayList<>();
+		for (HttpConnectionFactory factory : factories) {
+			result.add(new TestParameters(factory, false));
+			result.add(new TestParameters(factory, true));
+		}
+		return result;
+	}
+
+	protected final boolean enableProtocolV2;
+
+	protected AllProtocolsHttpTestCase(TestParameters params) {
+		HttpTransport.setConnectionFactory(params.factory);
+		enableProtocolV2 = params.enableProtocolV2;
+	}
+
+	private static HttpConnectionFactory originalFactory;
+
+	@BeforeClass
+	public static void saveConnectionFactory() {
+		originalFactory = HttpTransport.getConnectionFactory();
+	}
+
+	@AfterClass
+	public static void restoreConnectionFactory() {
+		HttpTransport.setConnectionFactory(originalFactory);
+	}
+
+}
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java
index 6da5f86..8b28c42 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java
@@ -35,6 +35,7 @@
 import org.eclipse.jgit.lib.NullProgressMonitor;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.StoredConfig;
 import org.eclipse.jgit.revwalk.RevBlob;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.transport.FetchConnection;
@@ -77,6 +78,9 @@ public void setUp() throws Exception {
 
 		remoteRepository = src.getRepository();
 		remoteURI = toURIish(app, srcGit.getName());
+		StoredConfig cfg = remoteRepository.getConfig();
+		cfg.setInt("protocol", null, "version", 0);
+		cfg.save();
 
 		A_txt = src.blob("A");
 		A = src.commit().add("A_txt", A_txt).create();
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java
index ccde1fe..986b5ca 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java
@@ -35,6 +35,7 @@
 import org.eclipse.jgit.lib.NullProgressMonitor;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.StoredConfig;
 import org.eclipse.jgit.revwalk.RevBlob;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.transport.FetchConnection;
@@ -42,11 +43,10 @@
 import org.eclipse.jgit.transport.Transport;
 import org.eclipse.jgit.transport.TransportHttp;
 import org.eclipse.jgit.transport.URIish;
-import org.eclipse.jgit.transport.http.HttpConnectionFactory;
 import org.junit.Before;
 import org.junit.Test;
 
-public class DumbClientSmartServerTest extends AllFactoriesHttpTestCase {
+public class DumbClientSmartServerTest extends AllProtocolsHttpTestCase {
 	private Repository remoteRepository;
 
 	private URIish remoteURI;
@@ -55,8 +55,8 @@ public class DumbClientSmartServerTest extends AllFactoriesHttpTestCase {
 
 	private RevCommit A, B;
 
-	public DumbClientSmartServerTest(HttpConnectionFactory cf) {
-		super(cf);
+	public DumbClientSmartServerTest(TestParameters params) {
+		super(params);
 	}
 
 	@Override
@@ -76,6 +76,9 @@ public void setUp() throws Exception {
 
 		remoteRepository = src.getRepository();
 		remoteURI = toURIish(app, srcName);
+		StoredConfig cfg = remoteRepository.getConfig();
+		cfg.setInt("protocol", null, "version", enableProtocolV2 ? 2 : 0);
+		cfg.save();
 
 		A_txt = src.blob("A");
 		A = src.commit().add("A_txt", A_txt).create();
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java
index 26a453b..df093c1 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java
@@ -38,7 +38,6 @@
 import org.eclipse.jgit.junit.TestRepository;
 import org.eclipse.jgit.junit.http.AccessEvent;
 import org.eclipse.jgit.junit.http.AppServer;
-import org.eclipse.jgit.lib.ConfigConstants;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.RefUpdate;
@@ -50,7 +49,6 @@
 import org.eclipse.jgit.transport.PacketLineIn;
 import org.eclipse.jgit.transport.PacketLineOut;
 import org.eclipse.jgit.transport.Transport;
-import org.eclipse.jgit.transport.TransferConfig;
 import org.eclipse.jgit.transport.URIish;
 import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
 import org.eclipse.jgit.transport.http.HttpConnection;
@@ -326,7 +324,22 @@ public void testListRemoteWithoutLocalRepository() throws Exception {
 	}
 
 	@Test
-	public void testHttpClientWantsV2ButServerNotConfigured() throws Exception {
+	public void testHttpClientWantsV2AndServerNotConfigured() throws Exception {
+		String url = smartAuthNoneURI.toString() + "/info/refs?service=git-upload-pack";
+		HttpConnection c = HttpTransport.getConnectionFactory()
+				.create(new URL(url));
+		c.setRequestMethod("GET");
+		c.setRequestProperty("Git-Protocol", "version=2");
+		assertEquals(200, c.getResponseCode());
+
+		PacketLineIn pckIn = new PacketLineIn(c.getInputStream());
+		assertThat(pckIn.readString(), is("version 2"));
+	}
+
+	@Test
+	public void testHttpServerConfiguredToV0() throws Exception {
+		remoteRepository.getRepository().getConfig().setInt(
+			"protocol", null, "version", 0);
 		String url = smartAuthNoneURI.toString() + "/info/refs?service=git-upload-pack";
 		HttpConnection c = HttpTransport.getConnectionFactory()
 				.create(new URL(url));
@@ -344,11 +357,6 @@ public void testHttpClientWantsV2ButServerNotConfigured() throws Exception {
 
 	@Test
 	public void testV2HttpFirstResponse() throws Exception {
-		remoteRepository.getRepository().getConfig().setString(
-				ConfigConstants.CONFIG_PROTOCOL_SECTION, null,
-				ConfigConstants.CONFIG_KEY_VERSION,
-				TransferConfig.ProtocolVersion.V2.version());
-
 		String url = smartAuthNoneURI.toString() + "/info/refs?service=git-upload-pack";
 		HttpConnection c = HttpTransport.getConnectionFactory()
 				.create(new URL(url));
@@ -368,11 +376,6 @@ public void testV2HttpFirstResponse() throws Exception {
 
 	@Test
 	public void testV2HttpSubsequentResponse() throws Exception {
-		remoteRepository.getRepository().getConfig().setString(
-				ConfigConstants.CONFIG_PROTOCOL_SECTION, null,
-				ConfigConstants.CONFIG_KEY_VERSION,
-				TransferConfig.ProtocolVersion.V2.version());
-
 		String url = smartAuthNoneURI.toString() + "/git-upload-pack";
 		HttpConnection c = HttpTransport.getConnectionFactory()
 				.create(new URL(url));
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerSslTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerSslTest.java
index 597fb2e..7bc50ca 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerSslTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerSslTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 Thomas Wolf <thomas.wolf@paranor.ch> and others
+ * Copyright (C) 2017, 2020 Thomas Wolf <thomas.wolf@paranor.ch> 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
@@ -41,6 +41,7 @@
 import org.eclipse.jgit.lib.ConfigConstants;
 import org.eclipse.jgit.lib.NullProgressMonitor;
 import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.StoredConfig;
 import org.eclipse.jgit.revwalk.RevBlob;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.transport.CredentialItem;
@@ -48,7 +49,6 @@
 import org.eclipse.jgit.transport.Transport;
 import org.eclipse.jgit.transport.URIish;
 import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
-import org.eclipse.jgit.transport.http.HttpConnectionFactory;
 import org.eclipse.jgit.util.HttpSupport;
 import org.junit.Before;
 import org.junit.Test;
@@ -56,7 +56,7 @@
 import org.junit.runners.Parameterized;
 
 @RunWith(Parameterized.class)
-public class SmartClientSmartServerSslTest extends AllFactoriesHttpTestCase {
+public class SmartClientSmartServerSslTest extends AllProtocolsHttpTestCase {
 
 	// We run these tests with a server on localhost with a self-signed
 	// certificate. We don't do authentication tests here, so there's no need
@@ -112,8 +112,8 @@ public boolean get(URIish uri, CredentialItem... items)
 
 	private RevCommit A, B;
 
-	public SmartClientSmartServerSslTest(HttpConnectionFactory cf) {
-		super(cf);
+	public SmartClientSmartServerSslTest(TestParameters params) {
+		super(params);
 	}
 
 	@Override
@@ -128,10 +128,11 @@ public void setUp() throws Exception {
 
 		final TestRepository<Repository> src = createTestRepository();
 		final String srcName = src.getRepository().getDirectory().getName();
-		src.getRepository()
-				.getConfig()
-				.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
-						ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, true);
+		StoredConfig cfg = src.getRepository().getConfig();
+		cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
+				ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, true);
+		cfg.setInt("protocol", null, "version", enableProtocolV2 ? 2 : 0);
+		cfg.save();
 
 		GitServlet gs = new GitServlet();
 
@@ -238,7 +239,7 @@ public void testInitialClone_ViaHttps() throws Exception {
 		fsck(dst, B);
 
 		List<AccessEvent> requests = getRequests();
-		assertEquals(2, requests.size());
+		assertEquals(enableProtocolV2 ? 3 : 2, requests.size());
 	}
 
 	@Test
@@ -256,7 +257,7 @@ public void testInitialClone_RedirectToHttps() throws Exception {
 		fsck(dst, B);
 
 		List<AccessEvent> requests = getRequests();
-		assertEquals(3, requests.size());
+		assertEquals(enableProtocolV2 ? 4 : 3, requests.size());
 	}
 
 	@Test
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java
index 8d1870a..887e970 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010, 2017 Google Inc. and others
+ * Copyright (C) 2010, 2020 Google Inc. 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
@@ -22,10 +22,17 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import java.io.ByteArrayOutputStream;
+import java.io.File;
 import java.io.IOException;
+import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
+import java.io.Writer;
+import java.net.Proxy;
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
 import java.text.MessageFormat;
 import java.util.Collections;
 import java.util.EnumSet;
@@ -48,6 +55,8 @@
 import org.eclipse.jetty.servlet.FilterHolder;
 import org.eclipse.jetty.servlet.ServletContextHandler;
 import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.TransportConfigCallback;
 import org.eclipse.jgit.errors.RemoteRepositoryException;
 import org.eclipse.jgit.errors.TransportException;
 import org.eclipse.jgit.errors.UnsupportedCredentialItem;
@@ -70,6 +79,7 @@
 import org.eclipse.jgit.lib.ReflogReader;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.lib.TextProgressMonitor;
 import org.eclipse.jgit.revwalk.RevBlob;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevWalk;
@@ -86,13 +96,14 @@
 import org.eclipse.jgit.transport.URIish;
 import org.eclipse.jgit.transport.UploadPack;
 import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
+import org.eclipse.jgit.transport.http.HttpConnection;
 import org.eclipse.jgit.transport.http.HttpConnectionFactory;
 import org.eclipse.jgit.util.HttpSupport;
 import org.eclipse.jgit.util.SystemReader;
 import org.junit.Before;
 import org.junit.Test;
 
-public class SmartClientSmartServerTest extends AllFactoriesHttpTestCase {
+public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase {
 	private static final String HDR_TRANSFER_ENCODING = "Transfer-Encoding";
 
 	private AdvertiseRefsHook advertiseRefsHook;
@@ -120,8 +131,8 @@ public class SmartClientSmartServerTest extends AllFactoriesHttpTestCase {
 
 	private RevCommit A, B, unreachableCommit;
 
-	public SmartClientSmartServerTest(HttpConnectionFactory cf) {
-		super(cf);
+	public SmartClientSmartServerTest(TestParameters params) {
+		super(params);
 	}
 
 	@Override
@@ -131,10 +142,11 @@ public void setUp() throws Exception {
 
 		final TestRepository<Repository> src = createTestRepository();
 		final String srcName = src.getRepository().getDirectory().getName();
-		src.getRepository()
-				.getConfig()
-				.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
-						ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, true);
+		StoredConfig cfg = src.getRepository().getConfig();
+		cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
+				ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, true);
+		cfg.setInt("protocol", null, "version", enableProtocolV2 ? 2 : 0);
+		cfg.save();
 
 		GitServlet gs = new GitServlet();
 		gs.setUploadPackFactory((HttpServletRequest req, Repository db) -> {
@@ -448,7 +460,7 @@ public void testListRemote() throws IOException {
 		assertEquals(B, map.get(Constants.HEAD).getObjectId());
 
 		List<AccessEvent> requests = getRequests();
-		assertEquals(1, requests.size());
+		assertEquals(enableProtocolV2 ? 2 : 1, requests.size());
 
 		AccessEvent info = requests.get(0);
 		assertEquals("GET", info.getMethod());
@@ -458,7 +470,22 @@ public void testListRemote() throws IOException {
 		assertEquals(200, info.getStatus());
 		assertEquals("application/x-git-upload-pack-advertisement", info
 				.getResponseHeader(HDR_CONTENT_TYPE));
-		assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
+		if (!enableProtocolV2) {
+			assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
+		} else {
+			AccessEvent lsRefs = requests.get(1);
+			assertEquals("POST", lsRefs.getMethod());
+			assertEquals(join(remoteURI, "git-upload-pack"), lsRefs.getPath());
+			assertEquals(0, lsRefs.getParameters().size());
+			assertNotNull("has content-length",
+					lsRefs.getRequestHeader(HDR_CONTENT_LENGTH));
+			assertNull("not chunked",
+					lsRefs.getRequestHeader(HDR_TRANSFER_ENCODING));
+			assertEquals("version=2", lsRefs.getRequestHeader("Git-Protocol"));
+			assertEquals(200, lsRefs.getStatus());
+			assertEquals("application/x-git-upload-pack-result",
+					lsRefs.getResponseHeader(HDR_CONTENT_TYPE));
+		}
 	}
 
 	@Test
@@ -576,9 +603,10 @@ public void testInitialClone_Small() throws Exception {
 		}
 
 		List<AccessEvent> requests = getRequests();
-		assertEquals(2, requests.size());
+		assertEquals(enableProtocolV2 ? 3 : 2, requests.size());
 
-		AccessEvent info = requests.get(0);
+		int requestNumber = 0;
+		AccessEvent info = requests.get(requestNumber++);
 		assertEquals("GET", info.getMethod());
 		assertEquals(join(remoteURI, "info/refs"), info.getPath());
 		assertEquals(1, info.getParameters().size());
@@ -586,9 +614,24 @@ public void testInitialClone_Small() throws Exception {
 		assertEquals(200, info.getStatus());
 		assertEquals("application/x-git-upload-pack-advertisement", info
 				.getResponseHeader(HDR_CONTENT_TYPE));
-		assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
+		if (!enableProtocolV2) {
+			assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
+		} else {
+			AccessEvent lsRefs = requests.get(requestNumber++);
+			assertEquals("POST", lsRefs.getMethod());
+			assertEquals(join(remoteURI, "git-upload-pack"), lsRefs.getPath());
+			assertEquals(0, lsRefs.getParameters().size());
+			assertNotNull("has content-length",
+					lsRefs.getRequestHeader(HDR_CONTENT_LENGTH));
+			assertNull("not chunked",
+					lsRefs.getRequestHeader(HDR_TRANSFER_ENCODING));
+			assertEquals("version=2", lsRefs.getRequestHeader("Git-Protocol"));
+			assertEquals(200, lsRefs.getStatus());
+			assertEquals("application/x-git-upload-pack-result",
+					lsRefs.getResponseHeader(HDR_CONTENT_TYPE));
+		}
 
-		AccessEvent service = requests.get(1);
+		AccessEvent service = requests.get(requestNumber);
 		assertEquals("POST", service.getMethod());
 		assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
 		assertEquals(0, service.getParameters().size());
@@ -602,6 +645,63 @@ public void testInitialClone_Small() throws Exception {
 				.getResponseHeader(HDR_CONTENT_TYPE));
 	}
 
+	@Test
+	public void test_CloneWithCustomFactory() throws Exception {
+		HttpConnectionFactory globalFactory = HttpTransport
+				.getConnectionFactory();
+		HttpConnectionFactory failingConnectionFactory = new HttpConnectionFactory() {
+
+			@Override
+			public HttpConnection create(URL url) throws IOException {
+				throw new IOException("Should not be reached");
+			}
+
+			@Override
+			public HttpConnection create(URL url, Proxy proxy)
+					throws IOException {
+				throw new IOException("Should not be reached");
+			}
+		};
+		HttpTransport.setConnectionFactory(failingConnectionFactory);
+		try {
+			File tmp = createTempDirectory("cloneViaApi");
+			boolean[] localFactoryUsed = { false };
+			TransportConfigCallback callback = new TransportConfigCallback() {
+
+				@Override
+				public void configure(Transport transport) {
+					if (transport instanceof TransportHttp) {
+						((TransportHttp) transport).setHttpConnectionFactory(
+								new HttpConnectionFactory() {
+
+									@Override
+									public HttpConnection create(URL url)
+											throws IOException {
+										localFactoryUsed[0] = true;
+										return globalFactory.create(url);
+									}
+
+									@Override
+									public HttpConnection create(URL url,
+											Proxy proxy) throws IOException {
+										localFactoryUsed[0] = true;
+										return globalFactory.create(url, proxy);
+									}
+								});
+					}
+				}
+			};
+			try (Git git = Git.cloneRepository().setDirectory(tmp)
+					.setTransportConfigCallback(callback)
+					.setURI(remoteURI.toPrivateString()).call()) {
+				assertTrue("Should have used the local HttpConnectionFactory",
+						localFactoryUsed[0]);
+			}
+		} finally {
+			HttpTransport.setConnectionFactory(globalFactory);
+		}
+	}
+
 	private void initialClone_Redirect(int nofRedirects, int code)
 			throws Exception {
 		initialClone_Redirect(nofRedirects, code, false);
@@ -628,7 +728,8 @@ private void initialClone_Redirect(int nofRedirects, int code,
 		}
 
 		List<AccessEvent> requests = getRequests();
-		assertEquals(2 + nofRedirects, requests.size());
+		assertEquals((enableProtocolV2 ? 3 : 2) + nofRedirects,
+				requests.size());
 
 		int n = 0;
 		while (n < nofRedirects) {
@@ -644,7 +745,22 @@ private void initialClone_Redirect(int nofRedirects, int code,
 		assertEquals(200, info.getStatus());
 		assertEquals("application/x-git-upload-pack-advertisement",
 				info.getResponseHeader(HDR_CONTENT_TYPE));
-		assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
+		if (!enableProtocolV2) {
+			assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
+		} else {
+			AccessEvent lsRefs = requests.get(n++);
+			assertEquals("POST", lsRefs.getMethod());
+			assertEquals(join(remoteURI, "git-upload-pack"), lsRefs.getPath());
+			assertEquals(0, lsRefs.getParameters().size());
+			assertNotNull("has content-length",
+					lsRefs.getRequestHeader(HDR_CONTENT_LENGTH));
+			assertNull("not chunked",
+					lsRefs.getRequestHeader(HDR_TRANSFER_ENCODING));
+			assertEquals("version=2", lsRefs.getRequestHeader("Git-Protocol"));
+			assertEquals(200, lsRefs.getStatus());
+			assertEquals("application/x-git-upload-pack-result",
+					lsRefs.getResponseHeader(HDR_CONTENT_TYPE));
+		}
 
 		AccessEvent service = requests.get(n++);
 		assertEquals("POST", service.getMethod());
@@ -756,7 +872,7 @@ public void testInitialClone_RedirectOnPostAllowed() throws Exception {
 		}
 
 		List<AccessEvent> requests = getRequests();
-		assertEquals(3, requests.size());
+		assertEquals(enableProtocolV2 ? 4 : 3, requests.size());
 
 		AccessEvent info = requests.get(0);
 		assertEquals("GET", info.getMethod());
@@ -766,24 +882,27 @@ public void testInitialClone_RedirectOnPostAllowed() throws Exception {
 		assertEquals(200, info.getStatus());
 		assertEquals("application/x-git-upload-pack-advertisement",
 				info.getResponseHeader(HDR_CONTENT_TYPE));
-		assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
+		if (!enableProtocolV2) {
+			assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
+		}
 
 		AccessEvent redirect = requests.get(1);
 		assertEquals("POST", redirect.getMethod());
 		assertEquals(301, redirect.getStatus());
 
-		AccessEvent service = requests.get(2);
-		assertEquals("POST", service.getMethod());
-		assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
-		assertEquals(0, service.getParameters().size());
-		assertNotNull("has content-length",
-				service.getRequestHeader(HDR_CONTENT_LENGTH));
-		assertNull("not chunked",
-				service.getRequestHeader(HDR_TRANSFER_ENCODING));
-
-		assertEquals(200, service.getStatus());
-		assertEquals("application/x-git-upload-pack-result",
-				service.getResponseHeader(HDR_CONTENT_TYPE));
+		for (int i = 2; i < requests.size(); i++) {
+			AccessEvent service = requests.get(i);
+			assertEquals("POST", service.getMethod());
+			assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
+			assertEquals(0, service.getParameters().size());
+			assertNotNull("has content-length",
+					service.getRequestHeader(HDR_CONTENT_LENGTH));
+			assertNull("not chunked",
+					service.getRequestHeader(HDR_TRANSFER_ENCODING));
+			assertEquals(200, service.getStatus());
+			assertEquals("application/x-git-upload-pack-result",
+					service.getResponseHeader(HDR_CONTENT_TYPE));
+		}
 	}
 
 	@Test
@@ -817,6 +936,35 @@ public void testInitialClone_RedirectForbidden() throws Exception {
 		}
 	}
 
+	private void assertFetchRequests(List<AccessEvent> requests, int index) {
+		AccessEvent info = requests.get(index++);
+		assertEquals("GET", info.getMethod());
+		assertEquals(join(authURI, "info/refs"), info.getPath());
+		assertEquals(1, info.getParameters().size());
+		assertEquals("git-upload-pack", info.getParameter("service"));
+		assertEquals(200, info.getStatus());
+		assertEquals("application/x-git-upload-pack-advertisement",
+				info.getResponseHeader(HDR_CONTENT_TYPE));
+		if (!enableProtocolV2) {
+			assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
+		}
+
+		for (int i = index; i < requests.size(); i++) {
+			AccessEvent service = requests.get(i);
+			assertEquals("POST", service.getMethod());
+			assertEquals(join(authURI, "git-upload-pack"), service.getPath());
+			assertEquals(0, service.getParameters().size());
+			assertNotNull("has content-length",
+					service.getRequestHeader(HDR_CONTENT_LENGTH));
+			assertNull("not chunked",
+					service.getRequestHeader(HDR_TRANSFER_ENCODING));
+
+			assertEquals(200, service.getStatus());
+			assertEquals("application/x-git-upload-pack-result",
+					service.getResponseHeader(HDR_CONTENT_TYPE));
+		}
+	}
+
 	@Test
 	public void testInitialClone_WithAuthentication() throws Exception {
 		try (Repository dst = createBareRepository();
@@ -830,34 +978,167 @@ public void testInitialClone_WithAuthentication() throws Exception {
 		}
 
 		List<AccessEvent> requests = getRequests();
-		assertEquals(3, requests.size());
+		assertEquals(enableProtocolV2 ? 4 : 3, requests.size());
 
 		AccessEvent info = requests.get(0);
 		assertEquals("GET", info.getMethod());
 		assertEquals(401, info.getStatus());
 
-		info = requests.get(1);
+		assertFetchRequests(requests, 1);
+	}
+
+	@Test
+	public void testInitialClone_WithPreAuthentication() throws Exception {
+		try (Repository dst = createBareRepository();
+				Transport t = Transport.open(dst, authURI)) {
+			assertFalse(dst.getObjectDatabase().has(A_txt));
+			((TransportHttp) t).setPreemptiveBasicAuthentication(
+					AppServer.username, AppServer.password);
+			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
+			assertTrue(dst.getObjectDatabase().has(A_txt));
+			assertEquals(B, dst.exactRef(master).getObjectId());
+			fsck(dst, B);
+		}
+
+		List<AccessEvent> requests = getRequests();
+		assertEquals(enableProtocolV2 ? 3 : 2, requests.size());
+
+		assertFetchRequests(requests, 0);
+	}
+
+	@Test
+	public void testInitialClone_WithPreAuthenticationCleared()
+			throws Exception {
+		try (Repository dst = createBareRepository();
+				Transport t = Transport.open(dst, authURI)) {
+			assertFalse(dst.getObjectDatabase().has(A_txt));
+			((TransportHttp) t).setPreemptiveBasicAuthentication(
+					AppServer.username, AppServer.password);
+			((TransportHttp) t).setPreemptiveBasicAuthentication(null, null);
+			t.setCredentialsProvider(testCredentials);
+			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
+			assertTrue(dst.getObjectDatabase().has(A_txt));
+			assertEquals(B, dst.exactRef(master).getObjectId());
+			fsck(dst, B);
+		}
+
+		List<AccessEvent> requests = getRequests();
+		assertEquals(enableProtocolV2 ? 4 : 3, requests.size());
+
+		AccessEvent info = requests.get(0);
 		assertEquals("GET", info.getMethod());
-		assertEquals(join(authURI, "info/refs"), info.getPath());
-		assertEquals(1, info.getParameters().size());
-		assertEquals("git-upload-pack", info.getParameter("service"));
-		assertEquals(200, info.getStatus());
-		assertEquals("application/x-git-upload-pack-advertisement",
-				info.getResponseHeader(HDR_CONTENT_TYPE));
-		assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
+		assertEquals(401, info.getStatus());
 
-		AccessEvent service = requests.get(2);
-		assertEquals("POST", service.getMethod());
-		assertEquals(join(authURI, "git-upload-pack"), service.getPath());
-		assertEquals(0, service.getParameters().size());
-		assertNotNull("has content-length",
-				service.getRequestHeader(HDR_CONTENT_LENGTH));
-		assertNull("not chunked",
-				service.getRequestHeader(HDR_TRANSFER_ENCODING));
+		assertFetchRequests(requests, 1);
+	}
 
-		assertEquals(200, service.getStatus());
-		assertEquals("application/x-git-upload-pack-result",
-				service.getResponseHeader(HDR_CONTENT_TYPE));
+	@Test
+	public void testInitialClone_PreAuthenticationTooLate() throws Exception {
+		try (Repository dst = createBareRepository();
+				Transport t = Transport.open(dst, authURI)) {
+			assertFalse(dst.getObjectDatabase().has(A_txt));
+			((TransportHttp) t).setPreemptiveBasicAuthentication(
+					AppServer.username, AppServer.password);
+			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
+			assertTrue(dst.getObjectDatabase().has(A_txt));
+			assertEquals(B, dst.exactRef(master).getObjectId());
+			fsck(dst, B);
+			List<AccessEvent> requests = getRequests();
+			assertEquals(enableProtocolV2 ? 3 : 2, requests.size());
+			assertFetchRequests(requests, 0);
+			assertThrows(IllegalStateException.class,
+					() -> ((TransportHttp) t).setPreemptiveBasicAuthentication(
+							AppServer.username, AppServer.password));
+			assertThrows(IllegalStateException.class, () -> ((TransportHttp) t)
+					.setPreemptiveBasicAuthentication(null, null));
+		}
+	}
+
+	@Test
+	public void testInitialClone_WithWrongPreAuthenticationAndCredentialProvider()
+			throws Exception {
+		try (Repository dst = createBareRepository();
+				Transport t = Transport.open(dst, authURI)) {
+			assertFalse(dst.getObjectDatabase().has(A_txt));
+			((TransportHttp) t).setPreemptiveBasicAuthentication(
+					AppServer.username, AppServer.password + 'x');
+			t.setCredentialsProvider(testCredentials);
+			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
+			assertTrue(dst.getObjectDatabase().has(A_txt));
+			assertEquals(B, dst.exactRef(master).getObjectId());
+			fsck(dst, B);
+		}
+
+		List<AccessEvent> requests = getRequests();
+		assertEquals(enableProtocolV2 ? 4 : 3, requests.size());
+
+		AccessEvent info = requests.get(0);
+		assertEquals("GET", info.getMethod());
+		assertEquals(401, info.getStatus());
+
+		assertFetchRequests(requests, 1);
+	}
+
+	@Test
+	public void testInitialClone_WithWrongPreAuthentication() throws Exception {
+		try (Repository dst = createBareRepository();
+				Transport t = Transport.open(dst, authURI)) {
+			assertFalse(dst.getObjectDatabase().has(A_txt));
+			((TransportHttp) t).setPreemptiveBasicAuthentication(
+					AppServer.username, AppServer.password + 'x');
+			TransportException e = assertThrows(TransportException.class,
+					() -> t.fetch(NullProgressMonitor.INSTANCE,
+							mirror(master)));
+			String msg = e.getMessage();
+			assertTrue("Unexpected exception message: " + msg,
+					msg.contains("no CredentialsProvider"));
+		}
+		List<AccessEvent> requests = getRequests();
+		assertEquals(1, requests.size());
+
+		AccessEvent info = requests.get(0);
+		assertEquals("GET", info.getMethod());
+		assertEquals(401, info.getStatus());
+	}
+
+	@Test
+	public void testInitialClone_WithUserInfo() throws Exception {
+		URIish withUserInfo = authURI.setUser(AppServer.username)
+				.setPass(AppServer.password);
+		try (Repository dst = createBareRepository();
+				Transport t = Transport.open(dst, withUserInfo)) {
+			assertFalse(dst.getObjectDatabase().has(A_txt));
+			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
+			assertTrue(dst.getObjectDatabase().has(A_txt));
+			assertEquals(B, dst.exactRef(master).getObjectId());
+			fsck(dst, B);
+		}
+
+		List<AccessEvent> requests = getRequests();
+		assertEquals(enableProtocolV2 ? 3 : 2, requests.size());
+
+		assertFetchRequests(requests, 0);
+	}
+
+	@Test
+	public void testInitialClone_PreAuthOverridesUserInfo() throws Exception {
+		URIish withUserInfo = authURI.setUser(AppServer.username)
+				.setPass(AppServer.password + 'x');
+		try (Repository dst = createBareRepository();
+				Transport t = Transport.open(dst, withUserInfo)) {
+			assertFalse(dst.getObjectDatabase().has(A_txt));
+			((TransportHttp) t).setPreemptiveBasicAuthentication(
+					AppServer.username, AppServer.password);
+			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
+			assertTrue(dst.getObjectDatabase().has(A_txt));
+			assertEquals(B, dst.exactRef(master).getObjectId());
+			fsck(dst, B);
+		}
+
+		List<AccessEvent> requests = getRequests();
+		assertEquals(enableProtocolV2 ? 3 : 2, requests.size());
+
+		assertFetchRequests(requests, 0);
 	}
 
 	@Test
@@ -937,19 +1218,20 @@ public boolean get(URIish uri, CredentialItem... items)
 		}
 
 		List<AccessEvent> requests = getRequests();
-		assertEquals(4, requests.size());
+		assertEquals(enableProtocolV2 ? 5 : 4, requests.size());
 
-		AccessEvent redirect = requests.get(0);
+		int requestNumber = 0;
+		AccessEvent redirect = requests.get(requestNumber++);
 		assertEquals("GET", redirect.getMethod());
 		assertEquals(join(cloneFrom, "info/refs"), redirect.getPath());
 		assertEquals(301, redirect.getStatus());
 
-		AccessEvent info = requests.get(1);
+		AccessEvent info = requests.get(requestNumber++);
 		assertEquals("GET", info.getMethod());
 		assertEquals(join(authURI, "info/refs"), info.getPath());
 		assertEquals(401, info.getStatus());
 
-		info = requests.get(2);
+		info = requests.get(requestNumber++);
 		assertEquals("GET", info.getMethod());
 		assertEquals(join(authURI, "info/refs"), info.getPath());
 		assertEquals(1, info.getParameters().size());
@@ -957,9 +1239,24 @@ public boolean get(URIish uri, CredentialItem... items)
 		assertEquals(200, info.getStatus());
 		assertEquals("application/x-git-upload-pack-advertisement",
 				info.getResponseHeader(HDR_CONTENT_TYPE));
-		assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
+		if (!enableProtocolV2) {
+			assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
+		} else {
+			AccessEvent lsRefs = requests.get(requestNumber++);
+			assertEquals("POST", lsRefs.getMethod());
+			assertEquals(join(authURI, "git-upload-pack"), lsRefs.getPath());
+			assertEquals(0, lsRefs.getParameters().size());
+			assertNotNull("has content-length",
+					lsRefs.getRequestHeader(HDR_CONTENT_LENGTH));
+			assertNull("not chunked",
+					lsRefs.getRequestHeader(HDR_TRANSFER_ENCODING));
+			assertEquals("version=2", lsRefs.getRequestHeader("Git-Protocol"));
+			assertEquals(200, lsRefs.getStatus());
+			assertEquals("application/x-git-upload-pack-result",
+					lsRefs.getResponseHeader(HDR_CONTENT_TYPE));
+		}
 
-		AccessEvent service = requests.get(3);
+		AccessEvent service = requests.get(requestNumber);
 		assertEquals("POST", service.getMethod());
 		assertEquals(join(authURI, "git-upload-pack"), service.getPath());
 		assertEquals(0, service.getParameters().size());
@@ -987,7 +1284,7 @@ public void testInitialClone_WithAuthenticationOnPostOnly()
 		}
 
 		List<AccessEvent> requests = getRequests();
-		assertEquals(3, requests.size());
+		assertEquals(enableProtocolV2 ? 4 : 3, requests.size());
 
 		AccessEvent info = requests.get(0);
 		assertEquals("GET", info.getMethod());
@@ -997,25 +1294,30 @@ public void testInitialClone_WithAuthenticationOnPostOnly()
 		assertEquals(200, info.getStatus());
 		assertEquals("application/x-git-upload-pack-advertisement",
 				info.getResponseHeader(HDR_CONTENT_TYPE));
-		assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
+		if (!enableProtocolV2) {
+			assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
+		}
 
 		AccessEvent service = requests.get(1);
 		assertEquals("POST", service.getMethod());
 		assertEquals(join(authOnPostURI, "git-upload-pack"), service.getPath());
 		assertEquals(401, service.getStatus());
 
-		service = requests.get(2);
-		assertEquals("POST", service.getMethod());
-		assertEquals(join(authOnPostURI, "git-upload-pack"), service.getPath());
-		assertEquals(0, service.getParameters().size());
-		assertNotNull("has content-length",
-				service.getRequestHeader(HDR_CONTENT_LENGTH));
-		assertNull("not chunked",
-				service.getRequestHeader(HDR_TRANSFER_ENCODING));
+		for (int i = 2; i < requests.size(); i++) {
+			service = requests.get(i);
+			assertEquals("POST", service.getMethod());
+			assertEquals(join(authOnPostURI, "git-upload-pack"),
+					service.getPath());
+			assertEquals(0, service.getParameters().size());
+			assertNotNull("has content-length",
+					service.getRequestHeader(HDR_CONTENT_LENGTH));
+			assertNull("not chunked",
+					service.getRequestHeader(HDR_TRANSFER_ENCODING));
 
-		assertEquals(200, service.getStatus());
-		assertEquals("application/x-git-upload-pack-result",
-				service.getResponseHeader(HDR_CONTENT_TYPE));
+			assertEquals(200, service.getStatus());
+			assertEquals("application/x-git-upload-pack-result",
+					service.getResponseHeader(HDR_CONTENT_TYPE));
+		}
 	}
 
 	@Test
@@ -1052,9 +1354,11 @@ public void testFetch_FewLocalCommits() throws Exception {
 
 		List<AccessEvent> requests = getRequests();
 		requests.removeAll(cloneRequests);
-		assertEquals(2, requests.size());
 
-		AccessEvent info = requests.get(0);
+		assertEquals(enableProtocolV2 ? 3 : 2, requests.size());
+
+		int requestNumber = 0;
+		AccessEvent info = requests.get(requestNumber++);
 		assertEquals("GET", info.getMethod());
 		assertEquals(join(remoteURI, "info/refs"), info.getPath());
 		assertEquals(1, info.getParameters().size());
@@ -1063,9 +1367,24 @@ public void testFetch_FewLocalCommits() throws Exception {
 		assertEquals("application/x-git-upload-pack-advertisement",
 				info.getResponseHeader(HDR_CONTENT_TYPE));
 
+		if (enableProtocolV2) {
+			AccessEvent lsRefs = requests.get(requestNumber++);
+			assertEquals("POST", lsRefs.getMethod());
+			assertEquals(join(remoteURI, "git-upload-pack"), lsRefs.getPath());
+			assertEquals(0, lsRefs.getParameters().size());
+			assertNotNull("has content-length",
+					lsRefs.getRequestHeader(HDR_CONTENT_LENGTH));
+			assertNull("not chunked",
+					lsRefs.getRequestHeader(HDR_TRANSFER_ENCODING));
+			assertEquals("version=2", lsRefs.getRequestHeader("Git-Protocol"));
+			assertEquals(200, lsRefs.getStatus());
+			assertEquals("application/x-git-upload-pack-result",
+					lsRefs.getResponseHeader(HDR_CONTENT_TYPE));
+		}
+
 		// We should have needed one request to perform the fetch.
 		//
-		AccessEvent service = requests.get(1);
+		AccessEvent service = requests.get(requestNumber);
 		assertEquals("POST", service.getMethod());
 		assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
 		assertEquals(0, service.getParameters().size());
@@ -1116,9 +1435,10 @@ public void testFetch_TooManyLocalCommits() throws Exception {
 
 		List<AccessEvent> requests = getRequests();
 		requests.removeAll(cloneRequests);
-		assertEquals(3, requests.size());
+		assertEquals(enableProtocolV2 ? 4 : 3, requests.size());
 
-		AccessEvent info = requests.get(0);
+		int requestNumber = 0;
+		AccessEvent info = requests.get(requestNumber++);
 		assertEquals("GET", info.getMethod());
 		assertEquals(join(remoteURI, "info/refs"), info.getPath());
 		assertEquals(1, info.getParameters().size());
@@ -1127,10 +1447,25 @@ public void testFetch_TooManyLocalCommits() throws Exception {
 		assertEquals("application/x-git-upload-pack-advertisement", info
 				.getResponseHeader(HDR_CONTENT_TYPE));
 
+		if (enableProtocolV2) {
+			AccessEvent lsRefs = requests.get(requestNumber++);
+			assertEquals("POST", lsRefs.getMethod());
+			assertEquals(join(remoteURI, "git-upload-pack"), lsRefs.getPath());
+			assertEquals(0, lsRefs.getParameters().size());
+			assertNotNull("has content-length",
+					lsRefs.getRequestHeader(HDR_CONTENT_LENGTH));
+			assertNull("not chunked",
+					lsRefs.getRequestHeader(HDR_TRANSFER_ENCODING));
+			assertEquals("version=2", lsRefs.getRequestHeader("Git-Protocol"));
+			assertEquals(200, lsRefs.getStatus());
+			assertEquals("application/x-git-upload-pack-result",
+					lsRefs.getResponseHeader(HDR_CONTENT_TYPE));
+		}
+
 		// We should have needed two requests to perform the fetch
 		// due to the high number of local unknown commits.
 		//
-		AccessEvent service = requests.get(1);
+		AccessEvent service = requests.get(requestNumber++);
 		assertEquals("POST", service.getMethod());
 		assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
 		assertEquals(0, service.getParameters().size());
@@ -1143,7 +1478,7 @@ public void testFetch_TooManyLocalCommits() throws Exception {
 		assertEquals("application/x-git-upload-pack-result", service
 				.getResponseHeader(HDR_CONTENT_TYPE));
 
-		service = requests.get(2);
+		service = requests.get(requestNumber);
 		assertEquals("POST", service.getMethod());
 		assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
 		assertEquals(0, service.getParameters().size());
@@ -1158,6 +1493,64 @@ public void testFetch_TooManyLocalCommits() throws Exception {
 	}
 
 	@Test
+	public void testFetch_MaxHavesCutoffAfterAckOnly() throws Exception {
+		// Bootstrap by doing the clone.
+		//
+		TestRepository dst = createTestRepository();
+		try (Transport t = Transport.open(dst.getRepository(), remoteURI)) {
+			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
+		}
+		assertEquals(B, dst.getRepository().exactRef(master).getObjectId());
+
+		// Force enough into the local client that enumeration will
+		// need more than MAX_HAVES (256) haves to be sent. The server
+		// doesn't know any of these, so it will never ACK. The client
+		// should keep going.
+		//
+		// If it does, client and server will find a common commit, and
+		// the pack file will contain exactly the one commit object Z
+		// we create on the remote, which we can test for via the progress
+		// monitor, which should have something like
+		// "Receiving objects: 100% (1/1)". If the client sends a "done"
+		// too early, the server will send more objects, and we'll have
+		// a line like "Receiving objects: 100% (8/8)".
+		TestRepository.BranchBuilder b = dst.branch(master);
+		// The client will send 32 + 64 + 128 + 256 + 512 haves. Only the
+		// last one will be a common commit. If the cutoff kicks in too
+		// early (after 480), we'll get too many objects in the fetch.
+		for (int i = 0; i < 992; i++)
+			b.commit().tick(3600 /* 1 hour */).message("c" + i).create();
+
+		// Create a new commit on the remote.
+		//
+		RevCommit Z;
+		try (TestRepository<Repository> tr = new TestRepository<>(
+				remoteRepository)) {
+			b = tr.branch(master);
+			Z = b.commit().message("Z").create();
+		}
+
+		// Now incrementally update.
+		//
+		ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+		Writer writer = new OutputStreamWriter(buffer, StandardCharsets.UTF_8);
+		TextProgressMonitor monitor = new TextProgressMonitor(writer);
+		try (Transport t = Transport.open(dst.getRepository(), remoteURI)) {
+			t.fetch(monitor, mirror(master));
+		}
+		assertEquals(Z, dst.getRepository().exactRef(master).getObjectId());
+
+		String progressMessages = new String(buffer.toByteArray(),
+				StandardCharsets.UTF_8);
+		Pattern expected = Pattern
+				.compile("Receiving objects:\\s+100% \\(1/1\\)\n");
+		if (!expected.matcher(progressMessages).find()) {
+			System.out.println(progressMessages);
+			fail("Expected only one object to be sent");
+		}
+	}
+
+	@Test
 	public void testInitialClone_BrokenServer() throws Exception {
 		try (Repository dst = createBareRepository();
 				Transport t = Transport.open(dst, brokenURI)) {
@@ -1211,7 +1604,8 @@ public void testInvalidWant() throws Exception {
 					Collections.<ObjectId> emptySet());
 			fail("Server accepted want " + id.name());
 		} catch (TransportException err) {
-			assertEquals("want " + id.name() + " not valid", err.getMessage());
+			assertTrue(err.getMessage()
+					.contains("want " + id.name() + " not valid"));
 		}
 	}
 
@@ -1224,6 +1618,8 @@ public void testFetch_RefsUnreadableOnUpload() throws Exception {
 					new DfsRepositoryDescription(repoName));
 			final TestRepository<Repository> repo = new TestRepository<>(
 					badRefsRepo);
+			badRefsRepo.getConfig().setInt("protocol", null, "version",
+					enableProtocolV2 ? 2 : 0);
 
 			ServletContextHandler app = noRefServer.addContext("/git");
 			GitServlet gs = new GitServlet();
@@ -1253,7 +1649,8 @@ public void testFetch_RefsUnreadableOnUpload() throws Exception {
 						Collections.<ObjectId> emptySet());
 				fail("Successfully served ref with value " + c.getRef(master));
 			} catch (TransportException err) {
-				assertEquals("Internal server error", err.getMessage());
+				assertTrue("Unexpected exception message " + err.getMessage(),
+						err.getMessage().contains("Internal server error"));
 			}
 		} finally {
 			noRefServer.tearDown();
@@ -1429,5 +1826,4 @@ private void enableReceivePack() throws IOException {
 		cfg.setBoolean("http", null, "receivepack", true);
 		cfg.save();
 	}
-
 }
diff --git a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
index 311cd0b..b6c2cb5 100644
--- a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-Name: %Bundle-Name
 Automatic-Module-Name: org.eclipse.jgit.junit.http
 Bundle-SymbolicName: org.eclipse.jgit.junit.http
-Bundle-Version: 5.10.1.qualifier
+Bundle-Version: 5.11.2.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %Bundle-Vendor
 Bundle-ActivationPolicy: lazy
@@ -22,16 +22,16 @@
  org.eclipse.jetty.util.log;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.util.security;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.util.ssl;version="[9.4.5,10.0.0)",
- org.eclipse.jgit.errors;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.http.server;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.internal.storage.file;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.junit;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lib;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.revwalk;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.transport;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.transport.resolver;version="[5.10.1,5.11.0)",
+ org.eclipse.jgit.errors;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.http.server;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.junit;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.lib;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.revwalk;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.transport;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.transport.resolver;version="[5.11.2,5.12.0)",
  org.junit;version="[4.13,5.0.0)"
-Export-Package: org.eclipse.jgit.junit.http;version="5.10.1";
+Export-Package: org.eclipse.jgit.junit.http;version="5.11.2";
   uses:="org.eclipse.jgit.transport,
    org.eclipse.jgit.junit,
    javax.servlet.http,
diff --git a/org.eclipse.jgit.junit.http/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.junit.http/META-INF/SOURCE-MANIFEST.MF
index de59edd..199e982 100644
--- a/org.eclipse.jgit.junit.http/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.junit.http/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
 Bundle-Name: org.eclipse.jgit.junit.http - Sources
 Bundle-SymbolicName: org.eclipse.jgit.junit.http.source
 Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 5.10.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.junit.http;version="5.10.1.qualifier";roots="."
+Bundle-Version: 5.11.2.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.junit.http;version="5.11.2.qualifier";roots="."
diff --git a/org.eclipse.jgit.junit.http/pom.xml b/org.eclipse.jgit.junit.http/pom.xml
index 25e1c70..eb008b0 100644
--- a/org.eclipse.jgit.junit.http/pom.xml
+++ b/org.eclipse.jgit.junit.http/pom.xml
@@ -17,7 +17,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.10.1-SNAPSHOT</version>
+    <version>5.11.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.junit.http</artifactId>
diff --git a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java
index 9239690..0f05298 100644
--- a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java
+++ b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java
@@ -23,8 +23,8 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
 
 import org.eclipse.jetty.http.HttpVersion;
 import org.eclipse.jetty.security.AbstractLoginService;
@@ -262,7 +262,7 @@ public ServletContextHandler authBasic(ServletContextHandler ctx,
 	static class TestMappedLoginService extends AbstractLoginService {
 		private String role;
 
-		protected final ConcurrentMap<String, UserPrincipal> users = new ConcurrentHashMap<>();
+		protected final Map<String, UserPrincipal> users = new ConcurrentHashMap<>();
 
 		TestMappedLoginService(String role) {
 			this.role = role;
diff --git a/org.eclipse.jgit.junit.ssh/.settings/.api_filters b/org.eclipse.jgit.junit.ssh/.settings/.api_filters
index fb27d49..44c9dfa 100644
--- a/org.eclipse.jgit.junit.ssh/.settings/.api_filters
+++ b/org.eclipse.jgit.junit.ssh/.settings/.api_filters
@@ -5,6 +5,20 @@
             <message_arguments>
                 <message_argument value="org.eclipse.jgit.junit.ssh.SshTestHarness"/>
                 <message_argument value="publicKey2"/>
+    </resource>
+    <resource path="META-INF/MANIFEST.MF">
+        <filter id="923795461">
+            <message_arguments>
+                <message_argument value="5.11.2"/>
+                <message_argument value="5.10.0"/>
+            </message_arguments>
+        </filter>
+    </resource>
+    <resource path="src/org/eclipse/jgit/junit/ssh/SshTestBase.java" type="org.eclipse.jgit.junit.ssh.SshTestBase">
+        <filter id="338792546">
+            <message_arguments>
+                <message_argument value="org.eclipse.jgit.junit.ssh.SshTestBase"/>
+                <message_argument value="testSshWithConfig()"/>
             </message_arguments>
         </filter>
     </resource>
diff --git a/org.eclipse.jgit.junit.ssh/.settings/edu.umd.cs.findbugs.core.prefs b/org.eclipse.jgit.junit.ssh/.settings/edu.umd.cs.findbugs.core.prefs
new file mode 100644
index 0000000..2792ea0
--- /dev/null
+++ b/org.eclipse.jgit.junit.ssh/.settings/edu.umd.cs.findbugs.core.prefs
@@ -0,0 +1,145 @@
+#SpotBugs User Preferences
+#Fri Dec 04 11:26:04 CET 2020
+detectorExplicitSerialization=ExplicitSerialization|true
+detectorMultithreadedInstanceAccess=MultithreadedInstanceAccess|true
+detectorConfusionBetweenInheritedAndOuterMethod=ConfusionBetweenInheritedAndOuterMethod|true
+detectorWrongMapIterator=WrongMapIterator|true
+detectorUnnecessaryMath=UnnecessaryMath|true
+detectorUselessSubclassMethod=UselessSubclassMethod|false
+filter_settings=Medium|BAD_PRACTICE,CORRECTNESS,EXPERIMENTAL,I18N,MALICIOUS_CODE,MT_CORRECTNESS,PERFORMANCE,SECURITY,STYLE|false|15
+detectorURLProblems=URLProblems|true
+detectorIteratorIdioms=IteratorIdioms|true
+detectorMutableEnum=MutableEnum|true
+detectorFindNonShortCircuit=FindNonShortCircuit|true
+detectorSynchronizeAndNullCheckField=SynchronizeAndNullCheckField|true
+detectorVolatileUsage=VolatileUsage|true
+detectorFindNakedNotify=FindNakedNotify|true
+detectorFindUninitializedGet=FindUninitializedGet|true
+detectorFindUseOfNonSerializableValue=FindUseOfNonSerializableValue|true
+detectorFindJSR166LockMonitorenter=FindJSR166LockMonitorenter|true
+detectorQuestionableBooleanAssignment=QuestionableBooleanAssignment|true
+detectorSwitchFallthrough=SwitchFallthrough|true
+detectorFindLocalSelfAssignment2=FindLocalSelfAssignment2|true
+detectorConfusedInheritance=ConfusedInheritance|true
+detectorSynchronizationOnSharedBuiltinConstant=SynchronizationOnSharedBuiltinConstant|true
+detectorMutableStaticFields=MutableStaticFields|true
+detectorInvalidJUnitTest=InvalidJUnitTest|true
+detectorInfiniteLoop=InfiniteLoop|true
+detectorFindRunInvocations=FindRunInvocations|true
+detectorBadSyntaxForRegularExpression=BadSyntaxForRegularExpression|true
+detectorXMLFactoryBypass=XMLFactoryBypass|true
+detectorFindOpenStream=FindOpenStream|true
+detectorCheckExpectedWarnings=CheckExpectedWarnings|false
+detectorHugeSharedStringConstants=HugeSharedStringConstants|true
+detectorLostLoggerDueToWeakReference=LostLoggerDueToWeakReference|true
+detectorStringConcatenation=StringConcatenation|true
+detectorLoadOfKnownNullValue=LoadOfKnownNullValue|true
+detectorFinalizerNullsFields=FinalizerNullsFields|true
+detectorFindFieldSelfAssignment=FindFieldSelfAssignment|true
+detectorInefficientToArray=InefficientToArray|false
+detectorDontCatchIllegalMonitorStateException=DontCatchIllegalMonitorStateException|true
+detectorInconsistentAnnotations=InconsistentAnnotations|true
+detectorBadlyOverriddenAdapter=BadlyOverriddenAdapter|true
+detectorInstantiateStaticClass=InstantiateStaticClass|true
+detectorCheckRelaxingNullnessAnnotation=CheckRelaxingNullnessAnnotation|true
+detectorMethodReturnCheck=MethodReturnCheck|true
+detectorEqualsOperandShouldHaveClassCompatibleWithThis=EqualsOperandShouldHaveClassCompatibleWithThis|true
+detectorFindDoubleCheck=FindDoubleCheck|true
+detectorFindBadForLoop=FindBadForLoop|true
+detectorDefaultEncodingDetector=DefaultEncodingDetector|true
+detectorFindInconsistentSync2=FindInconsistentSync2|true
+detectorFindSpinLoop=FindSpinLoop|true
+detectorFindMaskedFields=FindMaskedFields|true
+detectorBooleanReturnNull=BooleanReturnNull|true
+detectorFindUnsyncGet=FindUnsyncGet|true
+detectorCrossSiteScripting=CrossSiteScripting|true
+detectorDroppedException=DroppedException|true
+detectorFindDeadLocalStores=FindDeadLocalStores|true
+detectorCheckImmutableAnnotation=CheckImmutableAnnotation|true
+detectorInfiniteRecursiveLoop=InfiniteRecursiveLoop|true
+detectorFindRefComparison=FindRefComparison|true
+detectorFindRoughConstants=FindRoughConstants|true
+detectorMutableLock=MutableLock|true
+detectorFindNullDeref=FindNullDeref|true
+detectorFindReturnRef=FindReturnRef|true
+detectorSynchronizeOnClassLiteralNotGetClass=SynchronizeOnClassLiteralNotGetClass|true
+detectorFindUselessControlFlow=FindUselessControlFlow|true
+detectorOverridingEqualsNotSymmetrical=OverridingEqualsNotSymmetrical|true
+detectorIDivResultCastToDouble=IDivResultCastToDouble|true
+detectorReadOfInstanceFieldInMethodInvokedByConstructorInSuperclass=ReadOfInstanceFieldInMethodInvokedByConstructorInSuperclass|true
+detectorFindSelfComparison=FindSelfComparison|true
+detectorFindFloatEquality=FindFloatEquality|true
+detectorFindComparatorProblems=FindComparatorProblems|true
+detectorRepeatedConditionals=RepeatedConditionals|true
+filter_settings_neg=NOISE|
+detectorInefficientMemberAccess=InefficientMemberAccess|false
+detectorFindUncalledPrivateMethods=FindUncalledPrivateMethods|true
+detectorNumberConstructor=NumberConstructor|true
+detectorDontAssertInstanceofInTests=DontAssertInstanceofInTests|true
+detectorFindFinalizeInvocations=FindFinalizeInvocations|true
+detectorFindNullDerefsInvolvingNonShortCircuitEvaluation=FindNullDerefsInvolvingNonShortCircuitEvaluation|true
+detectorDontIgnoreResultOfPutIfAbsent=DontIgnoreResultOfPutIfAbsent|true
+detectorFindUnconditionalWait=FindUnconditionalWait|true
+detectorFindTwoLockWait=FindTwoLockWait|true
+detectorFindSleepWithLockHeld=FindSleepWithLockHeld|true
+detectorFindUnreleasedLock=FindUnreleasedLock|true
+detectorInefficientIndexOf=InefficientIndexOf|false
+detectorDoInsideDoPrivileged=DoInsideDoPrivileged|true
+detectorFindEmptySynchronizedBlock=FindEmptySynchronizedBlock|true
+detectorOverridingMethodsMustInvokeSuperDetector=OverridingMethodsMustInvokeSuperDetector|true
+detectorWaitInLoop=WaitInLoop|true
+detectorIntCast2LongAsInstant=IntCast2LongAsInstant|true
+detectorBadUseOfReturnValue=BadUseOfReturnValue|true
+detectorFindSqlInjection=FindSqlInjection|true
+detectorUnreadFields=UnreadFields|true
+detectorSynchronizingOnContentsOfFieldToProtectField=SynchronizingOnContentsOfFieldToProtectField|true
+detectorFindUselessObjects=FindUselessObjects|true
+detectorBadAppletConstructor=BadAppletConstructor|false
+detectorInheritanceUnsafeGetResource=InheritanceUnsafeGetResource|true
+detectorSerializableIdiom=SerializableIdiom|true
+detectorNaming=Naming|true
+detectorNoteUnconditionalParamDerefs=NoteUnconditionalParamDerefs|true
+detectorFormatStringChecker=FormatStringChecker|true
+detectorSuspiciousThreadInterrupted=SuspiciousThreadInterrupted|true
+detectorEmptyZipFileEntry=EmptyZipFileEntry|false
+detectorFindCircularDependencies=FindCircularDependencies|false
+detectorPreferZeroLengthArrays=PreferZeroLengthArrays|true
+detectorAtomicityProblem=AtomicityProblem|true
+detectorRuntimeExceptionCapture=RuntimeExceptionCapture|true
+detectorInitializationChain=InitializationChain|true
+detectorInitializeNonnullFieldsInConstructor=InitializeNonnullFieldsInConstructor|true
+detectorOptionalReturnNull=OptionalReturnNull|true
+detectorStartInConstructor=StartInConstructor|true
+detectorFindUnsatisfiedObligation=FindUnsatisfiedObligation|true
+detectorRedundantConditions=RedundantConditions|true
+effort=default
+detectorRedundantInterfaces=RedundantInterfaces|true
+detectorDuplicateBranches=DuplicateBranches|true
+detectorCheckTypeQualifiers=CheckTypeQualifiers|true
+detectorComparatorIdiom=ComparatorIdiom|true
+detectorFindBadCast2=FindBadCast2|true
+detectorFindMismatchedWaitOrNotify=FindMismatchedWaitOrNotify|true
+excludefilter0=findBugs/FindBugsExcludeFilter.xml|true
+detectorBadResultSetAccess=BadResultSetAccess|true
+detectorIncompatMask=IncompatMask|true
+detectorCovariantArrayAssignment=CovariantArrayAssignment|false
+detectorDumbMethodInvocations=DumbMethodInvocations|true
+run_at_full_build=false
+detectorStaticCalendarDetector=StaticCalendarDetector|true
+detectorUncallableMethodOfAnonymousClass=UncallableMethodOfAnonymousClass|true
+detectorVarArgsProblems=VarArgsProblems|true
+detectorInefficientInitializationInsideLoop=InefficientInitializationInsideLoop|false
+detectorCloneIdiom=CloneIdiom|true
+detectorFindHEmismatch=FindHEmismatch|true
+detectorAppendingToAnObjectOutputStream=AppendingToAnObjectOutputStream|true
+detectorFindSelfComparison2=FindSelfComparison2|true
+detectorLazyInit=LazyInit|true
+detectorFindUnrelatedTypesInGenericContainer=FindUnrelatedTypesInGenericContainer|true
+detectorDontUseEnum=DontUseEnum|true
+detectorFindPuzzlers=FindPuzzlers|true
+detectorCallToUnsupportedMethod=CallToUnsupportedMethod|false
+detectorSuperfluousInstanceOf=SuperfluousInstanceOf|true
+detectorReadReturnShouldBeChecked=ReadReturnShouldBeChecked|true
+detector_threshold=2
+detectorPublicSemaphores=PublicSemaphores|false
+detectorDumbMethods=DumbMethods|true
diff --git a/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF
index c5a3d06..13aa093 100644
--- a/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF
@@ -3,43 +3,46 @@
 Bundle-Name: %Bundle-Name
 Automatic-Module-Name: org.eclipse.jgit.junit.ssh
 Bundle-SymbolicName: org.eclipse.jgit.junit.ssh
-Bundle-Version: 5.10.1.qualifier
+Bundle-Version: 5.11.2.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %Bundle-Vendor
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.apache.sshd.common;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.config.keys;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.file.virtualfs;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.helpers;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.io;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.kex;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.keyprovider;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.session;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.util.buffer;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.util.logging;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.util.security;version="[2.4.0,2.5.0)",
- org.apache.sshd.common.util.threads;version="[2.4.0,2.5.0)",
- org.apache.sshd.server;version="[2.4.0,2.5.0)",
- org.apache.sshd.server.auth;version="[2.4.0,2.5.0)",
- org.apache.sshd.server.auth.gss;version="[2.4.0,2.5.0)",
- org.apache.sshd.server.auth.keyboard;version="[2.4.0,2.5.0)",
- org.apache.sshd.server.auth.password;version="[2.4.0,2.5.0)",
- org.apache.sshd.server.command;version="[2.4.0,2.5.0)",
- org.apache.sshd.server.session;version="[2.4.0,2.5.0)",
- org.apache.sshd.server.shell;version="[2.4.0,2.5.0)",
- org.apache.sshd.server.subsystem;version="[2.4.0,2.5.0)",
- org.apache.sshd.server.subsystem.sftp;version="[2.4.0,2.5.0)",
- org.eclipse.jgit.annotations;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.api;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.api.errors;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.errors;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.junit;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lib;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.revwalk;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.transport;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.util;version="[5.10.1,5.11.0)",
+Import-Package: org.apache.sshd.common;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.config.keys;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.file.virtualfs;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.helpers;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.io;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.kex;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.keyprovider;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.session;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.signature;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.util.buffer;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.util.logging;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.util.security;version="[2.6.0,2.7.0)",
+ org.apache.sshd.common.util.threads;version="[2.6.0,2.7.0)",
+ org.apache.sshd.core;version="[2.6.0,2.7.0)",
+ org.apache.sshd.server;version="[2.6.0,2.7.0)",
+ org.apache.sshd.server.auth;version="[2.6.0,2.7.0)",
+ org.apache.sshd.server.auth.gss;version="[2.6.0,2.7.0)",
+ org.apache.sshd.server.auth.keyboard;version="[2.6.0,2.7.0)",
+ org.apache.sshd.server.auth.password;version="[2.6.0,2.7.0)",
+ org.apache.sshd.server.command;version="[2.6.0,2.7.0)",
+ org.apache.sshd.server.session;version="[2.6.0,2.7.0)",
+ org.apache.sshd.server.shell;version="[2.6.0,2.7.0)",
+ org.apache.sshd.server.subsystem;version="[2.6.0,2.7.0)",
+ org.apache.sshd.sftp;version="[2.6.0,2.7.0)",
+ org.apache.sshd.sftp.server;version="[2.6.0,2.7.0)",
+ org.eclipse.jgit.annotations;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.api;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.api.errors;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.errors;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.junit;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.lib;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.revwalk;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.transport;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.util;version="[5.11.2,5.12.0)",
  org.junit;version="[4.13,5.0.0)",
  org.junit.experimental.theories;version="[4.13,5.0.0)",
  org.slf4j;version="[1.7.0,2.0.0)"
-Export-Package: org.eclipse.jgit.junit.ssh;version="5.10.1"
+Export-Package: org.eclipse.jgit.junit.ssh;version="5.11.2"
diff --git a/org.eclipse.jgit.junit.ssh/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.junit.ssh/META-INF/SOURCE-MANIFEST.MF
index 44d2bcc..b2d2d89 100644
--- a/org.eclipse.jgit.junit.ssh/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.junit.ssh/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
 Bundle-Name: org.eclipse.jgit.junit.ssh - Sources
 Bundle-SymbolicName: org.eclipse.jgit.junit.ssh.source
 Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 5.10.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.junit.ssh;version="5.10.1.qualifier";roots="."
+Bundle-Version: 5.11.2.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.junit.ssh;version="5.11.2.qualifier";roots="."
diff --git a/org.eclipse.jgit.junit.ssh/findBugs/FindBugsExcludeFilter.xml b/org.eclipse.jgit.junit.ssh/findBugs/FindBugsExcludeFilter.xml
new file mode 100644
index 0000000..999cb71
--- /dev/null
+++ b/org.eclipse.jgit.junit.ssh/findBugs/FindBugsExcludeFilter.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<FindBugsFilter>
+     <!-- Silence returning null for Boolean return type -->
+     <Match>
+       <Class name="org.eclipse.jgit.junit.ssh.SshTestGitServer$FakeUserAuthGSS" />
+       <Method name="doAuth" />
+       <Bug pattern="NP_BOOLEAN_RETURN_NULL" />
+     </Match>
+</FindBugsFilter>
diff --git a/org.eclipse.jgit.junit.ssh/pom.xml b/org.eclipse.jgit.junit.ssh/pom.xml
index a0e35aa..a1fd542 100644
--- a/org.eclipse.jgit.junit.ssh/pom.xml
+++ b/org.eclipse.jgit.junit.ssh/pom.xml
@@ -17,7 +17,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.10.1-SNAPSHOT</version>
+    <version>5.11.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.junit.ssh</artifactId>
diff --git a/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshBasicTestBase.java b/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshBasicTestBase.java
new file mode 100644
index 0000000..f9ca0b8
--- /dev/null
+++ b/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshBasicTestBase.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2020 Thomas Wolf <thomas.wolf@paranor.ch> 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
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.junit.ssh;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+
+import org.eclipse.jgit.api.Git;
+import org.junit.Test;
+
+/**
+ * Some minimal cloning and fetching tests. Concrete subclasses can implement
+ * the abstract operations from {@link SshTestHarness} to run with different SSH
+ * implementations.
+ */
+public abstract class SshBasicTestBase extends SshTestHarness {
+
+	protected File defaultCloneDir;
+
+	@Override
+	public void setUp() throws Exception {
+		super.setUp();
+		defaultCloneDir = new File(getTemporaryDirectory(), "cloned");
+	}
+
+	@Test
+	public void testSshCloneWithConfig() throws Exception {
+		cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, null, //
+				"Host localhost", //
+				"HostName localhost", //
+				"Port " + testPort, //
+				"User " + TEST_USER, //
+				"IdentityFile " + privateKey1.getAbsolutePath());
+	}
+
+	@Test
+	public void testSshFetchWithConfig() throws Exception {
+		File localClone = cloneWith("ssh://localhost/doesntmatter",
+				defaultCloneDir, null, //
+				"Host localhost", //
+				"HostName localhost", //
+				"Port " + testPort, //
+				"User " + TEST_USER, //
+				"IdentityFile " + privateKey1.getAbsolutePath());
+		// Do a commit in the upstream repo
+		try (Git git = new Git(db)) {
+			writeTrashFile("SomeOtherFile.txt", "Other commit");
+			git.add().addFilepattern("SomeOtherFile.txt").call();
+			git.commit().setMessage("New commit").call();
+		}
+		// Pull in the clone
+		try (Git git = Git.open(localClone)) {
+			File f = new File(git.getRepository().getWorkTree(),
+					"SomeOtherFile.txt");
+			assertFalse(f.exists());
+			git.pull().setRemote("origin").call();
+			assertTrue(f.exists());
+			assertEquals("Other commit", read(f));
+		}
+	}
+}
diff --git a/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestBase.java b/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestBase.java
index 3784741..6fa82f1 100644
--- a/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestBase.java
+++ b/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestBase.java
@@ -40,7 +40,7 @@
  * abstract operations from {@link SshTestHarness}. This gives a way to test
  * different ssh clients against a unified test suite.
  */
-public abstract class SshTestBase extends SshTestHarness {
+public abstract class SshTestBase extends SshBasicTestBase {
 
 	@DataPoints
 	public static String[] KEY_RESOURCES = { //
@@ -65,14 +65,6 @@ public abstract class SshTestBase extends SshTestHarness {
 			"id_ed25519_testpass", //
 			"id_ed25519_expensive_testpass" };
 
-	protected File defaultCloneDir;
-
-	@Override
-	public void setUp() throws Exception {
-		super.setUp();
-		defaultCloneDir = new File(getTemporaryDirectory(), "cloned");
-	}
-
 	@Test
 	public void testSshWithoutConfig() throws Exception {
 		assertThrows(TransportException.class,
@@ -133,16 +125,6 @@ public void testSshWithDefaultIdentity() throws Exception {
 	}
 
 	@Test
-	public void testSshWithConfig() throws Exception {
-		cloneWith("ssh://localhost/doesntmatter", defaultCloneDir, null, //
-				"Host localhost", //
-				"HostName localhost", //
-				"Port " + testPort, //
-				"User " + TEST_USER, //
-				"IdentityFile " + privateKey1.getAbsolutePath());
-	}
-
-	@Test
 	public void testSshWithConfigEncryptedUnusedKey() throws Exception {
 		// Copy the encrypted test key from the bundle.
 		File encryptedKey = new File(sshDir, "id_dsa");
diff --git a/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestGitServer.java b/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestGitServer.java
index ab8e0c1..4fe98f8 100644
--- a/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestGitServer.java
+++ b/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestGitServer.java
@@ -9,6 +9,9 @@
  */
 package org.eclipse.jgit.junit.ssh;
 
+import static org.apache.sshd.core.CoreModuleProperties.SERVER_EXTRA_IDENTIFICATION_LINES;
+import static org.apache.sshd.core.CoreModuleProperties.SERVER_EXTRA_IDENT_LINES_SEPARATOR;
+
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -21,26 +24,28 @@
 import java.security.PublicKey;
 import java.text.MessageFormat;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
 import java.util.concurrent.TimeUnit;
 
+import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.NamedResource;
 import org.apache.sshd.common.PropertyResolver;
-import org.apache.sshd.common.PropertyResolverUtils;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.config.keys.AuthorizedKeyEntry;
 import org.apache.sshd.common.config.keys.KeyUtils;
 import org.apache.sshd.common.config.keys.PublicKeyEntryResolver;
 import org.apache.sshd.common.file.virtualfs.VirtualFileSystemFactory;
-import org.apache.sshd.common.session.Session;
+import org.apache.sshd.common.signature.BuiltinSignatures;
+import org.apache.sshd.common.signature.Signature;
 import org.apache.sshd.common.util.buffer.Buffer;
 import org.apache.sshd.common.util.security.SecurityUtils;
 import org.apache.sshd.common.util.threads.CloseableExecutorService;
 import org.apache.sshd.common.util.threads.ThreadUtils;
 import org.apache.sshd.server.ServerAuthenticationManager;
-import org.apache.sshd.server.ServerFactoryManager;
+import org.apache.sshd.server.ServerBuilder;
 import org.apache.sshd.server.SshServer;
 import org.apache.sshd.server.auth.UserAuth;
 import org.apache.sshd.server.auth.UserAuthFactory;
@@ -52,8 +57,9 @@
 import org.apache.sshd.server.session.ServerSession;
 import org.apache.sshd.server.shell.UnknownCommand;
 import org.apache.sshd.server.subsystem.SubsystemFactory;
-import org.apache.sshd.server.subsystem.sftp.SftpSubsystemFactory;
+import org.apache.sshd.sftp.server.SftpSubsystemFactory;
 import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.transport.ReceivePack;
 import org.eclipse.jgit.transport.RemoteConfig;
@@ -161,7 +167,9 @@ public SshTestGitServer(@NonNull String testUser,
 		this.testUser = testUser;
 		setTestUserPublicKey(testKey);
 		this.repository = repository;
-		server = SshServer.setUpDefaultServer();
+		ServerBuilder builder = ServerBuilder.builder()
+				.signatureFactories(getSignatureFactories());
+		server = builder.build();
 		hostKeys.add(hostKey);
 		server.setKeyPairProvider((session) -> hostKeys);
 
@@ -186,6 +194,37 @@ public SshTestGitServer(@NonNull String testUser,
 		});
 	}
 
+	/**
+	 * Apache MINA sshd 2.6.0 has removed DSA, DSA_CERT and RSA_CERT. We have to
+	 * set it up explicitly to still allow users to connect with DSA keys.
+	 *
+	 * @return a list of supported signature factories
+	 */
+	@SuppressWarnings("deprecation")
+	private static List<NamedFactory<Signature>> getSignatureFactories() {
+		// @formatter:off
+		return Arrays.asList(
+                BuiltinSignatures.nistp256_cert,
+                BuiltinSignatures.nistp384_cert,
+                BuiltinSignatures.nistp521_cert,
+                BuiltinSignatures.ed25519_cert,
+                BuiltinSignatures.rsaSHA512_cert,
+                BuiltinSignatures.rsaSHA256_cert,
+                BuiltinSignatures.rsa_cert,
+                BuiltinSignatures.nistp256,
+                BuiltinSignatures.nistp384,
+                BuiltinSignatures.nistp521,
+                BuiltinSignatures.ed25519,
+                BuiltinSignatures.sk_ecdsa_sha2_nistp256,
+                BuiltinSignatures.sk_ssh_ed25519,
+                BuiltinSignatures.rsaSHA512,
+                BuiltinSignatures.rsaSHA256,
+                BuiltinSignatures.rsa,
+                BuiltinSignatures.dsa_cert,
+                BuiltinSignatures.dsa);
+		// @formatter:on
+	}
+
 	private static PublicKey readPublicKey(Path key)
 			throws IOException, GeneralSecurityException {
 		return AuthorizedKeyEntry.readAuthorizedKeys(key).get(0)
@@ -202,7 +241,7 @@ private static KeyPair readKeyPair(byte[] keyMaterial)
 
 	private static class FakeUserAuthGSS extends UserAuthGSS {
 		@Override
-		protected Boolean doAuth(Buffer buffer, boolean initial)
+		protected @Nullable Boolean doAuth(Buffer buffer, boolean initial)
 				throws Exception {
 			// We always reply that we did do this, but then we fail at the
 			// first token message. That way we can test that the client-side
@@ -277,14 +316,8 @@ public boolean validateInitialUser(ServerSession session,
 	@NonNull
 	protected List<SubsystemFactory> configureSubsystems() {
 		// SFTP.
-		server.setFileSystemFactory(new VirtualFileSystemFactory() {
-
-			@Override
-			protected Path computeRootDir(Session session) throws IOException {
-				return SshTestGitServer.this.repository.getDirectory()
-						.getParentFile().getAbsoluteFile().toPath();
-			}
-		});
+		server.setFileSystemFactory(new VirtualFileSystemFactory(repository
+				.getDirectory().getParentFile().getAbsoluteFile().toPath()));
 		return Collections
 				.singletonList((new SftpSubsystemFactory.Builder()).build());
 	}
@@ -433,9 +466,8 @@ public void setTestUserPublicKey(@NonNull PublicKey key) {
 	 */
 	public void setPreamble(String... lines) {
 		if (lines != null && lines.length > 0) {
-			PropertyResolverUtils.updateProperty(this.server,
-					ServerFactoryManager.SERVER_EXTRA_IDENTIFICATION_LINES,
-					String.join("|", lines));
+			SERVER_EXTRA_IDENTIFICATION_LINES.set(server, String.join(
+					String.valueOf(SERVER_EXTRA_IDENT_LINES_SEPARATOR), lines));
 		}
 	}
 
diff --git a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
index 75baf2c..f2f2e16 100644
--- a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
@@ -3,35 +3,35 @@
 Bundle-Name: %Bundle-Name
 Automatic-Module-Name: org.eclipse.jgit.junit
 Bundle-SymbolicName: org.eclipse.jgit.junit
-Bundle-Version: 5.10.1.qualifier
+Bundle-Version: 5.11.2.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %Bundle-Vendor
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.eclipse.jgit.annotations;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.api;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.api.errors;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.dircache;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.errors;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.internal.storage.file;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.internal.storage.pack;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lib;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.merge;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.revwalk;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.storage.file;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.transport;version="5.10.1",
- org.eclipse.jgit.treewalk;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.treewalk.filter;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.util;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.util.io;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.util.time;version="[5.10.1,5.11.0)",
+Import-Package: org.eclipse.jgit.annotations;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.api;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.api.errors;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.dircache;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.errors;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.lib;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.merge;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.revwalk;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.storage.file;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.transport;version="5.11.2",
+ org.eclipse.jgit.treewalk;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.util;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.util.io;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.util.time;version="[5.11.2,5.12.0)",
  org.junit;version="[4.13,5.0.0)",
  org.junit.rules;version="[4.13,5.0.0)",
  org.junit.runner;version="[4.13,5.0.0)",
  org.junit.runners;version="[4.13,5.0.0)",
  org.junit.runners.model;version="[4.13,5.0.0)",
  org.slf4j;version="[1.7.0,2.0.0)"
-Export-Package: org.eclipse.jgit.junit;version="5.10.1";
+Export-Package: org.eclipse.jgit.junit;version="5.11.2";
   uses:="org.eclipse.jgit.dircache,
    org.eclipse.jgit.lib,
    org.eclipse.jgit.revwalk,
@@ -44,4 +44,4 @@
    org.junit.runners.model,
    org.junit.runner,
    org.eclipse.jgit.util.time",
- org.eclipse.jgit.junit.time;version="5.10.1";uses:="org.eclipse.jgit.util.time"
+ org.eclipse.jgit.junit.time;version="5.11.2";uses:="org.eclipse.jgit.util.time"
diff --git a/org.eclipse.jgit.junit/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.junit/META-INF/SOURCE-MANIFEST.MF
index 7a2c896..b358c38 100644
--- a/org.eclipse.jgit.junit/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.junit/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
 Bundle-Name: org.eclipse.jgit.junit - Sources
 Bundle-SymbolicName: org.eclipse.jgit.junit.source
 Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 5.10.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.junit;version="5.10.1.qualifier";roots="."
+Bundle-Version: 5.11.2.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.junit;version="5.11.2.qualifier";roots="."
diff --git a/org.eclipse.jgit.junit/pom.xml b/org.eclipse.jgit.junit/pom.xml
index ae026fc..eb65596 100644
--- a/org.eclipse.jgit.junit/pom.xml
+++ b/org.eclipse.jgit.junit/pom.xml
@@ -19,7 +19,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.10.1-SNAPSHOT</version>
+    <version>5.11.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.junit</artifactId>
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/SeparateClassloaderTestRunner.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/SeparateClassloaderTestRunner.java
index 106abf0..c8c56b2 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/SeparateClassloaderTestRunner.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/SeparateClassloaderTestRunner.java
@@ -9,10 +9,10 @@
  */
 package org.eclipse.jgit.junit;
 
-import static java.lang.ClassLoader.getSystemClassLoader;
-
+import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLClassLoader;
+import java.nio.file.Paths;
 
 import org.junit.runners.BlockJUnit4ClassRunner;
 import org.junit.runners.model.InitializationError;
@@ -42,7 +42,13 @@ public SeparateClassloaderTestRunner(Class<?> klass)
 	private static Class<?> loadNewClass(Class<?> klass)
 			throws InitializationError {
 		try {
-			URL[] urls = ((URLClassLoader) getSystemClassLoader()).getURLs();
+			String pathSeparator = System.getProperty("path.separator");
+			String[] classPathEntries = System.getProperty("java.class.path")
+					.split(pathSeparator);
+			URL[] urls = new URL[classPathEntries.length];
+			for (int i = 0; i < classPathEntries.length; i++) {
+				urls[i] = Paths.get(classPathEntries[i]).toUri().toURL();
+			}
 			ClassLoader testClassLoader = new URLClassLoader(urls) {
 
 				@Override
@@ -56,7 +62,7 @@ public Class<?> loadClass(String name)
 				}
 			};
 			return Class.forName(klass.getName(), true, testClassLoader);
-		} catch (ClassNotFoundException e) {
+		} catch (ClassNotFoundException | MalformedURLException e) {
 			throw new InitializationError(e);
 		}
 	}
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
index fc19de0..54e4a09 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
@@ -43,8 +43,10 @@
 import org.eclipse.jgit.internal.storage.file.FileRepository;
 import org.eclipse.jgit.internal.storage.file.LockFile;
 import org.eclipse.jgit.internal.storage.file.ObjectDirectory;
+import org.eclipse.jgit.internal.storage.file.Pack;
 import org.eclipse.jgit.internal.storage.file.PackFile;
 import org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry;
+import org.eclipse.jgit.internal.storage.pack.PackExt;
 import org.eclipse.jgit.internal.storage.pack.PackWriter;
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.Constants;
@@ -775,7 +777,7 @@ protected void writeFile(String name, byte[] bin)
 			rw.writeInfoRefs();
 
 			final StringBuilder w = new StringBuilder();
-			for (PackFile p : fr.getObjectDatabase().getPacks()) {
+			for (Pack p : fr.getObjectDatabase().getPacks()) {
 				w.append("P ");
 				w.append(p.getPackFile().getName());
 				w.append('\n');
@@ -908,23 +910,22 @@ public void packAndPrune() throws Exception {
 			ObjectDirectory odb = (ObjectDirectory) db.getObjectDatabase();
 			NullProgressMonitor m = NullProgressMonitor.INSTANCE;
 
-			final File pack, idx;
+			final PackFile pack, idx;
 			try (PackWriter pw = new PackWriter(db)) {
 				Set<ObjectId> all = new HashSet<>();
 				for (Ref r : db.getRefDatabase().getRefs())
 					all.add(r.getObjectId());
 				pw.preparePack(m, all, PackWriter.NONE);
 
-				final ObjectId name = pw.computeName();
-
-				pack = nameFor(odb, name, ".pack");
+				pack = new PackFile(odb.getPackDirectory(), pw.computeName(),
+						PackExt.PACK);
 				try (OutputStream out =
 						new BufferedOutputStream(new FileOutputStream(pack))) {
 					pw.writePack(m, m, out);
 				}
 				pack.setReadOnly();
 
-				idx = nameFor(odb, name, ".idx");
+				idx = pack.create(PackExt.INDEX);
 				try (OutputStream out =
 						new BufferedOutputStream(new FileOutputStream(idx))) {
 					pw.writeIndex(out);
@@ -956,17 +957,12 @@ public void close() {
 	}
 
 	private static void prunePacked(ObjectDirectory odb) throws IOException {
-		for (PackFile p : odb.getPacks()) {
+		for (Pack p : odb.getPacks()) {
 			for (MutableEntry e : p)
 				FileUtils.delete(odb.fileFor(e.toObjectId()));
 		}
 	}
 
-	private static File nameFor(ObjectDirectory odb, ObjectId name, String t) {
-		File packdir = odb.getPackDirectory();
-		return new File(packdir, "pack-" + name.name() + t);
-	}
-
 	private void writeFile(File p, byte[] bin) throws IOException,
 			ObjectWritingException {
 		final LockFile lck = new LockFile(p);
diff --git a/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF
index 4f443e0..d757e45 100644
--- a/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF
@@ -3,17 +3,17 @@
 Bundle-Name: %Bundle-Name
 Automatic-Module-Name: org.eclipse.jgit.lfs.server.test
 Bundle-SymbolicName: org.eclipse.jgit.lfs.server.test
-Bundle-Version: 5.10.1.qualifier
+Bundle-Version: 5.11.2.qualifier
 Bundle-Vendor: %Bundle-Vendor
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Import-Package: javax.servlet;version="[3.1.0,4.0.0)",
  javax.servlet.http;version="[3.1.0,4.0.0)",
  org.apache.http;version="[4.3.0,5.0.0)",
- org.apache.http.client;version="[4.3.0,5.0.0)",
- org.apache.http.client.methods;version="[4.3.0,5.0.0)",
+ org.apache.http.client;version="[4.4.0,5.0.0)",
+ org.apache.http.client.methods;version="[4.4.0,5.0.0)",
  org.apache.http.entity;version="[4.3.0,5.0.0)",
- org.apache.http.impl.client;version="[4.3.0,5.0.0)",
+ org.apache.http.impl.client;version="[4.4.0,5.0.0)",
  org.eclipse.jetty.continuation;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.http;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.io;version="[9.4.5,10.0.0)",
@@ -28,24 +28,24 @@
  org.eclipse.jetty.util.log;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.util.security;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.util.thread;version="[9.4.5,10.0.0)",
- org.eclipse.jgit.api;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.api.errors;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.internal.storage.file;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.junit;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.junit.http;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lfs;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lfs.errors;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lfs.lib;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lfs.server;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lfs.server.fs;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lfs.test;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lib;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.revwalk;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.storage.file;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.transport;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.treewalk;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.treewalk.filter;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.util;version="[5.10.1,5.11.0)",
+ org.eclipse.jgit.api;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.api.errors;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.junit;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.junit.http;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.lfs;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.lfs.errors;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.lfs.lib;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.lfs.server;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.lfs.server.fs;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.lfs.test;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.lib;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.revwalk;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.storage.file;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.transport;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.treewalk;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.util;version="[5.11.2,5.12.0)",
  org.hamcrest.core;version="[1.1.0,2.0.0)",
  org.junit;version="[4.13,5.0.0)",
  org.junit.rules;version="[4.13,5.0.0)",
diff --git a/org.eclipse.jgit.lfs.server.test/pom.xml b/org.eclipse.jgit.lfs.server.test/pom.xml
index 193cd8d..4d6a76a 100644
--- a/org.eclipse.jgit.lfs.server.test/pom.xml
+++ b/org.eclipse.jgit.lfs.server.test/pom.xml
@@ -17,7 +17,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.10.1-SNAPSHOT</version>
+    <version>5.11.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.lfs.server.test</artifactId>
diff --git a/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF
index b5e6135..0545f2d 100644
--- a/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF
@@ -3,19 +3,19 @@
 Bundle-Name: %Bundle-Name
 Automatic-Module-Name: org.eclipse.jgit.lfs.server
 Bundle-SymbolicName: org.eclipse.jgit.lfs.server
-Bundle-Version: 5.10.1.qualifier
+Bundle-Version: 5.11.2.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %Bundle-Vendor
-Export-Package: org.eclipse.jgit.lfs.server;version="5.10.1";
+Export-Package: org.eclipse.jgit.lfs.server;version="5.11.2";
   uses:="javax.servlet.http,
    org.eclipse.jgit.lfs.lib",
- org.eclipse.jgit.lfs.server.fs;version="5.10.1";
+ org.eclipse.jgit.lfs.server.fs;version="5.11.2";
   uses:="javax.servlet,
    javax.servlet.http,
    org.eclipse.jgit.lfs.server,
    org.eclipse.jgit.lfs.lib",
- org.eclipse.jgit.lfs.server.internal;version="5.10.1";x-internal:=true,
- org.eclipse.jgit.lfs.server.s3;version="5.10.1";
+ org.eclipse.jgit.lfs.server.internal;version="5.11.2";x-internal:=true,
+ org.eclipse.jgit.lfs.server.s3;version="5.11.2";
   uses:="org.eclipse.jgit.lfs.server,
    org.eclipse.jgit.lfs.lib"
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
@@ -24,16 +24,15 @@
  javax.servlet.annotation;version="[3.1.0,4.0.0)",
  javax.servlet.http;version="[3.1.0,4.0.0)",
  org.apache.http;version="[4.3.0,5.0.0)",
- org.apache.http.client;version="[4.3.0,5.0.0)",
- org.eclipse.jgit.annotations;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.internal;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.internal.storage.file;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lfs.errors;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lfs.internal;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lfs.lib;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lib;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.nls;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.transport.http;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.transport.http.apache;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.util;version="[5.10.1,5.11.0)",
+ org.eclipse.jgit.annotations;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.internal;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.lfs.errors;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.lfs.internal;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.lfs.lib;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.lib;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.nls;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.transport.http;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.transport.http.apache;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.util;version="[5.11.2,5.12.0)",
  org.slf4j;version="[1.7.0,2.0.0)"
diff --git a/org.eclipse.jgit.lfs.server/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.lfs.server/META-INF/SOURCE-MANIFEST.MF
index d0f1020..7641f4a 100644
--- a/org.eclipse.jgit.lfs.server/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.lfs.server/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
 Bundle-Name: org.eclipse.jgit.lfs.server - Sources
 Bundle-SymbolicName: org.eclipse.jgit.lfs.server.source
 Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 5.10.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.lfs.server;version="5.10.1.qualifier";roots="."
+Bundle-Version: 5.11.2.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.lfs.server;version="5.11.2.qualifier";roots="."
diff --git a/org.eclipse.jgit.lfs.server/findBugs/FindBugsExcludeFilter.xml b/org.eclipse.jgit.lfs.server/findBugs/FindBugsExcludeFilter.xml
new file mode 100644
index 0000000..c5f3f80
--- /dev/null
+++ b/org.eclipse.jgit.lfs.server/findBugs/FindBugsExcludeFilter.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<FindBugsFilter>
+<!-- Field is written by gson, seems like spotbugs doesn't recognize this -->
+     <Match>
+       <Class name="org.eclipse.jgit.lfs.server.LfsObject" />
+       <Bug pattern="UWF_UNWRITTEN_FIELD" />
+     </Match>
+</FindBugsFilter>
diff --git a/org.eclipse.jgit.lfs.server/pom.xml b/org.eclipse.jgit.lfs.server/pom.xml
index 008b4f2..f908bf5 100644
--- a/org.eclipse.jgit.lfs.server/pom.xml
+++ b/org.eclipse.jgit.lfs.server/pom.xml
@@ -17,7 +17,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.10.1-SNAPSHOT</version>
+    <version>5.11.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.lfs.server</artifactId>
diff --git a/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
index c9877bd..df90846 100644
--- a/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
@@ -3,22 +3,24 @@
 Bundle-Name: %Bundle-Name
 Automatic-Module-Name: org.eclipse.jgit.lfs.test
 Bundle-SymbolicName: org.eclipse.jgit.lfs.test
-Bundle-Version: 5.10.1.qualifier
+Bundle-Version: 5.11.2.qualifier
 Bundle-Vendor: %Bundle-Vendor
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.eclipse.jgit.internal.storage.dfs;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.junit;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lfs;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lfs.errors;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lfs.lib;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lib;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.revwalk;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.treewalk;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.treewalk.filter;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.util;version="[5.10.1,5.11.0)",
+Import-Package: org.eclipse.jgit.api;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.attributes;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.junit;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.lfs;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.lfs.errors;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.lfs.lib;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.lib;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.revwalk;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.treewalk;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.util;version="[5.11.2,5.12.0)",
  org.hamcrest.core;version="[1.1.0,2.0.0)",
  org.junit;version="[4.13,5.0.0)",
  org.junit.runner;version="[4.13,5.0.0)",
  org.junit.runners;version="[4.13,5.0.0)"
-Export-Package: org.eclipse.jgit.lfs.test;version="5.10.1";x-friends:="org.eclipse.jgit.lfs.server.test"
+Export-Package: org.eclipse.jgit.lfs.test;version="5.11.2";x-friends:="org.eclipse.jgit.lfs.server.test"
diff --git a/org.eclipse.jgit.lfs.test/pom.xml b/org.eclipse.jgit.lfs.test/pom.xml
index 70d756d..eef3ac8 100644
--- a/org.eclipse.jgit.lfs.test/pom.xml
+++ b/org.eclipse.jgit.lfs.test/pom.xml
@@ -17,7 +17,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.10.1-SNAPSHOT</version>
+    <version>5.11.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.lfs.test</artifactId>
diff --git a/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/LfsGitTest.java b/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/LfsGitTest.java
new file mode 100644
index 0000000..8964310
--- /dev/null
+++ b/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/LfsGitTest.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2021, Thomas Wolf <thomas.wolf@paranor.ch> 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
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.lfs;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.ResetCommand.ResetType;
+import org.eclipse.jgit.attributes.FilterCommandRegistry;
+import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.lfs.lib.Constants;
+import org.eclipse.jgit.lib.StoredConfig;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class LfsGitTest extends RepositoryTestCase {
+
+	private static final String SMUDGE_NAME = org.eclipse.jgit.lib.Constants.BUILTIN_FILTER_PREFIX
+			+ Constants.ATTR_FILTER_DRIVER_PREFIX
+			+ org.eclipse.jgit.lib.Constants.ATTR_FILTER_TYPE_SMUDGE;
+
+	private static final String CLEAN_NAME = org.eclipse.jgit.lib.Constants.BUILTIN_FILTER_PREFIX
+			+ Constants.ATTR_FILTER_DRIVER_PREFIX
+			+ org.eclipse.jgit.lib.Constants.ATTR_FILTER_TYPE_CLEAN;
+
+	@BeforeClass
+	public static void installLfs() {
+		FilterCommandRegistry.register(SMUDGE_NAME, SmudgeFilter.FACTORY);
+		FilterCommandRegistry.register(CLEAN_NAME, CleanFilter.FACTORY);
+	}
+
+	@AfterClass
+	public static void removeLfs() {
+		FilterCommandRegistry.unregister(SMUDGE_NAME);
+		FilterCommandRegistry.unregister(CLEAN_NAME);
+	}
+
+	private Git git;
+
+	@Override
+	@Before
+	public void setUp() throws Exception {
+		super.setUp();
+		git = new Git(db);
+		// commit something
+		writeTrashFile("Test.txt", "Hello world");
+		git.add().addFilepattern("Test.txt").call();
+		git.commit().setMessage("Initial commit").call();
+		// prepare the config for LFS
+		StoredConfig config = git.getRepository().getConfig();
+		config.setString("filter", "lfs", "clean", CLEAN_NAME);
+		config.setString("filter", "lfs", "smudge", SMUDGE_NAME);
+		config.save();
+	}
+
+	@Test
+	public void checkoutNonLfsPointer() throws Exception {
+		String content = "size_t\nsome_function(void* ptr);\n";
+		File smallFile = writeTrashFile("Test.txt", content);
+		StringBuilder largeContent = new StringBuilder(
+				LfsPointer.SIZE_THRESHOLD * 4);
+		while (largeContent.length() < LfsPointer.SIZE_THRESHOLD * 4) {
+			largeContent.append(content);
+		}
+		File largeFile = writeTrashFile("large.txt", largeContent.toString());
+		fsTick(largeFile);
+		git.add().addFilepattern("Test.txt").addFilepattern("large.txt").call();
+		git.commit().setMessage("Text files").call();
+		writeTrashFile(".gitattributes", "*.txt filter=lfs");
+		git.add().addFilepattern(".gitattributes").call();
+		git.commit().setMessage("attributes").call();
+		assertTrue(smallFile.delete());
+		assertTrue(largeFile.delete());
+		// This reset will run the two text files through the smudge filter
+		git.reset().setMode(ResetType.HARD).call();
+		assertTrue(smallFile.exists());
+		assertTrue(largeFile.exists());
+		checkFile(smallFile, content);
+		checkFile(largeFile, largeContent.toString());
+		// Modify the large file
+		largeContent.append(content);
+		writeTrashFile("large.txt", largeContent.toString());
+		// This should convert largeFile to an LFS pointer
+		git.add().addFilepattern("large.txt").call();
+		git.commit().setMessage("Large modified").call();
+		String lfsPtr = "version https://git-lfs.github.com/spec/v1\n"
+				+ "oid sha256:d041ab19bd7edd899b3c0450d0f61819f96672f0b22d26c9753abc62e1261614\n"
+				+ "size 858\n";
+		assertEquals("[.gitattributes, mode:100644, content:*.txt filter=lfs]"
+				+ "[Test.txt, mode:100644, content:" + content + ']'
+						+ "[large.txt, mode:100644, content:" + lfsPtr + ']',
+				indexState(CONTENT));
+		// Verify the file has been saved
+		File savedFile = new File(db.getDirectory(), "lfs");
+		savedFile = new File(savedFile, "objects");
+		savedFile = new File(savedFile, "d0");
+		savedFile = new File(savedFile, "41");
+		savedFile = new File(savedFile,
+				"d041ab19bd7edd899b3c0450d0f61819f96672f0b22d26c9753abc62e1261614");
+		String saved = new String(Files.readAllBytes(savedFile.toPath()),
+				StandardCharsets.UTF_8);
+		assertEquals(saved, largeContent.toString());
+
+		assertTrue(smallFile.delete());
+		assertTrue(largeFile.delete());
+		git.reset().setMode(ResetType.HARD).call();
+		assertTrue(smallFile.exists());
+		assertTrue(largeFile.exists());
+		checkFile(smallFile, content);
+		checkFile(largeFile, largeContent.toString());
+		assertEquals("[.gitattributes, mode:100644, content:*.txt filter=lfs]"
+				+ "[Test.txt, mode:100644, content:" + content + ']'
+						+ "[large.txt, mode:100644, content:" + lfsPtr + ']',
+				indexState(CONTENT));
+		git.add().addFilepattern("Test.txt").call();
+		git.commit().setMessage("Small committed again").call();
+		String lfsPtrSmall = "version https://git-lfs.github.com/spec/v1\n"
+				+ "oid sha256:9110463275fb0e2f0e9fdeaf84e598e62915666161145cf08927079119cc7814\n"
+				+ "size 33\n";
+		assertEquals("[.gitattributes, mode:100644, content:*.txt filter=lfs]"
+				+ "[Test.txt, mode:100644, content:" + lfsPtrSmall + ']'
+						+ "[large.txt, mode:100644, content:" + lfsPtr + ']',
+				indexState(CONTENT));
+
+		assertTrue(git.status().call().isClean());
+	}
+}
diff --git a/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/lib/LFSPointerTest.java b/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/lib/LFSPointerTest.java
index 7ee898f..da78b28 100644
--- a/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/lib/LFSPointerTest.java
+++ b/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/lib/LFSPointerTest.java
@@ -12,7 +12,13 @@
 
 import static java.nio.charset.StandardCharsets.UTF_8;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
 
+import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 
@@ -23,17 +29,275 @@
  * Test LfsPointer file abstraction
  */
 public class LFSPointerTest {
+
+	private static final String TEST_SHA256 = "27e15b72937fc8f558da24ac3d50ec20302a4cf21e33b87ae8e4ce90e89c4b10";
+
 	@Test
 	public void testEncoding() throws IOException {
-		final String s = "27e15b72937fc8f558da24ac3d50ec20302a4cf21e33b87ae8e4ce90e89c4b10";
-		AnyLongObjectId id = LongObjectId.fromString(s);
+		AnyLongObjectId id = LongObjectId.fromString(TEST_SHA256);
 		LfsPointer ptr = new LfsPointer(id, 4);
 		try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
 			ptr.encode(baos);
 			assertEquals(
 					"version https://git-lfs.github.com/spec/v1\noid sha256:"
-							+ s + "\nsize 4\n",
+							+ TEST_SHA256 + "\nsize 4\n",
 					baos.toString(UTF_8.name()));
 		}
 	}
+
+	@Test
+	public void testReadValidLfsPointer() throws Exception {
+		String ptr = "version https://git-lfs.github.com/spec/v1\n"
+				+ "oid sha256:" + TEST_SHA256 + '\n'
+				+ "size 4\n";
+		AnyLongObjectId id = LongObjectId.fromString(TEST_SHA256);
+		LfsPointer lfs = new LfsPointer(id, 4);
+		try (ByteArrayInputStream in = new ByteArrayInputStream(
+				ptr.getBytes(UTF_8))) {
+			assertEquals(lfs, LfsPointer.parseLfsPointer(in));
+		}
+	}
+
+	@Test
+	public void testReadValidLfsPointerUnordered() throws Exception {
+		// This is actually not allowed per the spec, but JGit accepts it
+		// anyway.
+		String ptr = "version https://git-lfs.github.com/spec/v1\n"
+				+ "size 4\n"
+				+ "oid sha256:" + TEST_SHA256 + '\n';
+		AnyLongObjectId id = LongObjectId.fromString(TEST_SHA256);
+		LfsPointer lfs = new LfsPointer(id, 4);
+		try (ByteArrayInputStream in = new ByteArrayInputStream(
+				ptr.getBytes(UTF_8))) {
+			assertEquals(lfs, LfsPointer.parseLfsPointer(in));
+		}
+	}
+
+	@Test
+	public void testReadValidLfsPointerVersionNotFirst() throws Exception {
+		// This is actually not allowed per the spec, but JGit accepts it
+		// anyway.
+		String ptr = "oid sha256:" + TEST_SHA256 + '\n'
+				+ "size 4\n"
+				+ "version https://git-lfs.github.com/spec/v1\n";
+		AnyLongObjectId id = LongObjectId.fromString(TEST_SHA256);
+		LfsPointer lfs = new LfsPointer(id, 4);
+		try (ByteArrayInputStream in = new ByteArrayInputStream(
+				ptr.getBytes(UTF_8))) {
+			assertEquals(lfs, LfsPointer.parseLfsPointer(in));
+		}
+	}
+
+	@Test
+	public void testReadInvalidLfsPointer() throws Exception {
+		String cSource = "size_t someFunction(void *ptr); // Fake C source\n";
+		try (ByteArrayInputStream in = new ByteArrayInputStream(
+				cSource.getBytes(UTF_8))) {
+			assertNull("Is not a LFS pointer", LfsPointer.parseLfsPointer(in));
+		}
+	}
+
+	@Test
+	public void testReadInvalidLfsPointer2() throws Exception {
+		String cSource = "size_t\nsomeFunction(void *ptr);\n// Fake C source\n";
+		try (ByteArrayInputStream in = new ByteArrayInputStream(
+				cSource.getBytes(UTF_8))) {
+			assertNull("Is not a LFS pointer", LfsPointer.parseLfsPointer(in));
+		}
+	}
+
+	@Test
+	public void testReadInValidLfsPointerVersionWrong() throws Exception {
+		String ptr = "version https://git-lfs.example.org/spec/v1\n"
+				+ "oid sha256:" + TEST_SHA256 + '\n'
+				+ "size 4\n";
+		try (ByteArrayInputStream in = new ByteArrayInputStream(
+				ptr.getBytes(UTF_8))) {
+			assertNull("Is not a LFS pointer", LfsPointer.parseLfsPointer(in));
+		}
+	}
+
+	@Test
+	public void testReadInValidLfsPointerVersionTwice() throws Exception {
+		String ptr = "version https://git-lfs.github.com/spec/v1\n"
+				+ "version https://git-lfs.github.com/spec/v1\n"
+				+ "oid sha256:" + TEST_SHA256 + '\n'
+				+ "size 4\n";
+		try (ByteArrayInputStream in = new ByteArrayInputStream(
+				ptr.getBytes(UTF_8))) {
+			assertNull("Is not a LFS pointer", LfsPointer.parseLfsPointer(in));
+		}
+	}
+
+	@Test
+	public void testReadInValidLfsPointerVersionTwice2() throws Exception {
+		String ptr = "version https://git-lfs.github.com/spec/v1\n"
+				+ "oid sha256:" + TEST_SHA256 + '\n'
+				+ "version https://git-lfs.github.com/spec/v1\n"
+				+ "size 4\n";
+		try (ByteArrayInputStream in = new ByteArrayInputStream(
+				ptr.getBytes(UTF_8))) {
+			assertNull("Is not a LFS pointer", LfsPointer.parseLfsPointer(in));
+		}
+	}
+
+	@Test
+	public void testReadInValidLfsPointerOidTwice() throws Exception {
+		String ptr = "version https://git-lfs.github.com/spec/v1\n"
+				+ "oid sha256:" + TEST_SHA256 + '\n'
+				+ "oid sha256:" + TEST_SHA256 + '\n'
+				+ "size 4\n";
+		try (ByteArrayInputStream in = new ByteArrayInputStream(
+				ptr.getBytes(UTF_8))) {
+			assertNull("Is not a LFS pointer", LfsPointer.parseLfsPointer(in));
+		}
+	}
+
+	@Test
+	public void testReadInValidLfsPointerSizeTwice() throws Exception {
+		String ptr = "version https://git-lfs.github.com/spec/v1\n"
+				+ "size 4\n"
+				+ "size 4\n"
+				+ "oid sha256:" + TEST_SHA256 + '\n';
+		try (ByteArrayInputStream in = new ByteArrayInputStream(
+				ptr.getBytes(UTF_8))) {
+			assertNull("Is not a LFS pointer", LfsPointer.parseLfsPointer(in));
+		}
+	}
+
+	@Test
+	public void testRoundtrip() throws Exception {
+		AnyLongObjectId id = LongObjectId.fromString(TEST_SHA256);
+		LfsPointer ptr = new LfsPointer(id, 4);
+		try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
+			ptr.encode(baos);
+			try (ByteArrayInputStream in = new ByteArrayInputStream(
+					baos.toByteArray())) {
+				assertEquals(ptr, LfsPointer.parseLfsPointer(in));
+			}
+		}
+	}
+
+	@Test
+	public void testEquals() throws Exception {
+		AnyLongObjectId id = LongObjectId.fromString(TEST_SHA256);
+		LfsPointer lfs = new LfsPointer(id, 4);
+		AnyLongObjectId id2 = LongObjectId.fromString(TEST_SHA256);
+		LfsPointer lfs2 = new LfsPointer(id2, 4);
+		assertTrue(lfs.equals(lfs2));
+		assertTrue(lfs2.equals(lfs));
+	}
+
+	@Test
+	public void testEqualsNull() throws Exception {
+		AnyLongObjectId id = LongObjectId.fromString(TEST_SHA256);
+		LfsPointer lfs = new LfsPointer(id, 4);
+		assertFalse(lfs.equals(null));
+	}
+
+	@Test
+	public void testEqualsSame() throws Exception {
+		AnyLongObjectId id = LongObjectId.fromString(TEST_SHA256);
+		LfsPointer lfs = new LfsPointer(id, 4);
+		assertTrue(lfs.equals(lfs));
+	}
+
+	@Test
+	public void testEqualsOther() throws Exception {
+		AnyLongObjectId id = LongObjectId.fromString(TEST_SHA256);
+		LfsPointer lfs = new LfsPointer(id, 4);
+		assertFalse(lfs.equals(new Object()));
+	}
+
+	@Test
+	public void testNotEqualsOid() throws Exception {
+		AnyLongObjectId id = LongObjectId.fromString(TEST_SHA256);
+		LfsPointer lfs = new LfsPointer(id, 4);
+		AnyLongObjectId id2 = LongObjectId
+				.fromString(TEST_SHA256.replace('7', '5'));
+		LfsPointer lfs2 = new LfsPointer(id2, 4);
+		assertFalse(lfs.equals(lfs2));
+		assertFalse(lfs2.equals(lfs));
+	}
+
+	@Test
+	public void testNotEqualsSize() throws Exception {
+		AnyLongObjectId id = LongObjectId.fromString(TEST_SHA256);
+		LfsPointer lfs = new LfsPointer(id, 4);
+		AnyLongObjectId id2 = LongObjectId.fromString(TEST_SHA256);
+		LfsPointer lfs2 = new LfsPointer(id2, 5);
+		assertFalse(lfs.equals(lfs2));
+		assertFalse(lfs2.equals(lfs));
+	}
+
+	@Test
+	public void testCompareToEquals() throws Exception {
+		AnyLongObjectId id = LongObjectId.fromString(TEST_SHA256);
+		LfsPointer lfs = new LfsPointer(id, 4);
+		AnyLongObjectId id2 = LongObjectId.fromString(TEST_SHA256);
+		LfsPointer lfs2 = new LfsPointer(id2, 4);
+		assertEquals(0, lfs.compareTo(lfs2));
+		assertEquals(0, lfs2.compareTo(lfs));
+	}
+
+	@Test
+	@SuppressWarnings("SelfComparison")
+	public void testCompareToSame() throws Exception {
+		AnyLongObjectId id = LongObjectId.fromString(TEST_SHA256);
+		LfsPointer lfs = new LfsPointer(id, 4);
+		assertEquals(0, lfs.compareTo(lfs));
+	}
+
+	@Test
+	public void testCompareToNotEqualsOid() throws Exception {
+		AnyLongObjectId id = LongObjectId.fromString(TEST_SHA256);
+		LfsPointer lfs = new LfsPointer(id, 4);
+		AnyLongObjectId id2 = LongObjectId
+				.fromString(TEST_SHA256.replace('7', '5'));
+		LfsPointer lfs2 = new LfsPointer(id2, 4);
+		assertNotEquals(0, lfs.compareTo(lfs2));
+		assertNotEquals(0, lfs2.compareTo(lfs));
+	}
+
+	@Test
+	public void testCompareToNotEqualsSize() throws Exception {
+		AnyLongObjectId id = LongObjectId.fromString(TEST_SHA256);
+		LfsPointer lfs = new LfsPointer(id, 4);
+		AnyLongObjectId id2 = LongObjectId.fromString(TEST_SHA256);
+		LfsPointer lfs2 = new LfsPointer(id2, 5);
+		assertNotEquals(0, lfs.compareTo(lfs2));
+		assertNotEquals(0, lfs2.compareTo(lfs));
+	}
+
+	@Test
+	public void testCompareToNull() throws Exception {
+		AnyLongObjectId id = LongObjectId.fromString(TEST_SHA256);
+		LfsPointer lfs = new LfsPointer(id, 4);
+		assertThrows(NullPointerException.class, () -> lfs.compareTo(null));
+	}
+
+	@Test
+	public void testHashcodeEquals() throws Exception {
+		AnyLongObjectId id = LongObjectId.fromString(TEST_SHA256);
+		LfsPointer lfs = new LfsPointer(id, 4);
+		AnyLongObjectId id2 = LongObjectId.fromString(TEST_SHA256);
+		LfsPointer lfs2 = new LfsPointer(id2, 4);
+		assertEquals(lfs.hashCode(), lfs2.hashCode());
+	}
+
+	@Test
+	public void testHashcodeSame() throws Exception {
+		AnyLongObjectId id = LongObjectId.fromString(TEST_SHA256);
+		LfsPointer lfs = new LfsPointer(id, 4);
+		assertEquals(lfs.hashCode(), lfs.hashCode());
+	}
+
+	@Test
+	public void testHashcodeNotEquals() throws Exception {
+		AnyLongObjectId id = LongObjectId.fromString(TEST_SHA256);
+		LfsPointer lfs = new LfsPointer(id, 4);
+		AnyLongObjectId id2 = LongObjectId.fromString(TEST_SHA256);
+		LfsPointer lfs2 = new LfsPointer(id2, 5);
+		assertNotEquals(lfs.hashCode(), lfs2.hashCode());
+	}
 }
diff --git a/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
index 1b2a90c..876384f 100644
--- a/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
@@ -3,33 +3,31 @@
 Bundle-Name: %Bundle-Name
 Automatic-Module-Name: org.eclipse.jgit.lfs
 Bundle-SymbolicName: org.eclipse.jgit.lfs
-Bundle-Version: 5.10.1.qualifier
+Bundle-Version: 5.11.2.qualifier
 Bundle-Localization: plugin
 Bundle-Vendor: %Bundle-Vendor
-Export-Package: org.eclipse.jgit.lfs;version="5.10.1",
- org.eclipse.jgit.lfs.errors;version="5.10.1",
- org.eclipse.jgit.lfs.internal;version="5.10.1";x-friends:="org.eclipse.jgit.lfs.test,org.eclipse.jgit.lfs.server.fs,org.eclipse.jgit.lfs.server",
- org.eclipse.jgit.lfs.lib;version="5.10.1"
+Export-Package: org.eclipse.jgit.lfs;version="5.11.2",
+ org.eclipse.jgit.lfs.errors;version="5.11.2",
+ org.eclipse.jgit.lfs.internal;version="5.11.2";x-friends:="org.eclipse.jgit.lfs.test,org.eclipse.jgit.lfs.server.fs,org.eclipse.jgit.lfs.server",
+ org.eclipse.jgit.lfs.lib;version="5.11.2"
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: com.google.gson;version="[2.8.2,3.0.0)",
- com.google.gson.stream;version="[2.8.2,3.0.0)",
- org.apache.http.impl.client;version="[4.2.6,5.0.0)",
- org.apache.http.impl.conn;version="[4.2.6,5.0.0)",
- org.eclipse.jgit.annotations;version="[5.10.1,5.11.0)";resolution:=optional,
- org.eclipse.jgit.api.errors;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.attributes;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.diff;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.errors;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.hooks;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.internal.storage.file;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lib;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.nls;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.revwalk;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.storage.file;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.storage.pack;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.transport;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.transport.http;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.treewalk;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.treewalk.filter;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.util;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.util.io;version="[5.10.1,5.11.0)"
+Import-Package: com.google.gson;version="[2.8.0,3.0.0)",
+ com.google.gson.stream;version="[2.8.0,3.0.0)",
+ org.eclipse.jgit.annotations;version="[5.11.2,5.12.0)";resolution:=optional,
+ org.eclipse.jgit.api.errors;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.attributes;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.diff;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.errors;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.hooks;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.lib;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.nls;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.revwalk;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.storage.file;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.storage.pack;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.transport;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.transport.http;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.treewalk;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.util;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.util.io;version="[5.11.2,5.12.0)"
diff --git a/org.eclipse.jgit.lfs/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.lfs/META-INF/SOURCE-MANIFEST.MF
index 4d9bc2e..db9bcc6 100644
--- a/org.eclipse.jgit.lfs/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.lfs/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
 Bundle-Name: org.eclipse.jgit.lfs - Sources
 Bundle-SymbolicName: org.eclipse.jgit.lfs.source
 Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 5.10.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.lfs;version="5.10.1.qualifier";roots="."
+Bundle-Version: 5.11.2.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.lfs;version="5.11.2.qualifier";roots="."
diff --git a/org.eclipse.jgit.lfs/pom.xml b/org.eclipse.jgit.lfs/pom.xml
index b307916..d1f2ce4 100644
--- a/org.eclipse.jgit.lfs/pom.xml
+++ b/org.eclipse.jgit.lfs/pom.xml
@@ -17,7 +17,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.10.1-SNAPSHOT</version>
+    <version>5.11.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.lfs</artifactId>
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsBlobFilter.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsBlobFilter.java
index 52c3001..032a19b 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsBlobFilter.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsBlobFilter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017, Markus Duft <markus.duft@ssi-schaefer.com> and others
+ * Copyright (C) 2017, 2021 Markus Duft <markus.duft@ssi-schaefer.com> 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
@@ -45,7 +45,7 @@ public class LfsBlobFilter {
 	 */
 	public static ObjectLoader smudgeLfsBlob(Repository db, ObjectLoader loader)
 			throws IOException {
-		if (loader.getSize() > LfsPointer.SIZE_THRESHOLD) {
+		if (loader.getSize() > LfsPointer.FULL_SIZE_THRESHOLD) {
 			return loader;
 		}
 
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsPointer.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsPointer.java
index 4e2d8a9..0a8a3fa 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsPointer.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsPointer.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016, Christian Halstrick <christian.halstrick@sap.com> and others
+ * Copyright (C) 2016, 2021 Christian Halstrick <christian.halstrick@sap.com> 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
@@ -11,7 +11,9 @@
 
 import static java.nio.charset.StandardCharsets.UTF_8;
 
+import java.io.BufferedInputStream;
 import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -19,11 +21,13 @@
 import java.io.PrintStream;
 import java.io.UnsupportedEncodingException;
 import java.util.Locale;
+import java.util.Objects;
 
 import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.lfs.lib.AnyLongObjectId;
 import org.eclipse.jgit.lfs.lib.Constants;
 import org.eclipse.jgit.lfs.lib.LongObjectId;
+import org.eclipse.jgit.util.IO;
 
 /**
  * Represents an LFS pointer file
@@ -56,9 +60,15 @@ public class LfsPointer implements Comparable<LfsPointer> {
 	public static final String HASH_FUNCTION_NAME = Constants.LONG_HASH_FUNCTION
 			.toLowerCase(Locale.ROOT).replace("-", ""); //$NON-NLS-1$ //$NON-NLS-2$
 
-	private AnyLongObjectId oid;
+	/**
+	 * {@link #SIZE_THRESHOLD} is too low; with lfs extensions a LFS pointer can
+	 * be larger. But 8kB should be more than enough.
+	 */
+	static final int FULL_SIZE_THRESHOLD = 8 * 1024;
 
-	private long size;
+	private final AnyLongObjectId oid;
+
+	private final long size;
 
 	/**
 	 * <p>Constructor for LfsPointer.</p>
@@ -114,34 +124,113 @@ public void encode(OutputStream out) {
 
 	/**
 	 * Try to parse the data provided by an InputStream to the format defined by
-	 * {@link #VERSION}
+	 * {@link #VERSION}. If the given stream supports mark and reset as
+	 * indicated by {@link InputStream#markSupported()}, its input position will
+	 * be reset if the stream content is not actually a LFS pointer (i.e., when
+	 * {@code null} is returned). If the stream content is an invalid LFS
+	 * pointer or the given stream does not support mark/reset, the input
+	 * position may not be reset.
 	 *
 	 * @param in
 	 *            the {@link java.io.InputStream} from where to read the data
-	 * @return an {@link org.eclipse.jgit.lfs.LfsPointer} or <code>null</code>
-	 *         if the stream was not parseable as LfsPointer
+	 * @return an {@link org.eclipse.jgit.lfs.LfsPointer} or {@code null} if the
+	 *         stream was not parseable as LfsPointer
 	 * @throws java.io.IOException
 	 */
 	@Nullable
 	public static LfsPointer parseLfsPointer(InputStream in)
 			throws IOException {
+		if (in.markSupported()) {
+			return parse(in);
+		}
+		// Fallback; note that while parse() resets its input stream, that won't
+		// reset "in".
+		return parse(new BufferedInputStream(in));
+	}
+
+	@Nullable
+	private static LfsPointer parse(InputStream in)
+			throws IOException {
+		if (!in.markSupported()) {
+			// No translation; internal error
+			throw new IllegalArgumentException(
+					"LFS pointer parsing needs InputStream.markSupported() == true"); //$NON-NLS-1$
+		}
+		// Try reading only a short block first.
+		in.mark(SIZE_THRESHOLD);
+		byte[] preamble = new byte[SIZE_THRESHOLD];
+		int length = IO.readFully(in, preamble, 0);
+		if (length < preamble.length || in.read() < 0) {
+			// We have the whole file. Try to parse a pointer from it.
+			try (BufferedReader r = new BufferedReader(new InputStreamReader(
+					new ByteArrayInputStream(preamble, 0, length), UTF_8))) {
+				LfsPointer ptr = parse(r);
+				if (ptr == null) {
+					in.reset();
+				}
+				return ptr;
+			}
+		}
+		// Longer than SIZE_THRESHOLD: expect "version" to be the first line.
+		boolean hasVersion = checkVersion(preamble);
+		in.reset();
+		if (!hasVersion) {
+			return null;
+		}
+		in.mark(FULL_SIZE_THRESHOLD);
+		byte[] fullPointer = new byte[FULL_SIZE_THRESHOLD];
+		length = IO.readFully(in, fullPointer, 0);
+		if (length == fullPointer.length && in.read() >= 0) {
+			in.reset();
+			return null; // Too long.
+		}
+		try (BufferedReader r = new BufferedReader(new InputStreamReader(
+				new ByteArrayInputStream(fullPointer, 0, length), UTF_8))) {
+			LfsPointer ptr = parse(r);
+			if (ptr == null) {
+				in.reset();
+			}
+			return ptr;
+		}
+	}
+
+	private static LfsPointer parse(BufferedReader r) throws IOException {
 		boolean versionLine = false;
 		LongObjectId id = null;
 		long sz = -1;
-
-		try (BufferedReader br = new BufferedReader(
-				new InputStreamReader(in, UTF_8))) {
-			for (String s = br.readLine(); s != null; s = br.readLine()) {
-				if (s.startsWith("#") || s.length() == 0) { //$NON-NLS-1$
-					continue;
-				} else if (s.startsWith("version") && s.length() > 8 //$NON-NLS-1$
-						&& (s.substring(8).trim().equals(VERSION) ||
-								s.substring(8).trim().equals(VERSION_LEGACY))) {
-					versionLine = true;
-				} else if (s.startsWith("oid sha256:")) { //$NON-NLS-1$
-					id = LongObjectId.fromString(s.substring(11).trim());
-				} else if (s.startsWith("size") && s.length() > 5) { //$NON-NLS-1$
-					sz = Long.parseLong(s.substring(5).trim());
+		// This parsing is a bit too general if we go by the spec at
+		// https://github.com/git-lfs/git-lfs/blob/master/docs/spec.md
+		// Comment lines are not mentioned in the spec, the "version" line
+		// MUST be the first, and keys are ordered alphabetically.
+		for (String s = r.readLine(); s != null; s = r.readLine()) {
+			if (s.startsWith("#") || s.length() == 0) { //$NON-NLS-1$
+				continue;
+			} else if (s.startsWith("version")) { //$NON-NLS-1$
+				if (versionLine || !checkVersionLine(s)) {
+					return null; // Not a LFS pointer
+				}
+				versionLine = true;
+			} else {
+				try {
+					if (s.startsWith("oid sha256:")) { //$NON-NLS-1$
+						if (id != null) {
+							return null; // Not a LFS pointer
+						}
+						id = LongObjectId.fromString(s.substring(11).trim());
+					} else if (s.startsWith("size")) { //$NON-NLS-1$
+						if (sz > 0 || s.length() < 5 || s.charAt(4) != ' ') {
+							return null; // Not a LFS pointer
+						}
+						sz = Long.parseLong(s.substring(5).trim());
+					}
+				} catch (RuntimeException e) {
+					// We could not parse the line. If we have a version
+					// already, this is a corrupt LFS pointer. Otherwise it
+					// is just not an LFS pointer.
+					if (versionLine) {
+						throw e;
+					}
+					return null;
 				}
 			}
 			if (versionLine && id != null && sz > -1) {
@@ -151,6 +240,30 @@ public static LfsPointer parseLfsPointer(InputStream in)
 		return null;
 	}
 
+	private static boolean checkVersion(byte[] data) {
+		// According to the spec at
+		// https://github.com/git-lfs/git-lfs/blob/master/docs/spec.md
+		// it MUST always be the first line.
+		try (BufferedReader r = new BufferedReader(
+				new InputStreamReader(new ByteArrayInputStream(data), UTF_8))) {
+			String s = r.readLine();
+			if (s != null && s.startsWith("version")) { //$NON-NLS-1$
+				return checkVersionLine(s);
+			}
+		} catch (IOException e) {
+			// Doesn't occur, we're reading from a byte array!
+		}
+		return false;
+	}
+
+	private static boolean checkVersionLine(String s) {
+		if (s.length() < 8 || s.charAt(7) != ' ') {
+			return false; // Not a valid LFS pointer version line
+		}
+		String rest = s.substring(8).trim();
+		return VERSION.equals(rest) || VERSION_LEGACY.equals(rest);
+	}
+
 	/** {@inheritDoc} */
 	@Override
 	public String toString() {
@@ -170,5 +283,22 @@ public int compareTo(LfsPointer o) {
 
 		return Long.compare(getSize(), o.getSize());
 	}
-}
 
+	@Override
+	public int hashCode() {
+		return Objects.hash(getOid()) * 31 + Long.hashCode(getSize());
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj) {
+			return true;
+		}
+		if (obj == null || getClass() != obj.getClass()) {
+			return false;
+		}
+		LfsPointer other = (LfsPointer) obj;
+		return Objects.equals(getOid(), other.getOid())
+				&& getSize() == other.getSize();
+	}
+}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/SmudgeFilter.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/SmudgeFilter.java
index 2f80d5b..3411887 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/SmudgeFilter.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/SmudgeFilter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016, Christian Halstrick <christian.halstrick@sap.com> and others
+ * Copyright (C) 2016, 2021 Christian Halstrick <christian.halstrick@sap.com> 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
@@ -11,6 +11,7 @@
 
 import static java.nio.charset.StandardCharsets.UTF_8;
 
+import java.io.BufferedInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -87,20 +88,31 @@ static void register() {
 	 */
 	public SmudgeFilter(Repository db, InputStream in, OutputStream out)
 			throws IOException {
+		this(in.markSupported() ? in : new BufferedInputStream(in), out, db);
+	}
+
+	private SmudgeFilter(InputStream in, OutputStream out, Repository db)
+			throws IOException {
 		super(in, out);
+		InputStream from = in;
 		try {
-			Lfs lfs = new Lfs(db);
-			LfsPointer res = LfsPointer.parseLfsPointer(in);
+			LfsPointer res = LfsPointer.parseLfsPointer(from);
 			if (res != null) {
 				AnyLongObjectId oid = res.getOid();
+				Lfs lfs = new Lfs(db);
 				Path mediaFile = lfs.getMediaFile(oid);
 				if (!Files.exists(mediaFile)) {
 					downloadLfsResource(lfs, db, res);
 				}
 				this.in = Files.newInputStream(mediaFile);
+			} else {
+				// Not swapped; stream was reset, don't close!
+				from = null;
 			}
 		} finally {
-			in.close(); // make sure the swapped stream is closed properly.
+			if (from != null) {
+				from.close(); // Close the swapped-out stream
+			}
 		}
 	}
 
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConnectionFactory.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConnectionFactory.java
index 7a0ed45..e221913 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConnectionFactory.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConnectionFactory.java
@@ -18,7 +18,9 @@
 import java.net.ProxySelector;
 import java.net.URISyntaxException;
 import java.net.URL;
-import java.text.SimpleDateFormat;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
 import java.util.LinkedList;
 import java.util.Map;
 import java.util.TreeMap;
@@ -258,8 +260,8 @@ public static Protocol.Request toRequest(String operation,
 	private static final class AuthCache {
 		private static final long AUTH_CACHE_EAGER_TIMEOUT = 500;
 
-		private static final SimpleDateFormat ISO_FORMAT = new SimpleDateFormat(
-				"yyyy-MM-dd'T'HH:mm:ss.SSSX"); //$NON-NLS-1$
+		private static final DateTimeFormatter ISO_FORMAT = DateTimeFormatter
+				.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX"); //$NON-NLS-1$
 
 		/**
 		 * Creates a cache entry for an authentication response.
@@ -278,8 +280,10 @@ public AuthCache(Protocol.ExpiringAction action) {
 							- AUTH_CACHE_EAGER_TIMEOUT;
 				} else if (action.expiresAt != null
 						&& !action.expiresAt.isEmpty()) {
-					this.validUntil = ISO_FORMAT.parse(action.expiresAt)
-							.getTime() - AUTH_CACHE_EAGER_TIMEOUT;
+					this.validUntil = LocalDateTime
+							.parse(action.expiresAt, ISO_FORMAT)
+							.atZone(ZoneOffset.UTC).toInstant().toEpochMilli()
+							- AUTH_CACHE_EAGER_TIMEOUT;
 				} else {
 					this.validUntil = System.currentTimeMillis();
 				}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/LfsPointerFilter.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/LfsPointerFilter.java
index d84eebd..99bae49 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/LfsPointerFilter.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/LfsPointerFilter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015, 2017, Dariusz Luksza <dariusz@luksza.org> and others
+ * Copyright (C) 2015, 2021 Dariusz Luksza <dariusz@luksza.org> 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
@@ -58,6 +58,8 @@ public boolean include(TreeWalk walk) throws MissingObjectException,
 		try (ObjectStream stream = object.openStream()) {
 			pointer = LfsPointer.parseLfsPointer(stream);
 			return pointer != null;
+		} catch (RuntimeException e) {
+			return false;
 		}
 	}
 
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml
index 522cc7d..cc8756e 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit"
       label="%featureName"
-      version="5.10.1.qualifier"
+      version="5.11.2.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml
index aa9486a..ef6a8a6 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml
@@ -17,7 +17,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>5.10.1-SNAPSHOT</version>
+    <version>5.11.2-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/feature.xml
index 3908d3a..85dec4c 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.gpg.bc"
       label="%featureName"
-      version="5.10.1.qualifier"
+      version="5.11.2.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
@@ -23,7 +23,7 @@
    </url>
 
    <requires>
-      <import plugin="org.eclipse.jgit" version="5.10.1" match="equivalent"/>
+      <import plugin="org.eclipse.jgit" version="5.11.2" match="equivalent"/>
    </requires>
 
    <plugin
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/pom.xml
index 4ae91c5..eebe2c4 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/pom.xml
@@ -17,7 +17,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>5.10.1-SNAPSHOT</version>
+    <version>5.11.2-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml
index a47f8c7..beff00e 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.http.apache"
       label="%featureName"
-      version="5.10.1.qualifier"
+      version="5.11.2.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
@@ -23,7 +23,7 @@
    </url>
 
    <requires>
-      <import plugin="org.eclipse.jgit" version="5.10.1" match="equivalent"/>
+      <import plugin="org.eclipse.jgit" version="5.11.2" match="equivalent"/>
    </requires>
 
    <plugin
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml
index 965c916..2584dab 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml
@@ -17,7 +17,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>5.10.1-SNAPSHOT</version>
+    <version>5.11.2-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml
index 45d4845..ce6e241 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.junit"
       label="%featureName"
-      version="5.10.1.qualifier"
+      version="5.11.2.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
@@ -24,7 +24,7 @@
 
    <requires>
       <import plugin="com.jcraft.jsch"/>
-      <import plugin="org.eclipse.jgit" version="5.10.1" match="equivalent"/>
+      <import plugin="org.eclipse.jgit" version="5.11.2" match="equivalent"/>
    </requires>
 
    <plugin
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml
index cb8477e..70ed137 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml
@@ -17,7 +17,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>5.10.1-SNAPSHOT</version>
+    <version>5.11.2-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml
index e055c0a..a7f0dd9 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.lfs"
       label="%featureName"
-      version="5.10.1.qualifier"
+      version="5.11.2.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
@@ -23,7 +23,7 @@
    </url>
 
    <requires>
-      <import feature="org.eclipse.jgit" version="5.10.1" match="equivalent"/>
+      <import feature="org.eclipse.jgit" version="5.11.2" match="equivalent"/>
    </requires>
 
    <plugin
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml
index 9303934..74d9992 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml
@@ -17,7 +17,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>5.10.1-SNAPSHOT</version>
+    <version>5.11.2-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml
index 6b23287..d009c0a 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.pgm"
       label="%featureName"
-      version="5.10.1.qualifier"
+      version="5.11.2.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
@@ -35,9 +35,9 @@
          version="0.0.0"/>
 
    <requires>
-      <import feature="org.eclipse.jgit" version="5.10.1" match="equivalent"/>
-      <import feature="org.eclipse.jgit.lfs" version="5.10.1" match="equivalent"/>
-      <import feature="org.eclipse.jgit.ssh.apache" version="5.10.1" match="equivalent"/>
+      <import feature="org.eclipse.jgit" version="5.11.2" match="equivalent"/>
+      <import feature="org.eclipse.jgit.lfs" version="5.11.2" match="equivalent"/>
+      <import feature="org.eclipse.jgit.ssh.apache" version="5.11.2" match="equivalent"/>
    </requires>
 
    <plugin
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml
index 0f8a36d..2c1a283 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml
@@ -17,7 +17,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>5.10.1-SNAPSHOT</version>
+    <version>5.11.2-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml
index 749416a..48497e5 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml
@@ -17,7 +17,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>5.10.1-SNAPSHOT</version>
+    <version>5.11.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.repository</artifactId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml
index 5149be9..4b0ff95 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.source"
       label="%featureName"
-      version="5.10.1.qualifier"
+      version="5.11.2.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
@@ -23,7 +23,7 @@
    </url>
 
    <requires>
-      <import feature="org.eclipse.jgit" version="5.10.1" match="equivalent"/>
+      <import feature="org.eclipse.jgit" version="5.11.2" match="equivalent"/>
    </requires>
 
    <plugin
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml
index f6cd493..0ca001c 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml
@@ -17,7 +17,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>5.10.1-SNAPSHOT</version>
+    <version>5.11.2-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
@@ -30,7 +30,7 @@
     <dependency>
       <groupId>org.eclipse.jgit.feature</groupId>
       <artifactId>org.eclipse.jgit</artifactId>
-      <version>5.10.1-SNAPSHOT</version>
+      <version>5.11.2-SNAPSHOT</version>
     </dependency>
   </dependencies>
 
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/feature.xml
index 1fdea7f..3c9004b 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.ssh.apache"
       label="%featureName"
-      version="5.10.1.qualifier"
+      version="5.11.2.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
@@ -23,7 +23,7 @@
    </url>
 
    <requires>
-      <import feature="org.eclipse.jgit" version="5.10.1" match="equivalent"/>
+      <import feature="org.eclipse.jgit" version="5.11.2" match="equivalent"/>
    </requires>
 
    <plugin
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/pom.xml
index 8f281ff..f563cff 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/pom.xml
@@ -17,7 +17,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>5.10.1-SNAPSHOT</version>
+    <version>5.11.2-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/feature.xml
index ec6421e..1bc9234 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jgit.ssh.jsch"
       label="%featureName"
-      version="5.10.1.qualifier"
+      version="5.11.2.qualifier"
       provider-name="%providerName">
 
    <description url="http://www.eclipse.org/jgit/">
@@ -23,7 +23,7 @@
    </url>
 
    <requires>
-      <import plugin="org.eclipse.jgit" version="5.10.1" match="equivalent"/>
+      <import plugin="org.eclipse.jgit" version="5.11.2" match="equivalent"/>
    </requires>
 
    <plugin
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/pom.xml
index 3f5fdef..526e18c 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/pom.xml
@@ -17,7 +17,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>5.10.1-SNAPSHOT</version>
+    <version>5.11.2-SNAPSHOT</version>
   </parent>
 
   <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF
index 679072d..43c0a83 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF
@@ -2,4 +2,4 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: JGit Target Platform Bundle
 Bundle-SymbolicName: org.eclipse.jgit.target
-Bundle-Version: 5.10.1.qualifier
+Bundle-Version: 5.11.2.qualifier
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target
index 6a02260..d37f5cc 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target
@@ -1,30 +1,32 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.10" sequenceNumber="1638642627">
+<target name="jgit-4.10" sequenceNumber="1638646045">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.30.v20200611"/>
-      <repository id="jetty-9.4.30" location="https://archive.eclipse.org/jetty/updates/jetty-bundles-9.x/jetty-bundles-9.x/9.4.30.v20200611/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.36.v20210114"/>
+      <repository id="jetty-9.4.36" location="https://archive.eclipse.org/jetty/updates/jetty-bundles-9.x/jetty-bundles-9.x/9.4.36.v20210114/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
-      <unit id="com.google.gson.source" version="2.8.2.v20180104-1110"/>
+      <unit id="com.google.gson" version="2.8.6.v20201231-1626"/>
+      <unit id="com.google.gson.source" version="2.8.6.v20201231-1626"/>
       <unit id="com.jcraft.jsch" version="0.1.55.v20190404-1902"/>
       <unit id="com.jcraft.jsch.source" version="0.1.55.v20190404-1902"/>
       <unit id="com.jcraft.jzlib" version="1.1.1.v201205102305"/>
@@ -47,16 +49,16 @@
       <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
       <unit id="org.apache.commons.logging" version="1.2.0.v20180409-1502"/>
       <unit id="org.apache.commons.logging.source" version="1.2.0.v20180409-1502"/>
-      <unit id="org.apache.httpcomponents.httpclient" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.sshd.osgi" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.osgi.source" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.sftp" version="2.4.0.v20200319-1547"/>
-      <unit id="org.apache.sshd.sftp.source" version="2.4.0.v20200319-1547"/>
+      <unit id="org.apache.sshd.osgi" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.osgi.source" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp.source" version="2.6.0.v20210201-2003"/>
       <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
       <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
       <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
@@ -84,7 +86,7 @@
       <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
       <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
       <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
-      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20201130205003/repository"/>
+      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20210223232630/repository"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.osgi" version="0.0.0"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.tpd
index 24a70f4..216ff56 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.tpd
@@ -1,7 +1,7 @@
 target "jgit-4.10" with source configurePhase
 
 include "projects/jetty-9.4.x.tpd"
-include "orbit/R20201130205003-2020-12.tpd"
+include "orbit/R20210223232630-2021-03.tpd"
 
 location "https://download.eclipse.org/releases/2018-12/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target
index a2ae129..0323bc7 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target
@@ -1,30 +1,32 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.11" sequenceNumber="1638642627">
+<target name="jgit-4.11" sequenceNumber="1638646045">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.30.v20200611"/>
-      <repository id="jetty-9.4.30" location="https://archive.eclipse.org/jetty/updates/jetty-bundles-9.x/jetty-bundles-9.x/9.4.30.v20200611/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.36.v20210114"/>
+      <repository id="jetty-9.4.36" location="https://archive.eclipse.org/jetty/updates/jetty-bundles-9.x/jetty-bundles-9.x/9.4.36.v20210114/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
-      <unit id="com.google.gson.source" version="2.8.2.v20180104-1110"/>
+      <unit id="com.google.gson" version="2.8.6.v20201231-1626"/>
+      <unit id="com.google.gson.source" version="2.8.6.v20201231-1626"/>
       <unit id="com.jcraft.jsch" version="0.1.55.v20190404-1902"/>
       <unit id="com.jcraft.jsch.source" version="0.1.55.v20190404-1902"/>
       <unit id="com.jcraft.jzlib" version="1.1.1.v201205102305"/>
@@ -47,16 +49,16 @@
       <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
       <unit id="org.apache.commons.logging" version="1.2.0.v20180409-1502"/>
       <unit id="org.apache.commons.logging.source" version="1.2.0.v20180409-1502"/>
-      <unit id="org.apache.httpcomponents.httpclient" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.sshd.osgi" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.osgi.source" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.sftp" version="2.4.0.v20200319-1547"/>
-      <unit id="org.apache.sshd.sftp.source" version="2.4.0.v20200319-1547"/>
+      <unit id="org.apache.sshd.osgi" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.osgi.source" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp.source" version="2.6.0.v20210201-2003"/>
       <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
       <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
       <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
@@ -84,7 +86,7 @@
       <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
       <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
       <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
-      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20201130205003/repository"/>
+      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20210223232630/repository"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.osgi" version="0.0.0"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.tpd
index df221e6..013d621 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.tpd
@@ -1,7 +1,7 @@
 target "jgit-4.11" with source configurePhase
 
 include "projects/jetty-9.4.x.tpd"
-include "orbit/R20201130205003-2020-12.tpd"
+include "orbit/R20210223232630-2021-03.tpd"
 
 location "https://download.eclipse.org/releases/2019-03/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.target
index 4ca8843..d0e3d4b 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.target
@@ -1,30 +1,32 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.12" sequenceNumber="1638642627">
+<target name="jgit-4.12" sequenceNumber="1638646045">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.30.v20200611"/>
-      <repository id="jetty-9.4.30" location="https://archive.eclipse.org/jetty/updates/jetty-bundles-9.x/jetty-bundles-9.x/9.4.30.v20200611/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.36.v20210114"/>
+      <repository id="jetty-9.4.36" location="https://archive.eclipse.org/jetty/updates/jetty-bundles-9.x/jetty-bundles-9.x/9.4.36.v20210114/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
-      <unit id="com.google.gson.source" version="2.8.2.v20180104-1110"/>
+      <unit id="com.google.gson" version="2.8.6.v20201231-1626"/>
+      <unit id="com.google.gson.source" version="2.8.6.v20201231-1626"/>
       <unit id="com.jcraft.jsch" version="0.1.55.v20190404-1902"/>
       <unit id="com.jcraft.jsch.source" version="0.1.55.v20190404-1902"/>
       <unit id="com.jcraft.jzlib" version="1.1.1.v201205102305"/>
@@ -47,16 +49,16 @@
       <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
       <unit id="org.apache.commons.logging" version="1.2.0.v20180409-1502"/>
       <unit id="org.apache.commons.logging.source" version="1.2.0.v20180409-1502"/>
-      <unit id="org.apache.httpcomponents.httpclient" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.sshd.osgi" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.osgi.source" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.sftp" version="2.4.0.v20200319-1547"/>
-      <unit id="org.apache.sshd.sftp.source" version="2.4.0.v20200319-1547"/>
+      <unit id="org.apache.sshd.osgi" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.osgi.source" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp.source" version="2.6.0.v20210201-2003"/>
       <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
       <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
       <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
@@ -84,7 +86,7 @@
       <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
       <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
       <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
-      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20201130205003/repository"/>
+      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20210223232630/repository"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.osgi" version="0.0.0"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.tpd
index 56fd714..99008ab 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.tpd
@@ -1,7 +1,7 @@
 target "jgit-4.12" with source configurePhase
 
 include "projects/jetty-9.4.x.tpd"
-include "orbit/R20201130205003-2020-12.tpd"
+include "orbit/R20210223232630-2021-03.tpd"
 
 location "https://download.eclipse.org/releases/2019-06/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.target
index 4367b5f..ef27e80 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.target
@@ -1,30 +1,32 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.13" sequenceNumber="1638642627">
+<target name="jgit-4.13" sequenceNumber="1638646045">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.30.v20200611"/>
-      <repository id="jetty-9.4.30" location="https://archive.eclipse.org/jetty/updates/jetty-bundles-9.x/jetty-bundles-9.x/9.4.30.v20200611/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.36.v20210114"/>
+      <repository id="jetty-9.4.36" location="https://archive.eclipse.org/jetty/updates/jetty-bundles-9.x/jetty-bundles-9.x/9.4.36.v20210114/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
-      <unit id="com.google.gson.source" version="2.8.2.v20180104-1110"/>
+      <unit id="com.google.gson" version="2.8.6.v20201231-1626"/>
+      <unit id="com.google.gson.source" version="2.8.6.v20201231-1626"/>
       <unit id="com.jcraft.jsch" version="0.1.55.v20190404-1902"/>
       <unit id="com.jcraft.jsch.source" version="0.1.55.v20190404-1902"/>
       <unit id="com.jcraft.jzlib" version="1.1.1.v201205102305"/>
@@ -47,16 +49,16 @@
       <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
       <unit id="org.apache.commons.logging" version="1.2.0.v20180409-1502"/>
       <unit id="org.apache.commons.logging.source" version="1.2.0.v20180409-1502"/>
-      <unit id="org.apache.httpcomponents.httpclient" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.sshd.osgi" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.osgi.source" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.sftp" version="2.4.0.v20200319-1547"/>
-      <unit id="org.apache.sshd.sftp.source" version="2.4.0.v20200319-1547"/>
+      <unit id="org.apache.sshd.osgi" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.osgi.source" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp.source" version="2.6.0.v20210201-2003"/>
       <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
       <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
       <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
@@ -84,7 +86,7 @@
       <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
       <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
       <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
-      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20201130205003/repository"/>
+      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20210223232630/repository"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.osgi" version="0.0.0"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.tpd
index 46069c3..d0db92c 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.tpd
@@ -1,7 +1,7 @@
 target "jgit-4.13" with source configurePhase
 
 include "projects/jetty-9.4.x.tpd"
-include "orbit/R20201130205003-2020-12.tpd"
+include "orbit/R20210223232630-2021-03.tpd"
 
 location "https://download.eclipse.org/releases/2019-09/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.14.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.14.target
index 32288ce..e4c4e0d 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.14.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.14.target
@@ -1,30 +1,32 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.14" sequenceNumber="1638642627">
+<target name="jgit-4.14" sequenceNumber="1638646045">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.30.v20200611"/>
-      <repository id="jetty-9.4.30" location="https://archive.eclipse.org/jetty/updates/jetty-bundles-9.x/jetty-bundles-9.x/9.4.30.v20200611/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.36.v20210114"/>
+      <repository id="jetty-9.4.36" location="https://archive.eclipse.org/jetty/updates/jetty-bundles-9.x/jetty-bundles-9.x/9.4.36.v20210114/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
-      <unit id="com.google.gson.source" version="2.8.2.v20180104-1110"/>
+      <unit id="com.google.gson" version="2.8.6.v20201231-1626"/>
+      <unit id="com.google.gson.source" version="2.8.6.v20201231-1626"/>
       <unit id="com.jcraft.jsch" version="0.1.55.v20190404-1902"/>
       <unit id="com.jcraft.jsch.source" version="0.1.55.v20190404-1902"/>
       <unit id="com.jcraft.jzlib" version="1.1.1.v201205102305"/>
@@ -47,16 +49,16 @@
       <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
       <unit id="org.apache.commons.logging" version="1.2.0.v20180409-1502"/>
       <unit id="org.apache.commons.logging.source" version="1.2.0.v20180409-1502"/>
-      <unit id="org.apache.httpcomponents.httpclient" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.sshd.osgi" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.osgi.source" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.sftp" version="2.4.0.v20200319-1547"/>
-      <unit id="org.apache.sshd.sftp.source" version="2.4.0.v20200319-1547"/>
+      <unit id="org.apache.sshd.osgi" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.osgi.source" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp.source" version="2.6.0.v20210201-2003"/>
       <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
       <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
       <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
@@ -84,7 +86,7 @@
       <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
       <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
       <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
-      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20201130205003/repository"/>
+      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20210223232630/repository"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.osgi" version="0.0.0"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.14.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.14.tpd
index dfc57fc..6b1e0f4 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.14.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.14.tpd
@@ -1,7 +1,7 @@
 target "jgit-4.14" with source configurePhase
 
 include "projects/jetty-9.4.x.tpd"
-include "orbit/R20201130205003-2020-12.tpd"
+include "orbit/R20210223232630-2021-03.tpd"
 
 location "https://download.eclipse.org/releases/2019-12/201912181000/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.15.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.15.target
index cd77494..d799873 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.15.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.15.target
@@ -1,30 +1,32 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.15" sequenceNumber="1638642627">
+<target name="jgit-4.15" sequenceNumber="1638646045">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.30.v20200611"/>
-      <repository id="jetty-9.4.30" location="https://archive.eclipse.org/jetty/updates/jetty-bundles-9.x/jetty-bundles-9.x/9.4.30.v20200611/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.36.v20210114"/>
+      <repository id="jetty-9.4.36" location="https://archive.eclipse.org/jetty/updates/jetty-bundles-9.x/jetty-bundles-9.x/9.4.36.v20210114/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
-      <unit id="com.google.gson.source" version="2.8.2.v20180104-1110"/>
+      <unit id="com.google.gson" version="2.8.6.v20201231-1626"/>
+      <unit id="com.google.gson.source" version="2.8.6.v20201231-1626"/>
       <unit id="com.jcraft.jsch" version="0.1.55.v20190404-1902"/>
       <unit id="com.jcraft.jsch.source" version="0.1.55.v20190404-1902"/>
       <unit id="com.jcraft.jzlib" version="1.1.1.v201205102305"/>
@@ -47,16 +49,16 @@
       <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
       <unit id="org.apache.commons.logging" version="1.2.0.v20180409-1502"/>
       <unit id="org.apache.commons.logging.source" version="1.2.0.v20180409-1502"/>
-      <unit id="org.apache.httpcomponents.httpclient" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.sshd.osgi" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.osgi.source" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.sftp" version="2.4.0.v20200319-1547"/>
-      <unit id="org.apache.sshd.sftp.source" version="2.4.0.v20200319-1547"/>
+      <unit id="org.apache.sshd.osgi" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.osgi.source" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp.source" version="2.6.0.v20210201-2003"/>
       <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
       <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
       <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
@@ -84,7 +86,7 @@
       <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
       <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
       <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
-      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20201130205003/repository"/>
+      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20210223232630/repository"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.osgi" version="0.0.0"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.15.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.15.tpd
index 1e4a0ee..773a9a9 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.15.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.15.tpd
@@ -1,7 +1,7 @@
 target "jgit-4.15" with source configurePhase
 
 include "projects/jetty-9.4.x.tpd"
-include "orbit/R20201130205003-2020-12.tpd"
+include "orbit/R20210223232630-2021-03.tpd"
 
 location "https://download.eclipse.org/releases/2020-03/202003181000/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.16.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.16.target
index ec0759c..5ff1efc 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.16.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.16.target
@@ -1,30 +1,32 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.16" sequenceNumber="1638642627">
+<target name="jgit-4.16" sequenceNumber="1638646045">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.30.v20200611"/>
-      <repository id="jetty-9.4.30" location="https://archive.eclipse.org/jetty/updates/jetty-bundles-9.x/jetty-bundles-9.x/9.4.30.v20200611/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.36.v20210114"/>
+      <repository id="jetty-9.4.36" location="https://archive.eclipse.org/jetty/updates/jetty-bundles-9.x/jetty-bundles-9.x/9.4.36.v20210114/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
-      <unit id="com.google.gson.source" version="2.8.2.v20180104-1110"/>
+      <unit id="com.google.gson" version="2.8.6.v20201231-1626"/>
+      <unit id="com.google.gson.source" version="2.8.6.v20201231-1626"/>
       <unit id="com.jcraft.jsch" version="0.1.55.v20190404-1902"/>
       <unit id="com.jcraft.jsch.source" version="0.1.55.v20190404-1902"/>
       <unit id="com.jcraft.jzlib" version="1.1.1.v201205102305"/>
@@ -47,16 +49,16 @@
       <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
       <unit id="org.apache.commons.logging" version="1.2.0.v20180409-1502"/>
       <unit id="org.apache.commons.logging.source" version="1.2.0.v20180409-1502"/>
-      <unit id="org.apache.httpcomponents.httpclient" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.sshd.osgi" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.osgi.source" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.sftp" version="2.4.0.v20200319-1547"/>
-      <unit id="org.apache.sshd.sftp.source" version="2.4.0.v20200319-1547"/>
+      <unit id="org.apache.sshd.osgi" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.osgi.source" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp.source" version="2.6.0.v20210201-2003"/>
       <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
       <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
       <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
@@ -84,7 +86,7 @@
       <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
       <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
       <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
-      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20201130205003/repository"/>
+      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20210223232630/repository"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.osgi" version="0.0.0"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.16.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.16.tpd
index 2435c48..8b4de8b 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.16.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.16.tpd
@@ -1,7 +1,7 @@
 target "jgit-4.16" with source configurePhase
 
 include "projects/jetty-9.4.x.tpd"
-include "orbit/R20201130205003-2020-12.tpd"
+include "orbit/R20210223232630-2021-03.tpd"
 
 location "https://download.eclipse.org/releases/2020-06/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.target
index e041087..1c3af70 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.target
@@ -1,30 +1,32 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.17-staging" sequenceNumber="1638642625">
+<target name="jgit-4.17" sequenceNumber="1638646045">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.30.v20200611"/>
-      <repository id="jetty-9.4.30" location="https://archive.eclipse.org/jetty/updates/jetty-bundles-9.x/jetty-bundles-9.x/9.4.30.v20200611/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.36.v20210114"/>
+      <repository id="jetty-9.4.36" location="https://archive.eclipse.org/jetty/updates/jetty-bundles-9.x/jetty-bundles-9.x/9.4.36.v20210114/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
-      <unit id="com.google.gson.source" version="2.8.2.v20180104-1110"/>
+      <unit id="com.google.gson" version="2.8.6.v20201231-1626"/>
+      <unit id="com.google.gson.source" version="2.8.6.v20201231-1626"/>
       <unit id="com.jcraft.jsch" version="0.1.55.v20190404-1902"/>
       <unit id="com.jcraft.jsch.source" version="0.1.55.v20190404-1902"/>
       <unit id="com.jcraft.jzlib" version="1.1.1.v201205102305"/>
@@ -39,24 +41,24 @@
       <unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/>
       <unit id="net.i2p.crypto.eddsa" version="0.3.0.v20181102-1323"/>
       <unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20181102-1323"/>
-      <unit id="org.apache.ant" version="1.10.8.v20200515-1239"/>
-      <unit id="org.apache.ant.source" version="1.10.8.v20200515-1239"/>
+      <unit id="org.apache.ant" version="1.10.9.v20201106-1946"/>
+      <unit id="org.apache.ant.source" version="1.10.9.v20201106-1946"/>
       <unit id="org.apache.commons.codec" version="1.14.0.v20200818-1422"/>
       <unit id="org.apache.commons.codec.source" version="1.14.0.v20200818-1422"/>
       <unit id="org.apache.commons.compress" version="1.19.0.v20200106-2343"/>
       <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
       <unit id="org.apache.commons.logging" version="1.2.0.v20180409-1502"/>
       <unit id="org.apache.commons.logging.source" version="1.2.0.v20180409-1502"/>
-      <unit id="org.apache.httpcomponents.httpclient" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.sshd.osgi" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.osgi.source" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.sftp" version="2.4.0.v20200319-1547"/>
-      <unit id="org.apache.sshd.sftp.source" version="2.4.0.v20200319-1547"/>
+      <unit id="org.apache.sshd.osgi" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.osgi.source" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp.source" version="2.6.0.v20210201-2003"/>
       <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
       <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
       <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
@@ -78,13 +80,13 @@
       <unit id="org.mockito.source" version="2.23.0.v20200310-1642"/>
       <unit id="org.objenesis" version="2.6.0.v20180420-1519"/>
       <unit id="org.objenesis.source" version="2.6.0.v20180420-1519"/>
-      <unit id="org.slf4j.api" version="1.7.2.v20121108-1250"/>
-      <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
-      <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
-      <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/>
+      <unit id="org.slf4j.api" version="1.7.30.v20200204-2150"/>
+      <unit id="org.slf4j.api.source" version="1.7.30.v20200204-2150"/>
+      <unit id="org.slf4j.binding.log4j12" version="1.7.30.v20201108-2042"/>
+      <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
       <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
       <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
-      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20200831200620/repository"/>
+      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20210223232630/repository"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.osgi" version="0.0.0"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.tpd
index e704318..b2585be 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.tpd
@@ -1,7 +1,7 @@
-target "jgit-4.17-staging" with source configurePhase
+target "jgit-4.17" with source configurePhase
 
 include "projects/jetty-9.4.x.tpd"
-include "orbit/R20200831200620-2020-09.tpd"
+include "orbit/R20210223232630-2021-03.tpd"
 
 location "https://download.eclipse.org/releases/2020-09/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.target
index 4362c7c..2944eb4 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.target
@@ -1,30 +1,32 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.18-staging" sequenceNumber="1638642639">
+<target name="jgit-4.18" sequenceNumber="1638646045">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.30.v20200611"/>
-      <repository id="jetty-9.4.30" location="https://archive.eclipse.org/jetty/updates/jetty-bundles-9.x/jetty-bundles-9.x/9.4.30.v20200611/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.36.v20210114"/>
+      <repository id="jetty-9.4.36" location="https://archive.eclipse.org/jetty/updates/jetty-bundles-9.x/jetty-bundles-9.x/9.4.36.v20210114/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
-      <unit id="com.google.gson.source" version="2.8.2.v20180104-1110"/>
+      <unit id="com.google.gson" version="2.8.6.v20201231-1626"/>
+      <unit id="com.google.gson.source" version="2.8.6.v20201231-1626"/>
       <unit id="com.jcraft.jsch" version="0.1.55.v20190404-1902"/>
       <unit id="com.jcraft.jsch.source" version="0.1.55.v20190404-1902"/>
       <unit id="com.jcraft.jzlib" version="1.1.1.v201205102305"/>
@@ -47,16 +49,16 @@
       <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
       <unit id="org.apache.commons.logging" version="1.2.0.v20180409-1502"/>
       <unit id="org.apache.commons.logging.source" version="1.2.0.v20180409-1502"/>
-      <unit id="org.apache.httpcomponents.httpclient" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.sshd.osgi" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.osgi.source" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.sftp" version="2.4.0.v20200319-1547"/>
-      <unit id="org.apache.sshd.sftp.source" version="2.4.0.v20200319-1547"/>
+      <unit id="org.apache.sshd.osgi" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.osgi.source" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp.source" version="2.6.0.v20210201-2003"/>
       <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
       <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
       <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
@@ -84,7 +86,7 @@
       <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
       <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
       <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
-      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20201130205003/repository"/>
+      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20210223232630/repository"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.osgi" version="0.0.0"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.tpd
index b457322..6d16256 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.tpd
@@ -1,7 +1,7 @@
-target "jgit-4.18-staging" with source configurePhase
+target "jgit-4.18" with source configurePhase
 
 include "projects/jetty-9.4.x.tpd"
-include "orbit/R20201130205003-2020-12.tpd"
+include "orbit/R20210223232630-2021-03.tpd"
 
 location "https://download.eclipse.org/releases/2020-12/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19.target
new file mode 100644
index 0000000..bce0169
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19.target
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?pde?>
+<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
+<target name="jgit-4.19" sequenceNumber="1638646047">
+  <locations>
+    <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
+      <unit id="org.eclipse.jetty.client" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.36.v20210114"/>
+      <repository id="jetty-9.4.36" location="https://archive.eclipse.org/jetty/updates/jetty-bundles-9.x/jetty-bundles-9.x/9.4.36.v20210114/"/>
+    </location>
+    <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
+      <unit id="com.google.gson" version="2.8.6.v20201231-1626"/>
+      <unit id="com.google.gson.source" version="2.8.6.v20201231-1626"/>
+      <unit id="com.jcraft.jsch" version="0.1.55.v20190404-1902"/>
+      <unit id="com.jcraft.jsch.source" version="0.1.55.v20190404-1902"/>
+      <unit id="com.jcraft.jzlib" version="1.1.1.v201205102305"/>
+      <unit id="com.jcraft.jzlib.source" version="1.1.1.v201205102305"/>
+      <unit id="javaewah" version="1.1.7.v20200107-0831"/>
+      <unit id="javaewah.source" version="1.1.7.v20200107-0831"/>
+      <unit id="javax.servlet" version="3.1.0.v201410161800"/>
+      <unit id="javax.servlet.source" version="3.1.0.v201410161800"/>
+      <unit id="net.bytebuddy.byte-buddy" version="1.9.0.v20181107-1410"/>
+      <unit id="net.bytebuddy.byte-buddy-agent" version="1.9.0.v20181106-1534"/>
+      <unit id="net.bytebuddy.byte-buddy-agent.source" version="1.9.0.v20181106-1534"/>
+      <unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/>
+      <unit id="net.i2p.crypto.eddsa" version="0.3.0.v20181102-1323"/>
+      <unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20181102-1323"/>
+      <unit id="org.apache.ant" version="1.10.9.v20201106-1946"/>
+      <unit id="org.apache.ant.source" version="1.10.9.v20201106-1946"/>
+      <unit id="org.apache.commons.codec" version="1.14.0.v20200818-1422"/>
+      <unit id="org.apache.commons.codec.source" version="1.14.0.v20200818-1422"/>
+      <unit id="org.apache.commons.compress" version="1.19.0.v20200106-2343"/>
+      <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
+      <unit id="org.apache.commons.logging" version="1.2.0.v20180409-1502"/>
+      <unit id="org.apache.commons.logging.source" version="1.2.0.v20180409-1502"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
+      <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
+      <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
+      <unit id="org.apache.sshd.osgi" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.osgi.source" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp.source" version="2.6.0.v20210201-2003"/>
+      <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
+      <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
+      <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
+      <unit id="org.bouncycastle.bcpg.source" version="1.65.0.v20200527-1955"/>
+      <unit id="org.bouncycastle.bcpkix" version="1.65.0.v20200527-1955"/>
+      <unit id="org.bouncycastle.bcpkix.source" version="1.65.0.v20200527-1955"/>
+      <unit id="org.bouncycastle.bcprov" version="1.65.1.v20200529-1514"/>
+      <unit id="org.bouncycastle.bcprov.source" version="1.65.1.v20200529-1514"/>
+      <unit id="org.hamcrest" version="1.1.0.v20090501071000"/>
+      <unit id="org.hamcrest.core" version="1.3.0.v20180420-1519"/>
+      <unit id="org.hamcrest.core.source" version="1.3.0.v20180420-1519"/>
+      <unit id="org.hamcrest.library" version="1.3.0.v20180524-2246"/>
+      <unit id="org.hamcrest.library.source" version="1.3.0.v20180524-2246"/>
+      <unit id="org.junit" version="4.13.0.v20200204-1500"/>
+      <unit id="org.junit.source" version="4.13.0.v20200204-1500"/>
+      <unit id="org.kohsuke.args4j" version="2.33.0.v20160323-2218"/>
+      <unit id="org.kohsuke.args4j.source" version="2.33.0.v20160323-2218"/>
+      <unit id="org.mockito" version="2.23.0.v20200310-1642"/>
+      <unit id="org.mockito.source" version="2.23.0.v20200310-1642"/>
+      <unit id="org.objenesis" version="2.6.0.v20180420-1519"/>
+      <unit id="org.objenesis.source" version="2.6.0.v20180420-1519"/>
+      <unit id="org.slf4j.api" version="1.7.30.v20200204-2150"/>
+      <unit id="org.slf4j.api.source" version="1.7.30.v20200204-2150"/>
+      <unit id="org.slf4j.binding.log4j12" version="1.7.30.v20201108-2042"/>
+      <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
+      <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
+      <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
+      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20210223232630/repository"/>
+    </location>
+    <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
+      <unit id="org.eclipse.osgi" version="0.0.0"/>
+      <repository location="https://download.eclipse.org/releases/2021-03/"/>
+    </location>
+  </locations>
+</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19.tpd
new file mode 100644
index 0000000..10ce05d
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19.tpd
@@ -0,0 +1,8 @@
+target "jgit-4.19" with source configurePhase
+
+include "projects/jetty-9.4.x.tpd"
+include "orbit/R20210223232630-2021-03.tpd"
+
+location "https://download.eclipse.org/releases/2021-03/" {
+	org.eclipse.osgi lazy
+}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target
index 210ffe2..278c3d2 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target
@@ -1,30 +1,32 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.6" sequenceNumber="1638642627">
+<target name="jgit-4.6" sequenceNumber="1638646045">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.30.v20200611"/>
-      <repository id="jetty-9.4.30" location="https://archive.eclipse.org/jetty/updates/jetty-bundles-9.x/jetty-bundles-9.x/9.4.30.v20200611/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.36.v20210114"/>
+      <repository id="jetty-9.4.36" location="https://archive.eclipse.org/jetty/updates/jetty-bundles-9.x/jetty-bundles-9.x/9.4.36.v20210114/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
-      <unit id="com.google.gson.source" version="2.8.2.v20180104-1110"/>
+      <unit id="com.google.gson" version="2.8.6.v20201231-1626"/>
+      <unit id="com.google.gson.source" version="2.8.6.v20201231-1626"/>
       <unit id="com.jcraft.jsch" version="0.1.55.v20190404-1902"/>
       <unit id="com.jcraft.jsch.source" version="0.1.55.v20190404-1902"/>
       <unit id="com.jcraft.jzlib" version="1.1.1.v201205102305"/>
@@ -47,16 +49,16 @@
       <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
       <unit id="org.apache.commons.logging" version="1.2.0.v20180409-1502"/>
       <unit id="org.apache.commons.logging.source" version="1.2.0.v20180409-1502"/>
-      <unit id="org.apache.httpcomponents.httpclient" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.sshd.osgi" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.osgi.source" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.sftp" version="2.4.0.v20200319-1547"/>
-      <unit id="org.apache.sshd.sftp.source" version="2.4.0.v20200319-1547"/>
+      <unit id="org.apache.sshd.osgi" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.osgi.source" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp.source" version="2.6.0.v20210201-2003"/>
       <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
       <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
       <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
@@ -84,7 +86,7 @@
       <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
       <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
       <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
-      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20201130205003/repository"/>
+      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20210223232630/repository"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.osgi" version="0.0.0"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd
index c7fbf02..6e7cd8b 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd
@@ -1,7 +1,7 @@
 target "jgit-4.6" with source configurePhase
 
 include "projects/jetty-9.4.x.tpd"
-include "orbit/R20201130205003-2020-12.tpd"
+include "orbit/R20210223232630-2021-03.tpd"
 
 location "https://download.eclipse.org/releases/neon/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target
index 0782ea0..461e1fe 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target
@@ -1,30 +1,32 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.7" sequenceNumber="1638642627">
+<target name="jgit-4.7" sequenceNumber="1638646045">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.30.v20200611"/>
-      <repository id="jetty-9.4.30" location="https://archive.eclipse.org/jetty/updates/jetty-bundles-9.x/jetty-bundles-9.x/9.4.30.v20200611/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.36.v20210114"/>
+      <repository id="jetty-9.4.36" location="https://archive.eclipse.org/jetty/updates/jetty-bundles-9.x/jetty-bundles-9.x/9.4.36.v20210114/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
-      <unit id="com.google.gson.source" version="2.8.2.v20180104-1110"/>
+      <unit id="com.google.gson" version="2.8.6.v20201231-1626"/>
+      <unit id="com.google.gson.source" version="2.8.6.v20201231-1626"/>
       <unit id="com.jcraft.jsch" version="0.1.55.v20190404-1902"/>
       <unit id="com.jcraft.jsch.source" version="0.1.55.v20190404-1902"/>
       <unit id="com.jcraft.jzlib" version="1.1.1.v201205102305"/>
@@ -47,16 +49,16 @@
       <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
       <unit id="org.apache.commons.logging" version="1.2.0.v20180409-1502"/>
       <unit id="org.apache.commons.logging.source" version="1.2.0.v20180409-1502"/>
-      <unit id="org.apache.httpcomponents.httpclient" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.sshd.osgi" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.osgi.source" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.sftp" version="2.4.0.v20200319-1547"/>
-      <unit id="org.apache.sshd.sftp.source" version="2.4.0.v20200319-1547"/>
+      <unit id="org.apache.sshd.osgi" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.osgi.source" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp.source" version="2.6.0.v20210201-2003"/>
       <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
       <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
       <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
@@ -84,7 +86,7 @@
       <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
       <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
       <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
-      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20201130205003/repository"/>
+      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20210223232630/repository"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.osgi" version="0.0.0"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd
index 585e04b..5a58b00 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd
@@ -1,7 +1,7 @@
 target "jgit-4.7" with source configurePhase
 
 include "projects/jetty-9.4.x.tpd"
-include "orbit/R20201130205003-2020-12.tpd"
+include "orbit/R20210223232630-2021-03.tpd"
 
 location "https://download.eclipse.org/releases/oxygen/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target
index 7b7f3c8..c88f472 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target
@@ -1,30 +1,32 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.8" sequenceNumber="1638642627">
+<target name="jgit-4.8" sequenceNumber="1638646045">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.30.v20200611"/>
-      <repository id="jetty-9.4.30" location="https://archive.eclipse.org/jetty/updates/jetty-bundles-9.x/jetty-bundles-9.x/9.4.30.v20200611/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.36.v20210114"/>
+      <repository id="jetty-9.4.36" location="https://archive.eclipse.org/jetty/updates/jetty-bundles-9.x/jetty-bundles-9.x/9.4.36.v20210114/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
-      <unit id="com.google.gson.source" version="2.8.2.v20180104-1110"/>
+      <unit id="com.google.gson" version="2.8.6.v20201231-1626"/>
+      <unit id="com.google.gson.source" version="2.8.6.v20201231-1626"/>
       <unit id="com.jcraft.jsch" version="0.1.55.v20190404-1902"/>
       <unit id="com.jcraft.jsch.source" version="0.1.55.v20190404-1902"/>
       <unit id="com.jcraft.jzlib" version="1.1.1.v201205102305"/>
@@ -47,16 +49,16 @@
       <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
       <unit id="org.apache.commons.logging" version="1.2.0.v20180409-1502"/>
       <unit id="org.apache.commons.logging.source" version="1.2.0.v20180409-1502"/>
-      <unit id="org.apache.httpcomponents.httpclient" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.sshd.osgi" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.osgi.source" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.sftp" version="2.4.0.v20200319-1547"/>
-      <unit id="org.apache.sshd.sftp.source" version="2.4.0.v20200319-1547"/>
+      <unit id="org.apache.sshd.osgi" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.osgi.source" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp.source" version="2.6.0.v20210201-2003"/>
       <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
       <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
       <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
@@ -84,7 +86,7 @@
       <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
       <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
       <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
-      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20201130205003/repository"/>
+      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20210223232630/repository"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.osgi" version="0.0.0"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd
index 694fc67..3114877 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd
@@ -1,7 +1,7 @@
 target "jgit-4.8" with source configurePhase
 
 include "projects/jetty-9.4.x.tpd"
-include "orbit/R20201130205003-2020-12.tpd"
+include "orbit/R20210223232630-2021-03.tpd"
 
 location "https://download.eclipse.org/releases/photon/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target
index 37c17f3..3670fa8 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target
@@ -1,30 +1,32 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.9" sequenceNumber="1638642627">
+<target name="jgit-4.9" sequenceNumber="1638646045">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.eclipse.jetty.client" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.client.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.continuation" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.continuation.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.http" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.http.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.io" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.io.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.security" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.security.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.server" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.server.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.servlet" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.servlet.source" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.util" version="9.4.30.v20200611"/>
-      <unit id="org.eclipse.jetty.util.source" version="9.4.30.v20200611"/>
-      <repository id="jetty-9.4.30" location="https://archive.eclipse.org/jetty/updates/jetty-bundles-9.x/jetty-bundles-9.x/9.4.30.v20200611/"/>
+      <unit id="org.eclipse.jetty.client" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.client.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.continuation.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.http.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.io.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.security.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.server.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.servlet.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.source" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax" version="9.4.36.v20210114"/>
+      <unit id="org.eclipse.jetty.util.ajax.source" version="9.4.36.v20210114"/>
+      <repository id="jetty-9.4.36" location="https://archive.eclipse.org/jetty/updates/jetty-bundles-9.x/jetty-bundles-9.x/9.4.36.v20210114/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
-      <unit id="com.google.gson.source" version="2.8.2.v20180104-1110"/>
+      <unit id="com.google.gson" version="2.8.6.v20201231-1626"/>
+      <unit id="com.google.gson.source" version="2.8.6.v20201231-1626"/>
       <unit id="com.jcraft.jsch" version="0.1.55.v20190404-1902"/>
       <unit id="com.jcraft.jsch.source" version="0.1.55.v20190404-1902"/>
       <unit id="com.jcraft.jzlib" version="1.1.1.v201205102305"/>
@@ -47,16 +49,16 @@
       <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
       <unit id="org.apache.commons.logging" version="1.2.0.v20180409-1502"/>
       <unit id="org.apache.commons.logging.source" version="1.2.0.v20180409-1502"/>
-      <unit id="org.apache.httpcomponents.httpclient" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
-      <unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
-      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
       <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
       <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
-      <unit id="org.apache.sshd.osgi" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.osgi.source" version="2.4.0.v20200318-1614"/>
-      <unit id="org.apache.sshd.sftp" version="2.4.0.v20200319-1547"/>
-      <unit id="org.apache.sshd.sftp.source" version="2.4.0.v20200319-1547"/>
+      <unit id="org.apache.sshd.osgi" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.osgi.source" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp" version="2.6.0.v20210201-2003"/>
+      <unit id="org.apache.sshd.sftp.source" version="2.6.0.v20210201-2003"/>
       <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
       <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
       <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
@@ -84,7 +86,7 @@
       <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
       <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
       <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
-      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20201130205003/repository"/>
+      <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20210223232630/repository"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.osgi" version="0.0.0"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd
index ae5390c..132a0b0 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd
@@ -1,7 +1,7 @@
 target "jgit-4.9" with source configurePhase
 
 include "projects/jetty-9.4.x.tpd"
-include "orbit/R20201130205003-2020-12.tpd"
+include "orbit/R20210223232630-2021-03.tpd"
 
 location "https://download.eclipse.org/releases/2018-09/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20210223232630-2021-03.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20210223232630-2021-03.tpd
new file mode 100644
index 0000000..605a43b
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20210223232630-2021-03.tpd
@@ -0,0 +1,66 @@
+target "R20210223232630-2021-03" with source configurePhase
+// see https://download.eclipse.org/tools/orbit/downloads/
+
+location "https://download.eclipse.org/tools/orbit/downloads/drops/R20210223232630/repository" {
+	com.google.gson [2.8.6.v20201231-1626,2.8.6.v20201231-1626]
+	com.google.gson.source [2.8.6.v20201231-1626,2.8.6.v20201231-1626]
+	com.jcraft.jsch [0.1.55.v20190404-1902,0.1.55.v20190404-1902]
+	com.jcraft.jsch.source [0.1.55.v20190404-1902,0.1.55.v20190404-1902]
+	com.jcraft.jzlib [1.1.1.v201205102305,1.1.1.v201205102305]
+	com.jcraft.jzlib.source [1.1.1.v201205102305,1.1.1.v201205102305]
+	javaewah [1.1.7.v20200107-0831,1.1.7.v20200107-0831]
+	javaewah.source [1.1.7.v20200107-0831,1.1.7.v20200107-0831]
+	javax.servlet [3.1.0.v201410161800,3.1.0.v201410161800]
+	javax.servlet.source [3.1.0.v201410161800,3.1.0.v201410161800]
+	net.bytebuddy.byte-buddy [1.9.0.v20181107-1410,1.9.0.v20181107-1410]
+	net.bytebuddy.byte-buddy-agent [1.9.0.v20181106-1534,1.9.0.v20181106-1534]
+	net.bytebuddy.byte-buddy-agent.source [1.9.0.v20181106-1534,1.9.0.v20181106-1534]
+	net.bytebuddy.byte-buddy.source [1.9.0.v20181107-1410,1.9.0.v20181107-1410]
+	net.i2p.crypto.eddsa [0.3.0.v20181102-1323,0.3.0.v20181102-1323]
+	net.i2p.crypto.eddsa.source [0.3.0.v20181102-1323,0.3.0.v20181102-1323]
+	org.apache.ant [1.10.9.v20201106-1946,1.10.9.v20201106-1946]
+	org.apache.ant.source [1.10.9.v20201106-1946,1.10.9.v20201106-1946]
+	org.apache.commons.codec [1.14.0.v20200818-1422,1.14.0.v20200818-1422]
+	org.apache.commons.codec.source [1.14.0.v20200818-1422,1.14.0.v20200818-1422]
+	org.apache.commons.compress [1.19.0.v20200106-2343,1.19.0.v20200106-2343]
+	org.apache.commons.compress.source [1.19.0.v20200106-2343,1.19.0.v20200106-2343]
+	org.apache.commons.logging [1.2.0.v20180409-1502,1.2.0.v20180409-1502]
+	org.apache.commons.logging.source [1.2.0.v20180409-1502,1.2.0.v20180409-1502]
+	org.apache.httpcomponents.httpclient [4.5.13.v20210128-2225,4.5.13.v20210128-2225]
+	org.apache.httpcomponents.httpclient.source [4.5.13.v20210128-2225,4.5.13.v20210128-2225]
+	org.apache.httpcomponents.httpcore [4.4.14.v20210128-2225,4.4.14.v20210128-2225]
+	org.apache.httpcomponents.httpcore.source [4.4.14.v20210128-2225,4.4.14.v20210128-2225]
+	org.apache.log4j [1.2.15.v201012070815,1.2.15.v201012070815]
+	org.apache.log4j.source [1.2.15.v201012070815,1.2.15.v201012070815]
+	org.apache.sshd.osgi [2.6.0.v20210201-2003,2.6.0.v20210201-2003]
+	org.apache.sshd.osgi.source [2.6.0.v20210201-2003,2.6.0.v20210201-2003]
+	org.apache.sshd.sftp [2.6.0.v20210201-2003,2.6.0.v20210201-2003]
+	org.apache.sshd.sftp.source [2.6.0.v20210201-2003,2.6.0.v20210201-2003]
+	org.assertj [3.14.0.v20200120-1926,3.14.0.v20200120-1926]
+	org.assertj.source [3.14.0.v20200120-1926,3.14.0.v20200120-1926]
+	org.bouncycastle.bcpg [1.65.0.v20200527-1955,1.65.0.v20200527-1955]
+	org.bouncycastle.bcpg.source [1.65.0.v20200527-1955,1.65.0.v20200527-1955]
+	org.bouncycastle.bcpkix [1.65.0.v20200527-1955,1.65.0.v20200527-1955]
+	org.bouncycastle.bcpkix.source [1.65.0.v20200527-1955,1.65.0.v20200527-1955]
+	org.bouncycastle.bcprov [1.65.1.v20200529-1514,1.65.1.v20200529-1514]
+	org.bouncycastle.bcprov.source [1.65.1.v20200529-1514,1.65.1.v20200529-1514]
+	org.hamcrest [1.1.0.v20090501071000,1.1.0.v20090501071000]
+	org.hamcrest.core [1.3.0.v20180420-1519,1.3.0.v20180420-1519]
+	org.hamcrest.core.source [1.3.0.v20180420-1519,1.3.0.v20180420-1519]
+	org.hamcrest.library [1.3.0.v20180524-2246,1.3.0.v20180524-2246]
+	org.hamcrest.library.source [1.3.0.v20180524-2246,1.3.0.v20180524-2246]
+	org.junit [4.13.0.v20200204-1500,4.13.0.v20200204-1500]
+	org.junit.source [4.13.0.v20200204-1500,4.13.0.v20200204-1500]
+	org.kohsuke.args4j [2.33.0.v20160323-2218,2.33.0.v20160323-2218]
+	org.kohsuke.args4j.source [2.33.0.v20160323-2218,2.33.0.v20160323-2218]
+	org.mockito [2.23.0.v20200310-1642,2.23.0.v20200310-1642]
+	org.mockito.source [2.23.0.v20200310-1642,2.23.0.v20200310-1642]
+	org.objenesis [2.6.0.v20180420-1519,2.6.0.v20180420-1519]
+	org.objenesis.source [2.6.0.v20180420-1519,2.6.0.v20180420-1519]
+	org.slf4j.api [1.7.30.v20200204-2150,1.7.30.v20200204-2150]
+	org.slf4j.api.source [1.7.30.v20200204-2150,1.7.30.v20200204-2150]
+	org.slf4j.binding.log4j12 [1.7.30.v20201108-2042,1.7.30.v20201108-2042]
+	org.slf4j.binding.log4j12.source [1.7.30.v20201108-2042,1.7.30.v20201108-2042]
+	org.tukaani.xz [1.8.0.v20180207-1613,1.8.0.v20180207-1613]
+	org.tukaani.xz.source [1.8.0.v20180207-1613,1.8.0.v20180207-1613]
+}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml
index a0b4931..70f7cea 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml
@@ -16,7 +16,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>jgit.tycho.parent</artifactId>
-    <version>5.10.1-SNAPSHOT</version>
+    <version>5.11.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.target</artifactId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.x.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.x.tpd
index f76d500..3dfd2a9 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.x.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.x.tpd
@@ -1,20 +1,22 @@
 target "jetty-9.4.x" with source configurePhase
 
-location jetty-9.4.30 "https://archive.eclipse.org/jetty/updates/jetty-bundles-9.x/jetty-bundles-9.x/9.4.30.v20200611/" {
-	org.eclipse.jetty.client [9.4.30.v20200611,9.4.30.v20200611]
-	org.eclipse.jetty.client.source [9.4.30.v20200611,9.4.30.v20200611]
-	org.eclipse.jetty.continuation [9.4.30.v20200611,9.4.30.v20200611]
-	org.eclipse.jetty.continuation.source [9.4.30.v20200611,9.4.30.v20200611]
-	org.eclipse.jetty.http [9.4.30.v20200611,9.4.30.v20200611]
-	org.eclipse.jetty.http.source [9.4.30.v20200611,9.4.30.v20200611]
-	org.eclipse.jetty.io [9.4.30.v20200611,9.4.30.v20200611]
-	org.eclipse.jetty.io.source [9.4.30.v20200611,9.4.30.v20200611]
-	org.eclipse.jetty.security [9.4.30.v20200611,9.4.30.v20200611]
-	org.eclipse.jetty.security.source [9.4.30.v20200611,9.4.30.v20200611]
-	org.eclipse.jetty.server [9.4.30.v20200611,9.4.30.v20200611]
-	org.eclipse.jetty.server.source [9.4.30.v20200611,9.4.30.v20200611]
-	org.eclipse.jetty.servlet [9.4.30.v20200611,9.4.30.v20200611]
-	org.eclipse.jetty.servlet.source [9.4.30.v20200611,9.4.30.v20200611]
-	org.eclipse.jetty.util [9.4.30.v20200611,9.4.30.v20200611]
-	org.eclipse.jetty.util.source [9.4.30.v20200611,9.4.30.v20200611]
+location jetty-9.4.36 "https://archive.eclipse.org/jetty/updates/jetty-bundles-9.x/jetty-bundles-9.x/9.4.36.v20210114/" {
+	org.eclipse.jetty.client [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.client.source [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.continuation [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.continuation.source [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.http [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.http.source [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.io [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.io.source [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.security [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.security.source [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.server [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.server.source [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.servlet [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.servlet.source [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.util [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.util.source [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.util.ajax [9.4.36.v20210114,9.4.36.v20210114]
+	org.eclipse.jetty.util.ajax.source [9.4.36.v20210114,9.4.36.v20210114]
 }
diff --git a/org.eclipse.jgit.packaging/pom.xml b/org.eclipse.jgit.packaging/pom.xml
index 14eb409..f51a642 100644
--- a/org.eclipse.jgit.packaging/pom.xml
+++ b/org.eclipse.jgit.packaging/pom.xml
@@ -16,7 +16,7 @@
 
   <groupId>org.eclipse.jgit</groupId>
   <artifactId>jgit.tycho.parent</artifactId>
-  <version>5.10.1-SNAPSHOT</version>
+  <version>5.11.2-SNAPSHOT</version>
   <packaging>pom</packaging>
 
   <name>JGit Tycho Parent</name>
@@ -165,7 +165,7 @@
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-enforcer-plugin</artifactId>
-        <version>3.0.0-M1</version>
+        <version>3.0.0-M3</version>
         <executions>
           <execution>
             <id>enforce-maven</id>
@@ -175,7 +175,7 @@
             <configuration>
               <rules>
                 <requireMavenVersion>
-                  <version>3.5.2</version>
+                  <version>3.6.3</version>
                 </requireMavenVersion>
               </rules>
             </configuration>
@@ -299,7 +299,7 @@
         <plugin>
           <groupId>org.codehaus.mojo</groupId>
           <artifactId>build-helper-maven-plugin</artifactId>
-          <version>3.0.0</version>
+          <version>3.2.0</version>
         </plugin>
         <plugin>
           <artifactId>maven-clean-plugin</artifactId>
@@ -318,7 +318,7 @@
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-site-plugin</artifactId>
-          <version>3.8.2</version>
+          <version>3.9.1</version>
         </plugin>
       </plugins>
     </pluginManagement>
diff --git a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
index 891d217..ae67125 100644
--- a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
@@ -3,28 +3,28 @@
 Bundle-Name: %Bundle-Name
 Automatic-Module-Name: org.eclipse.jgit.pgm.test
 Bundle-SymbolicName: org.eclipse.jgit.pgm.test
-Bundle-Version: 5.10.1.qualifier
+Bundle-Version: 5.11.2.qualifier
 Bundle-Vendor: %Bundle-Vendor
 Bundle-Localization: plugin
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.eclipse.jgit.api;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.api.errors;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.diff;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.dircache;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.internal.storage.file;version="5.10.1",
- org.eclipse.jgit.junit;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lib;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.merge;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.pgm;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.pgm.internal;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.pgm.opt;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.revwalk;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.storage.file;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.transport;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.treewalk;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.util;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.util.io;version="[5.10.1,5.11.0)",
+Import-Package: org.eclipse.jgit.api;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.api.errors;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.diff;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.dircache;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.internal.storage.file;version="5.11.2",
+ org.eclipse.jgit.junit;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.lib;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.merge;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.pgm;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.pgm.internal;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.pgm.opt;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.revwalk;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.storage.file;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.transport;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.treewalk;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.util;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.util.io;version="[5.11.2,5.12.0)",
  org.hamcrest.core;bundle-version="[1.1.0,2.0.0)",
  org.junit;version="[4.13,5.0.0)",
  org.junit.rules;version="[4.13,5.0.0)",
diff --git a/org.eclipse.jgit.pgm.test/pom.xml b/org.eclipse.jgit.pgm.test/pom.xml
index ab17f1d..ca908a4 100644
--- a/org.eclipse.jgit.pgm.test/pom.xml
+++ b/org.eclipse.jgit.pgm.test/pom.xml
@@ -17,7 +17,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.10.1-SNAPSHOT</version>
+    <version>5.11.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.pgm.test</artifactId>
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CloneTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CloneTest.java
index 2f09b7f..4cbd61c 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CloneTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CloneTest.java
@@ -11,7 +11,9 @@
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 
 import java.io.File;
@@ -25,6 +27,7 @@
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.StoredConfig;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.transport.RefSpec;
@@ -64,6 +67,45 @@ public void testClone() throws Exception {
 		assertEquals("expected 1 branch", 1, branches.size());
 	}
 
+	@Test
+	public void testCloneInitialBranch() throws Exception {
+		createInitialCommit();
+
+		File gitDir = db.getDirectory();
+		String sourceURI = gitDir.toURI().toString();
+		File target = createTempDirectory("target");
+		String cmd = "git clone --branch master " + sourceURI + " "
+				+ shellQuote(target.getPath());
+		String[] result = execute(cmd);
+		assertArrayEquals(new String[] {
+				"Cloning into '" + target.getPath() + "'...", "", "" }, result);
+
+		Git git2 = Git.open(target);
+		List<Ref> branches = git2.branchList().call();
+		assertEquals("expected 1 branch", 1, branches.size());
+
+		Repository db2 = git2.getRepository();
+		ObjectId head = db2.resolve("HEAD");
+		assertNotNull(head);
+		assertNotEquals(ObjectId.zeroId(), head);
+		ObjectId master = db2.resolve("master");
+		assertEquals(head, master);
+	}
+
+	@Test
+	public void testCloneInitialBranchMissing() throws Exception {
+		createInitialCommit();
+
+		File gitDir = db.getDirectory();
+		String sourceURI = gitDir.toURI().toString();
+		File target = createTempDirectory("target");
+		String cmd = "git clone --branch foo " + sourceURI + " "
+				+ shellQuote(target.getPath());
+		Die e = assertThrows(Die.class, () -> execute(cmd));
+		assertEquals("Remote branch 'foo' not found in upstream origin",
+				e.getMessage());
+	}
+
 	private RevCommit createInitialCommit() throws Exception {
 		JGitTestUtil.writeTrashFile(db, "hello.txt", "world");
 		git.add().addFilepattern("hello.txt").call();
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/InitTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/InitTest.java
index 84474e3..88789d3 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/InitTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/InitTest.java
@@ -11,11 +11,14 @@
 package org.eclipse.jgit.pgm;
 
 import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
 
 import java.io.File;
 
+import org.eclipse.jgit.internal.storage.file.FileRepository;
 import org.eclipse.jgit.lib.CLIRepositoryTestCase;
 import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.Repository;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
@@ -54,4 +57,22 @@ public void testInitDirectory() throws Exception {
 		assertArrayEquals(expecteds, result);
 	}
 
+	@Test
+	public void testInitDirectoryInitialBranch() throws Exception {
+		File workDirectory = tempFolder.getRoot();
+		File gitDirectory = new File(workDirectory, Constants.DOT_GIT);
+
+		String[] result = execute(
+				"git init -b main '" + workDirectory.getCanonicalPath() + "'");
+
+		String[] expecteds = new String[] {
+				"Initialized empty Git repository in "
+						+ gitDirectory.getCanonicalPath(),
+				"" };
+		assertArrayEquals(expecteds, result);
+
+		try (Repository repo = new FileRepository(gitDirectory)) {
+			assertEquals("refs/heads/main", repo.getFullBranch());
+		}
+	}
 }
diff --git a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
index 419d754..9200d3b 100644
--- a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
@@ -3,58 +3,57 @@
 Bundle-Name: %Bundle-Name
 Automatic-Module-Name: org.eclipse.jgit.pgm
 Bundle-SymbolicName: org.eclipse.jgit.pgm
-Bundle-Version: 5.10.1.qualifier
+Bundle-Version: 5.11.2.qualifier
 Bundle-Vendor: %Bundle-Vendor
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Import-Package: javax.servlet;version="[3.1.0,4.0.0)",
+ org.apache.commons.logging;version="[1.2,2.0)",
  org.eclipse.jetty.server;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.server.handler;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.servlet;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.util;version="[9.4.5,10.0.0)",
  org.eclipse.jetty.util.component;version="[9.4.5,10.0.0)",
- org.eclipse.jgit.api;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.api.errors;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.archive;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.awtui;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.blame;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.diff;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.dircache;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.errors;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.gitrepo;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.internal.ketch;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.internal.storage.file;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.internal.storage.io;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.internal.storage.pack;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.internal.storage.reftable;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.internal.storage.reftree;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lfs;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lfs.server;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lfs.server.fs;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lfs.server.s3;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.lib;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.merge;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.nls;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.notes;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.revplot;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.revwalk;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.revwalk.filter;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.storage.file;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.storage.pack;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.transport;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.transport.http.apache;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.transport.resolver;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.transport.sshd;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.treewalk;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.treewalk.filter;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.util;version="[5.10.1,5.11.0)",
- org.eclipse.jgit.util.io;version="[5.10.1,5.11.0)",
+ org.eclipse.jgit.api;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.api.errors;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.archive;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.awtui;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.blame;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.diff;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.dircache;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.errors;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.gitrepo;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.internal.storage.file;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.internal.storage.io;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.internal.storage.reftable;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.lfs;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.lfs.server;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.lfs.server.fs;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.lfs.server.s3;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.lib;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.merge;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.nls;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.notes;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.revplot;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.revwalk;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.revwalk.filter;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.storage.file;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.storage.pack;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.transport;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.transport.http.apache;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.transport.resolver;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.transport.sshd;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.treewalk;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.treewalk.filter;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.util;version="[5.11.2,5.12.0)",
+ org.eclipse.jgit.util.io;version="[5.11.2,5.12.0)",
  org.kohsuke.args4j;version="[2.33.0,3.0.0)",
  org.kohsuke.args4j.spi;version="[2.33.0,3.0.0)"
-Export-Package: org.eclipse.jgit.console;version="5.10.1";
+Export-Package: org.eclipse.jgit.console;version="5.11.2";
  uses:="org.eclipse.jgit.transport,
   org.eclipse.jgit.util",
- org.eclipse.jgit.pgm;version="5.10.1";
+ org.eclipse.jgit.pgm;version="5.11.2";
   uses:="org.eclipse.jgit.transport,
    org.eclipse.jgit.util.io,
    org.eclipse.jgit.awtui,
@@ -66,14 +65,14 @@
    org.eclipse.jgit.treewalk,
    org.eclipse.jgit.api,
    javax.swing",
- org.eclipse.jgit.pgm.debug;version="5.10.1";
+ org.eclipse.jgit.pgm.debug;version="5.11.2";
   uses:="org.eclipse.jgit.util.io,
    org.eclipse.jgit.pgm,
    org.eclipse.jetty.servlet",
- org.eclipse.jgit.pgm.internal;version="5.10.1";
+ org.eclipse.jgit.pgm.internal;version="5.11.2";
   x-friends:="org.eclipse.jgit.pgm.test,
    org.eclipse.jgit.test",
- org.eclipse.jgit.pgm.opt;version="5.10.1";
+ org.eclipse.jgit.pgm.opt;version="5.11.2";
   uses:="org.kohsuke.args4j,
    org.eclipse.jgit.lib,
    org.eclipse.jgit.revwalk,
diff --git a/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF
index 2464093..df01339 100644
--- a/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
 Bundle-Name: org.eclipse.jgit.pgm - Sources
 Bundle-SymbolicName: org.eclipse.jgit.pgm.source
 Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 5.10.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="5.10.1.qualifier";roots="."
+Bundle-Version: 5.11.2.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="5.11.2.qualifier";roots="."
diff --git a/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin b/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin
index 062b964..e645255 100644
--- a/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin
+++ b/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin
@@ -47,7 +47,6 @@
 org.eclipse.jgit.pgm.debug.ReadDirCache
 org.eclipse.jgit.pgm.debug.ReadReftable
 org.eclipse.jgit.pgm.debug.RebuildCommitGraph
-org.eclipse.jgit.pgm.debug.RebuildRefTree
 org.eclipse.jgit.pgm.debug.ShowCacheTree
 org.eclipse.jgit.pgm.debug.ShowCommands
 org.eclipse.jgit.pgm.debug.ShowDirCache
diff --git a/org.eclipse.jgit.pgm/pom.xml b/org.eclipse.jgit.pgm/pom.xml
index b00ade3..c07e146 100644
--- a/org.eclipse.jgit.pgm/pom.xml
+++ b/org.eclipse.jgit.pgm/pom.xml
@@ -17,7 +17,7 @@
   <parent>
     <groupId>org.eclipse.jgit</groupId>
     <artifactId>org.eclipse.jgit-parent</artifactId>
-    <version>5.10.1-SNAPSHOT</version>
+    <version>5.11.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>org.eclipse.jgit.pgm</artifactId>
diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
index 6112a27..83846ee 100644
--- a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
+++ b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
@@ -77,14 +77,15 @@
 invalidRecurseSubmodulesMode=Invalid recurse submodules mode: {0}
 invalidUntrackedFilesMode=Invalid untracked files mode ''{0}''
 jgitVersion=jgit version {0}
-lineFormat={0}
-listeningOn=Listening on {0}
 lfsNoAccessKey=No accessKey in {0}
 lfsNoSecretKey=No secretKey in {0}
 lfsProtocolUrl=LFS protocol URL: {0}
 lfsStoreDirectory=LFS objects stored in: {0}
 lfsStoreUrl=LFS store URL: {0}
 lfsUnknownStoreType="Unknown LFS store type: {0}"
+lineFormat={0}
+listeningOn=Listening on {0}
+logNoSignatureVerifier="No signature verifier available"
 mergeConflict=CONFLICT(content): Merge conflict in {0}
 mergeCheckoutConflict=error: Your local changes to the following files would be overwritten by merge:
 mergeFailed=Automatic merge failed; fix conflicts and then commit the result
@@ -118,7 +119,6 @@
 metaVar_filepattern=filepattern
 metaVar_gitDir=GIT_DIR
 metaVar_hostName=HOSTNAME
-metaVar_ketchServerType=SERVERTYPE
 metaVar_lfsStorage=STORAGE
 metaVar_linesOfContext=lines
 metaVar_message=message
@@ -143,6 +143,7 @@
 metaVar_s3StorageClass=STORAGE-CLASS
 metaVar_seconds=SECONDS
 metaVar_service=SERVICE
+metaVar_tagLocalUser=<GPG key ID>
 metaVar_treeish=tree-ish
 metaVar_uriish=uri-ish
 metaVar_url=URL
@@ -246,7 +247,6 @@
 usage_Gc=Cleanup unnecessary files and optimize the local repository
 usage_Glog=View commit history as a graph
 usage_IndexPack=Build pack index file for an existing packed archive
-usage_ketchServerType=Ketch server type
 usage_LFSDirectory=Directory to store large objects
 usage_LFSPort=Server http port
 usage_LFSRunStore=Store (fs | s3), store lfs objects in file system or Amazon S3
@@ -266,8 +266,6 @@
 usage_PrunePreserved=Remove the preserved subdirectory containing previously preserved old pack files before repacking, and before preserving more old pack files
 usage_ReadDirCache= Read the DirCache 100 times
 usage_RebuildCommitGraph=Recreate a repository from another one's commit graph
-usage_RebuildRefTree=Copy references into a RefTree
-usage_RebuildRefTreeEnable=set extensions.refStorage = reftree
 usage_Remote=Manage set of tracked repositories
 usage_RepositoryToReadFrom=Repository to read from
 usage_RepositoryToReceiveInto=Repository to receive into
@@ -414,6 +412,7 @@
 usage_showRefNamesMatchingCommits=Show ref names matching commits
 usage_showPatch=display patch
 usage_showNotes=Add this ref to the list of note branches from which notes are displayed
+usage_showSignature=Verify signatures of signed commits in the log
 usage_showTimeInMilliseconds=Show mtime in milliseconds
 usage_squash=Squash commits as if a real merge happened, but do not make a commit or move the HEAD.
 usage_srcPrefix=show the source prefix instead of "a/"
@@ -421,13 +420,19 @@
 usage_symbolicVersionForTheProject=Symbolic version for the project
 usage_tags=fetch all tags
 usage_notags=do not fetch tags
+usage_tagAnnotated=create an annotated tag, unsigned unless -s or -u are given, or config tag.gpgSign is true
 usage_tagDelete=delete tag
-usage_tagMessage=tag message
+usage_tagLocalUser=create a signed annotated tag using the specified GPG key ID
+usage_tagMessage=create an annotated tag with the given message, unsigned unless -s or -u are given, or config tag.gpgSign is true, or tar.forceSignAnnotated is true and -a is not given
+usage_tagSign=create a signed annotated tag
+usage_tagNoSign=suppress signing the tag
+usage_tagVerify=Verify the GPG signature
 usage_untrackedFilesMode=show untracked files
 usage_updateRef=reference to update
 usage_updateRemoteRefsFromAnotherRepository=Update remote refs from another repository
 usage_useNameInsteadOfOriginToTrackUpstream=use <name> instead of 'origin' to track upstream
 usage_checkoutBranchAfterClone=check out named branch instead of remote's HEAD
+usage_initialBranch=initial branch of the newly created repository (default 'master', can be configured via config option init.defaultBranch)
 usage_viewCommitHistory=View commit history
 usage_orphan=Create a new orphan branch. The first commit made on this new branch will have no parents and it will be the root of a new history totally disconnected from other branches and commits.
 usernameFor=Username for {0}:
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java
index 8f80d6d..f28915d 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java
@@ -18,6 +18,7 @@
 import org.eclipse.jgit.api.CloneCommand;
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.errors.InvalidRemoteException;
+import org.eclipse.jgit.api.errors.TransportException;
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.TextProgressMonitor;
@@ -50,6 +51,9 @@ class Clone extends AbstractFetchCommand implements CloneCommand.Callback {
 	@Option(name = "--recurse-submodules", usage = "usage_recurseSubmodules")
 	private boolean cloneSubmodules;
 
+	@Option(name = "--timeout", metaVar = "metaVar_seconds", usage = "usage_abortConnectionIfNoActivity")
+	int timeout = -1;
+
 	@Argument(index = 0, required = true, metaVar = "metaVar_uriish")
 	private String sourceUri;
 
@@ -90,9 +94,8 @@ protected void run() throws Exception {
 
 		CloneCommand command = Git.cloneRepository();
 		command.setURI(sourceUri).setRemote(remoteName).setBare(isBare)
-				.setMirror(isMirror)
-				.setNoCheckout(noCheckout).setBranch(branch)
-				.setCloneSubmodules(cloneSubmodules);
+				.setMirror(isMirror).setNoCheckout(noCheckout).setBranch(branch)
+				.setCloneSubmodules(cloneSubmodules).setTimeout(timeout);
 
 		command.setGitDir(gitdir == null ? null : new File(gitdir));
 		command.setDirectory(localNameF);
@@ -108,6 +111,8 @@ protected void run() throws Exception {
 			db = command.call().getRepository();
 			if (msgs && db.resolve(Constants.HEAD) == null)
 				outw.println(CLIText.get().clonedEmptyRepository);
+		} catch (TransportException e) {
+			throw die(e.getMessage(), e);
 		} catch (InvalidRemoteException e) {
 			throw die(MessageFormat.format(CLIText.get().doesNotExist,
 					sourceUri), e);
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Daemon.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Daemon.java
index bf91025..f987f2c 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Daemon.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Daemon.java
@@ -13,19 +13,12 @@
 import java.io.File;
 import java.io.IOException;
 import java.net.InetSocketAddress;
-import java.net.URISyntaxException;
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.Executors;
 
 import org.eclipse.jgit.errors.ConfigInvalidException;
-import org.eclipse.jgit.internal.ketch.KetchLeader;
-import org.eclipse.jgit.internal.ketch.KetchLeaderCache;
-import org.eclipse.jgit.internal.ketch.KetchPreReceive;
-import org.eclipse.jgit.internal.ketch.KetchSystem;
-import org.eclipse.jgit.internal.ketch.KetchText;
-import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.StoredConfig;
 import org.eclipse.jgit.pgm.internal.CLIText;
 import org.eclipse.jgit.storage.file.FileBasedConfig;
@@ -33,10 +26,7 @@
 import org.eclipse.jgit.storage.pack.PackConfig;
 import org.eclipse.jgit.transport.DaemonClient;
 import org.eclipse.jgit.transport.DaemonService;
-import org.eclipse.jgit.transport.ReceivePack;
 import org.eclipse.jgit.transport.resolver.FileResolver;
-import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
-import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
 import org.eclipse.jgit.util.FS;
 import org.eclipse.jgit.util.SystemReader;
 import org.kohsuke.args4j.Argument;
@@ -71,13 +61,6 @@ class Daemon extends TextBuiltin {
 	@Option(name = "--export-all", usage = "usage_exportWithoutGitDaemonExportOk")
 	boolean exportAll;
 
-	@Option(name = "--ketch", metaVar = "metaVar_ketchServerType", usage = "usage_ketchServerType")
-	KetchServerType ketchServerType;
-
-	enum KetchServerType {
-		LEADER;
-	}
-
 	@Argument(required = true, metaVar = "metaVar_directory", usage = "usage_directoriesToExport")
 	List<File> directory = new ArrayList<>();
 
@@ -102,9 +85,9 @@ protected void run() throws Exception {
 			}
 			cfg = new FileBasedConfig(configFile, FS.DETECTED);
 		}
-		cfg.load();
-		new WindowCacheConfig().fromConfig(cfg).install();
-		packConfig.fromConfig(cfg);
+			cfg.load();
+			new WindowCacheConfig().fromConfig(cfg).install();
+			packConfig.fromConfig(cfg);
 
 		int threads = packConfig.getThreads();
 		if (threads <= 0)
@@ -137,9 +120,6 @@ protected void run() throws Exception {
 			service(d, n).setOverridable(true);
 		for (String n : forbidOverride)
 			service(d, n).setOverridable(false);
-		if (ketchServerType == KetchServerType.LEADER) {
-			startKetchLeader(d);
-		}
 		d.start();
 		outw.println(MessageFormat.format(CLIText.get().listeningOn, d.getAddress()));
 	}
@@ -162,24 +142,4 @@ private static DaemonService service(
 			throw die(MessageFormat.format(CLIText.get().serviceNotSupported, n));
 		return svc;
 	}
-
-	private void startKetchLeader(org.eclipse.jgit.transport.Daemon daemon) {
-		KetchSystem system = new KetchSystem();
-		final KetchLeaderCache leaders = new KetchLeaderCache(system);
-		final ReceivePackFactory<DaemonClient> factory;
-
-		factory = daemon.getReceivePackFactory();
-		daemon.setReceivePackFactory((DaemonClient req, Repository repo) -> {
-			ReceivePack rp = factory.create(req, repo);
-			KetchLeader leader;
-			try {
-				leader = leaders.get(repo);
-			} catch (URISyntaxException err) {
-				throw new ServiceNotEnabledException(
-						KetchText.get().invalidFollowerUri, err);
-			}
-			rp.setPreReceiveHook(new KetchPreReceive(leader));
-			return rp;
-		});
-	}
 }
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Init.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Init.java
index 7f59ef4..7a0d96d 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Init.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Init.java
@@ -24,6 +24,7 @@
 import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.pgm.internal.CLIText;
+import org.eclipse.jgit.util.StringUtils;
 import org.kohsuke.args4j.Argument;
 import org.kohsuke.args4j.Option;
 
@@ -32,6 +33,10 @@ class Init extends TextBuiltin {
 	@Option(name = "--bare", usage = "usage_CreateABareRepository")
 	private boolean bare;
 
+	@Option(name = "--initial-branch", aliases = { "-b" },
+			metaVar = "metaVar_branchName", usage = "usage_initialBranch")
+	private String branch;
+
 	@Argument(index = 0, metaVar = "metaVar_directory")
 	private String directory;
 
@@ -54,6 +59,9 @@ protected void run() {
 		}
 		Repository repository;
 		try {
+			if (!StringUtils.isEmptyOrNull(branch)) {
+				command.setInitialBranch(branch);
+			}
 			repository = command.call().getRepository();
 			outw.println(MessageFormat.format(
 					CLIText.get().initializedEmptyGitRepositoryIn,
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java
index 55efd23..353b64b 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2010, Google Inc.
- * Copyright (C) 2006-2008, Robin Rosenberg <robin.rosenberg@dewire.com>
- * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others
+ * Copyright (C) 2006, 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2008, 2021, Shawn O. Pearce <spearce@spearce.org> 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
@@ -31,12 +31,17 @@
 import org.eclipse.jgit.errors.LargeObjectException;
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.GpgConfig;
+import org.eclipse.jgit.lib.GpgSignatureVerifier;
+import org.eclipse.jgit.lib.GpgSignatureVerifier.SignatureVerification;
+import org.eclipse.jgit.lib.GpgSignatureVerifierFactory;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.PersonIdent;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.notes.NoteMap;
 import org.eclipse.jgit.pgm.internal.CLIText;
+import org.eclipse.jgit.pgm.internal.VerificationUtils;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevTree;
 import org.eclipse.jgit.util.GitDateFormatter;
@@ -68,6 +73,9 @@ void addAdditionalNoteRef(String notesRef) {
 		additionalNoteRefs.add(notesRef);
 	}
 
+	@Option(name = "--show-signature", usage = "usage_showSignature")
+	private boolean showSignature;
+
 	@Option(name = "--date", usage = "usage_date")
 	void dateFormat(String date) {
 		if (date.toLowerCase(Locale.ROOT).equals(date))
@@ -147,6 +155,10 @@ void noPrefix(@SuppressWarnings("unused") boolean on) {
 	// END -- Options shared with Diff
 
 
+	private GpgSignatureVerifier verifier;
+
+	private GpgConfig config;
+
 	Log() {
 		dateFormatter = new GitDateFormatter(Format.DEFAULT);
 	}
@@ -161,6 +173,7 @@ protected void init(Repository repository, String gitDir) {
 	/** {@inheritDoc} */
 	@Override
 	protected void run() {
+		config = new GpgConfig(db.getConfig());
 		diffFmt.setRepository(db);
 		try {
 			diffFmt.setPathFilter(pathFilter);
@@ -197,6 +210,9 @@ protected void run() {
 			throw die(e.getMessage(), e);
 		} finally {
 			diffFmt.close();
+			if (verifier != null) {
+				verifier.clear();
+			}
 		}
 	}
 
@@ -229,6 +245,9 @@ protected void show(RevCommit c) throws Exception {
 		}
 		outw.println();
 
+		if (showSignature) {
+			showSignature(c);
+		}
 		final PersonIdent author = c.getAuthorIdent();
 		outw.println(MessageFormat.format(CLIText.get().authorInfo, author.getName(), author.getEmailAddress()));
 		outw.println(MessageFormat.format(CLIText.get().dateInfo,
@@ -252,6 +271,27 @@ protected void show(RevCommit c) throws Exception {
 		outw.flush();
 	}
 
+	private void showSignature(RevCommit c) throws IOException {
+		if (c.getRawGpgSignature() == null) {
+			return;
+		}
+		if (verifier == null) {
+			GpgSignatureVerifierFactory factory = GpgSignatureVerifierFactory
+					.getDefault();
+			if (factory == null) {
+				throw die(CLIText.get().logNoSignatureVerifier, null);
+			}
+			verifier = factory.getVerifier();
+		}
+		SignatureVerification verification = verifier.verifySignature(c,
+				config);
+		if (verification == null) {
+			return;
+		}
+		VerificationUtils.writeVerification(outw, verification,
+				verifier.getName(), c.getCommitterIdent());
+	}
+
 	/**
 	 * @param c
 	 * @return <code>true</code> if at least one note was printed,
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsRemote.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsRemote.java
index 055b48a..83446cc 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsRemote.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsRemote.java
@@ -79,7 +79,7 @@ private void show(AnyObjectId id, String name)
 
 	private void show(Ref ref, String name)
 			throws IOException {
-		outw.print("ref: ");
+		outw.print("ref: "); //$NON-NLS-1$
 		outw.print(ref.getName());
 		outw.print('\t');
 		outw.print(name);
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Show.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Show.java
index 5f9551e..3beab60 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Show.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Show.java
@@ -29,10 +29,15 @@
 import org.eclipse.jgit.errors.RevisionSyntaxException;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.GpgConfig;
+import org.eclipse.jgit.lib.GpgSignatureVerifier;
+import org.eclipse.jgit.lib.GpgSignatureVerifierFactory;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.PersonIdent;
 import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.GpgSignatureVerifier.SignatureVerification;
 import org.eclipse.jgit.pgm.internal.CLIText;
+import org.eclipse.jgit.pgm.internal.VerificationUtils;
 import org.eclipse.jgit.pgm.opt.PathTreeFilterHandler;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevObject;
@@ -41,6 +46,7 @@
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.treewalk.TreeWalk;
 import org.eclipse.jgit.treewalk.filter.TreeFilter;
+import org.eclipse.jgit.util.RawParseUtils;
 import org.kohsuke.args4j.Argument;
 import org.kohsuke.args4j.Option;
 
@@ -58,6 +64,9 @@ class Show extends TextBuiltin {
 	@Option(name = "--", metaVar = "metaVar_path", handler = PathTreeFilterHandler.class)
 	protected TreeFilter pathFilter = TreeFilter.ALL;
 
+	@Option(name = "--show-signature", usage = "usage_showSignature")
+	private boolean showSignature;
+
 	// BEGIN -- Options shared with Diff
 	@Option(name = "-p", usage = "usage_showPatch")
 	boolean showPatch;
@@ -219,13 +228,20 @@ private void show(RevTag tag) throws IOException {
 		}
 
 		outw.println();
-		final String[] lines = tag.getFullMessage().split("\n"); //$NON-NLS-1$
-		for (String s : lines) {
-			outw.print("    "); //$NON-NLS-1$
-			outw.print(s);
-			outw.println();
+		String fullMessage = tag.getFullMessage();
+		if (!fullMessage.isEmpty()) {
+			String[] lines = tag.getFullMessage().split("\n"); //$NON-NLS-1$
+			for (String s : lines) {
+				outw.println(s);
+			}
 		}
-
+		byte[] rawSignature = tag.getRawGpgSignature();
+		if (rawSignature != null) {
+			String[] lines = RawParseUtils.decode(rawSignature).split("\n"); //$NON-NLS-1$
+			for (String s : lines) {
+				outw.println(s);
+			}
+		}
 		outw.println();
 	}
 
@@ -253,6 +269,10 @@ private void show(RevWalk rw, RevCommit c) throws IOException {
 		c.getId().copyTo(outbuffer, outw);
 		outw.println();
 
+		if (showSignature) {
+			showSignature(c);
+		}
+
 		final PersonIdent author = c.getAuthorIdent();
 		outw.println(MessageFormat.format(CLIText.get().authorInfo,
 				author.getName(), author.getEmailAddress()));
@@ -291,4 +311,28 @@ private void showDiff(RevCommit c) throws IOException {
 		}
 		outw.println();
 	}
+
+	private void showSignature(RevCommit c) throws IOException {
+		if (c.getRawGpgSignature() == null) {
+			return;
+		}
+		GpgSignatureVerifierFactory factory = GpgSignatureVerifierFactory
+				.getDefault();
+		if (factory == null) {
+			throw die(CLIText.get().logNoSignatureVerifier, null);
+		}
+		GpgSignatureVerifier verifier = factory.getVerifier();
+		GpgConfig config = new GpgConfig(db.getConfig());
+		try {
+			SignatureVerification verification = verifier.verifySignature(c,
+					config);
+			if (verification == null) {
+				return;
+			}
+			VerificationUtils.writeVerification(outw, verification,
+					verifier.getName(), c.getCommitterIdent());
+		} finally {
+			verifier.clear();
+		}
+	}
 }
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java
index b408b78..e2cd31d 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java
@@ -4,7 +4,7 @@
  * Copyright (C) 2008, Charles O'Farrell <charleso@charleso.org>
  * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg.lists@dewire.com>
  * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
- * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others
+ * Copyright (C) 2008, 2021 Shawn O. Pearce <spearce@spearce.org> 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
@@ -22,26 +22,59 @@
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.ListTagCommand;
 import org.eclipse.jgit.api.TagCommand;
+import org.eclipse.jgit.api.VerificationResult;
+import org.eclipse.jgit.api.VerifySignatureCommand;
 import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.GpgSignatureVerifier.SignatureVerification;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.pgm.internal.CLIText;
+import org.eclipse.jgit.pgm.internal.VerificationUtils;
+import org.eclipse.jgit.revwalk.RevTag;
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.kohsuke.args4j.Argument;
 import org.kohsuke.args4j.Option;
 
 @Command(common = true, usage = "usage_CreateATag")
 class Tag extends TextBuiltin {
-	@Option(name = "-f", usage = "usage_forceReplacingAnExistingTag")
+
+	@Option(name = "--force", aliases = { "-f" }, forbids = { "--delete",
+			"--verify" }, usage = "usage_forceReplacingAnExistingTag")
 	private boolean force;
 
-	@Option(name = "-d", usage = "usage_tagDelete")
+	@Option(name = "--delete", aliases = { "-d" }, forbids = {
+			"--verify" }, usage = "usage_tagDelete")
 	private boolean delete;
 
-	@Option(name = "-m", metaVar = "metaVar_message", usage = "usage_tagMessage")
-	private String message = ""; //$NON-NLS-1$
+	@Option(name = "--annotate", aliases = {
+			"-a" }, forbids = { "--delete",
+					"--verify" }, usage = "usage_tagAnnotated")
+	private boolean annotated;
+
+	@Option(name = "-m", forbids = { "--delete",
+			"--verify" }, metaVar = "metaVar_message", usage = "usage_tagMessage")
+	private String message;
+
+	@Option(name = "--sign", aliases = { "-s" }, forbids = {
+			"--no-sign", "--delete", "--verify" }, usage = "usage_tagSign")
+	private boolean sign;
+
+	@Option(name = "--no-sign", usage = "usage_tagNoSign", forbids = {
+			"--sign", "--delete", "--verify" })
+	private boolean noSign;
+
+	@Option(name = "--local-user", aliases = {
+			"-u" }, forbids = { "--delete",
+					"--verify" }, metaVar = "metaVar_tagLocalUser", usage = "usage_tagLocalUser")
+	private String gpgKeyId;
+
+	@Option(name = "--verify", aliases = { "-v" }, forbids = { "--delete",
+			"--force", "--annotate", "-m", "--sign", "--no-sign",
+			"--local-user" }, usage = "usage_tagVerify")
+	private boolean verify;
 
 	@Argument(index = 0, metaVar = "metaVar_name")
 	private String tagName;
@@ -54,7 +87,25 @@ class Tag extends TextBuiltin {
 	protected void run() {
 		try (Git git = new Git(db)) {
 			if (tagName != null) {
-				if (delete) {
+				if (verify) {
+					VerifySignatureCommand verifySig = git.verifySignature()
+							.setMode(VerifySignatureCommand.VerifyMode.TAGS)
+							.addName(tagName);
+
+					VerificationResult verification = verifySig.call()
+							.get(tagName);
+					if (verification == null) {
+						showUnsigned(git, tagName);
+					} else {
+						Throwable error = verification.getException();
+						if (error != null) {
+							throw die(error.getMessage(), error);
+						}
+						writeVerification(verifySig.getVerifier().getName(),
+								(RevTag) verification.getObject(),
+								verification.getVerification());
+					}
+				} else if (delete) {
 					List<String> deletedTags = git.tagDelete().setTags(tagName)
 							.call();