Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEd Merks2022-01-14 12:48:14 +0000
committerEd Merks2022-01-15 04:56:31 +0000
commitb40860241cf12625c3611f00649c5d1d88aeafa1 (patch)
tree7c10183b88aa56b3243ce67834caf65c665d1139
parentc193e5197535846f3f546f0e9ce210660c190484 (diff)
downloadrt.equinox.p2-b40860241cf12625c3611f00649c5d1d88aeafa1.tar.gz
rt.equinox.p2-b40860241cf12625c3611f00649c5d1d88aeafa1.tar.xz
rt.equinox.p2-b40860241cf12625c3611f00649c5d1d88aeafa1.zip
Bug 578024 - Improve the TrustCertificateDialog
Provide support for computing the verified certifications of all known keys and use this to display the web-of-trust information in the trust certificate dialog. Also support "Copy Fingerprint" for PGP keys in the certificate chain viewer. Change-Id: I2039b585911def54cf888d91ab5bc6ee8606ddb2 Signed-off-by: Ed Merks <ed.merks@gmail.com> Reviewed-on: https://git.eclipse.org/r/c/equinox/rt.equinox.p2/+/189634 Tested-by: Equinox Bot <equinox-bot@eclipse.org>
-rw-r--r--bundles/org.eclipse.equinox.p2.artifact.repository/META-INF/MANIFEST.MF2
-rw-r--r--bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/processors/pgp/PGPSignatureVerifier.java48
-rw-r--r--bundles/org.eclipse.equinox.p2.ui/META-INF/MANIFEST.MF1
-rw-r--r--bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/ValidationDialogServiceUI.java35
-rw-r--r--bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/dialogs/TrustCertificateDialog.java44
-rw-r--r--bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/messages.properties4
6 files changed, 124 insertions, 10 deletions
diff --git a/bundles/org.eclipse.equinox.p2.artifact.repository/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.p2.artifact.repository/META-INF/MANIFEST.MF
index 49e639b77..05dc70a3c 100644
--- a/bundles/org.eclipse.equinox.p2.artifact.repository/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.p2.artifact.repository/META-INF/MANIFEST.MF
@@ -10,7 +10,7 @@ Export-Package: org.eclipse.equinox.internal.p2.artifact.processing;x-friends:="
org.eclipse.equinox.internal.p2.artifact.processors.checksum;x-friends:="org.eclipse.equinox.p2.publisher",
org.eclipse.equinox.internal.p2.artifact.processors.md5;x-internal:=true,
org.eclipse.equinox.internal.p2.artifact.processors.pack200;x-friends:="org.eclipse.equinox.p2.artifact.processors,org.eclipse.equinox.p2.artifact.optimizers",
- org.eclipse.equinox.internal.p2.artifact.processors.pgp;x-friends:="org.eclipse.equinox.p2.engine,org.eclipse.equinox.p2.ui.sdk",
+ org.eclipse.equinox.internal.p2.artifact.processors.pgp;x-friends:="org.eclipse.equinox.p2.engine,org.eclipse.equinox.p2.ui.sdk,org.eclipse.equinox.p2.ui",
org.eclipse.equinox.internal.p2.artifact.repository;
x-friends:="org.eclipse.equinox.p2.publisher,
org.eclipse.equinox.p2.reconciler.dropins,
diff --git a/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/processors/pgp/PGPSignatureVerifier.java b/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/processors/pgp/PGPSignatureVerifier.java
index 5a06ec3b7..410214f8b 100644
--- a/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/processors/pgp/PGPSignatureVerifier.java
+++ b/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/processors/pgp/PGPSignatureVerifier.java
@@ -47,6 +47,54 @@ public final class PGPSignatureVerifier extends ProcessingStep {
link(nullOutputStream(), new NullProgressMonitor()); // this is convenience for tests
}
+ public static Map<PGPPublicKey, Set<PGPPublicKey>> getVerifiedKnownKeyCertifications() {
+ Map<PGPPublicKey, Set<PGPPublicKey>> result = new LinkedHashMap<>();
+ for (PGPPublicKey key : KNOWN_KEYS.all()) {
+ Set<PGPPublicKey> certifications = new LinkedHashSet<>();
+ for (Iterator<PGPSignature> signatures = key.getSignatures(); signatures.hasNext();) {
+ PGPSignature signature = signatures.next();
+ long signingKeyID = signature.getKeyID();
+ PGPPublicKey signingKey = KNOWN_KEYS.getKey(signingKeyID);
+ if (signingKey != null) {
+ switch (signature.getSignatureType()) {
+ case PGPSignature.SUBKEY_BINDING:
+ case PGPSignature.PRIMARYKEY_BINDING: {
+ try {
+ signature.init(new BcPGPContentVerifierBuilderProvider(), signingKey);
+ if (signature.verifyCertification(signingKey, key)) {
+ certifications.add(signingKey);
+ }
+ } catch (PGPException e) {
+ //$FALL-THROUGH$
+ }
+ break;
+ }
+ case PGPSignature.DEFAULT_CERTIFICATION:
+ case PGPSignature.NO_CERTIFICATION:
+ case PGPSignature.CASUAL_CERTIFICATION:
+ case PGPSignature.POSITIVE_CERTIFICATION: {
+ for (Iterator<String> userIDs = key.getUserIDs(); userIDs.hasNext();) {
+ String userID = userIDs.next();
+ try {
+ signature.init(new BcPGPContentVerifierBuilderProvider(), signingKey);
+ if (signature.verifyCertification(userID, key)) {
+ certifications.add(signingKey);
+ break;
+ }
+ } catch (PGPException e) {
+ //$FALL-THROUGH$
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ result.put(key, certifications);
+ }
+ return result;
+ }
+
public static Collection<PGPSignature> getSignatures(IArtifactDescriptor artifact)
throws IOException, PGPException {
String signatureText = unnormalizedPGPProperty(artifact.getProperty(PGP_SIGNATURES_PROPERTY_NAME));
diff --git a/bundles/org.eclipse.equinox.p2.ui/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.p2.ui/META-INF/MANIFEST.MF
index 036afa9cb..9a353459c 100644
--- a/bundles/org.eclipse.equinox.p2.ui/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.p2.ui/META-INF/MANIFEST.MF
@@ -39,6 +39,7 @@ Import-Package: javax.xml.parsers,
org.bouncycastle.bcpg;version="1.65.0",
org.bouncycastle.openpgp;version="1.65.0",
org.bouncycastle.util;version="1.65.1",
+ org.eclipse.equinox.internal.p2.artifact.processors.pgp,
org.eclipse.equinox.internal.p2.artifact.repository,
org.eclipse.equinox.internal.p2.core.helpers,
org.eclipse.equinox.internal.p2.director,
diff --git a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/ValidationDialogServiceUI.java b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/ValidationDialogServiceUI.java
index 482fe4844..e0dd88651 100644
--- a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/ValidationDialogServiceUI.java
+++ b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/ValidationDialogServiceUI.java
@@ -21,6 +21,7 @@ import java.util.List;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.equinox.internal.p2.artifact.processors.pgp.PGPSignatureVerifier;
import org.eclipse.equinox.internal.p2.ui.dialogs.TrustCertificateDialog;
import org.eclipse.equinox.internal.p2.ui.dialogs.UserValidationDialog;
import org.eclipse.equinox.p2.core.UIServices;
@@ -208,13 +209,41 @@ public class ValidationDialogServiceUI extends UIServices {
parent = node;
}
}
- for (PGPPublicKey key : untrustedPublicKeys) {
- children[i] = new TreeNode(key);
- i++;
+
+ if (!untrustedPublicKeys.isEmpty()) {
+ Map<PGPPublicKey, Set<PGPPublicKey>> verifiedKnownKeyCertifications = PGPSignatureVerifier
+ .getVerifiedKnownKeyCertifications();
+ for (PGPPublicKey key : untrustedPublicKeys) {
+ children[i] = createTreeNode(key, verifiedKnownKeyCertifications, new HashSet<>());
+ i++;
+ }
}
return children;
}
+ private TreeNode createTreeNode(PGPPublicKey key,
+ Map<PGPPublicKey, Set<PGPPublicKey>> verifiedKnownKeyCertification, Set<PGPPublicKey> visited) {
+ if (visited.add(key)) {
+ TreeNode result = new TreeNode(key);
+ List<TreeNode> children = new ArrayList<>();
+ Set<PGPPublicKey> visitedChildren = new LinkedHashSet<>();
+ Set<PGPPublicKey> certifications = verifiedKnownKeyCertification.get(key);
+ if (certifications != null) {
+ for (PGPPublicKey certifyingKey : certifications) {
+ if (!visited.contains(certifyingKey) && visitedChildren.add(certifyingKey)) {
+ children.add(createTreeNode(certifyingKey, verifiedKnownKeyCertification, visited));
+ }
+ }
+ }
+ if (!children.isEmpty()) {
+ result.setChildren(children.toArray(TreeNode[]::new));
+ children.forEach(child -> child.setParent(result));
+ }
+ return result;
+ }
+ return null;
+ }
+
@Override
public AuthenticationInfo getUsernamePassword(final String location, final AuthenticationInfo previousInfo) {
final AuthenticationInfo[] result = new AuthenticationInfo[1];
diff --git a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/dialogs/TrustCertificateDialog.java b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/dialogs/TrustCertificateDialog.java
index 23fcf9b35..fa4395143 100644
--- a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/dialogs/TrustCertificateDialog.java
+++ b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/dialogs/TrustCertificateDialog.java
@@ -133,8 +133,46 @@ public class TrustCertificateDialog extends SelectionDialog {
certificateChainViewer.getTree().setLayoutData(data);
certificateChainViewer.setAutoExpandLevel(AbstractTreeViewer.ALL_LEVELS);
certificateChainViewer.setContentProvider(new TreeNodeContentProvider());
- certificateChainViewer.setLabelProvider(new CertificateLabelProvider());
+ certificateChainViewer.setLabelProvider(new CertificateLabelProvider() {
+ @Override
+ public String getText(Object element) {
+ if (element instanceof TreeNode) {
+ Object o = ((TreeNode) element).getValue();
+ if (o instanceof PGPPublicKey) {
+ PGPPublicKey key = (PGPPublicKey) o;
+ String userFriendlyFingerPrint = userFriendlyFingerPrint(key);
+ java.util.List<String> users = new ArrayList<>();
+ key.getUserIDs().forEachRemaining(users::add);
+ String userIDs = String.join(",", users); //$NON-NLS-1$
+ if (!userIDs.isEmpty()) {
+ return userFriendlyFingerPrint + " [" + userIDs + "]"; //$NON-NLS-1$//$NON-NLS-2$
+ }
+ return userFriendlyFingerPrint;
+ }
+ }
+ return super.getText(element);
+ }
+ });
certificateChainViewer.addSelectionChangedListener(getChainSelectionListener());
+ Menu menu = new Menu(certificateChainViewer.getTree());
+ certificateChainViewer.getTree().setMenu(menu);
+ MenuItem item = new MenuItem(menu, SWT.PUSH);
+ item.setText(ProvUIMessages.TrustCertificateDialog_CopyFingerprint);
+ item.addSelectionListener(widgetSelectedAdapter(e -> {
+ Object o = ((IStructuredSelection) certificateChainViewer.getSelection()).getFirstElement();
+ if (o instanceof TreeNode) {
+ o = ((TreeNode) o).getValue();
+ }
+ if (o instanceof PGPPublicKey) {
+ PGPPublicKey key = (PGPPublicKey) o;
+ Clipboard clipboard = new Clipboard(getShell().getDisplay());
+ clipboard.setContents(new Object[] { userFriendlyFingerPrint(key) },
+ new Transfer[] { TextTransfer.getInstance() });
+ clipboard.dispose();
+ }
+ }));
+ certificateChainViewer.addSelectionChangedListener(e -> item.setEnabled(containsPGPKeys(e.getSelection())));
+
listViewer.addDoubleClickListener(getDoubleClickListener());
listViewer.addSelectionChangedListener(getParentSelectionListener());
createButtons(composite);
@@ -406,9 +444,7 @@ public class TrustCertificateDialog extends SelectionDialog {
if (selection instanceof StructuredSelection) {
TreeNode firstElement = (TreeNode) ((StructuredSelection) selection).getFirstElement();
getCertificateChainViewer().setInput(new TreeNode[] { firstElement });
- if (firstElement.getValue() instanceof X509Certificate) {
- getCertificateChainViewer().setSelection(new StructuredSelection(firstElement));
- }
+ getCertificateChainViewer().setSelection(new StructuredSelection(firstElement));
Button okButton = getOkButton();
if (okButton != null) {
okButton.setEnabled(listViewer.getCheckedElements().length > 0);
diff --git a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/messages.properties b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/messages.properties
index a26826e94..5a5fc0363 100644
--- a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/messages.properties
+++ b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/messages.properties
@@ -281,8 +281,8 @@ TrustCertificateDialog_Export=\uD83D\uDCE5 E&xport...
TrustCertificateDialog_Title=Trust
TrustCertificateDialog_Message=Do you trust these signers?
TrustCertificateDialog_MessageWithPGP=Do you trust these signers?\n\
-For PGP keys, verifying user can usually be achieved by querying key fingerprint against some trusted keyserver.
-TrustCertificateDialog_AcceptSelectedButtonLabel=&Trust selected
+For PGP keys, verification is typically achieved by querying the key\'s fingerprint against a trusted key server.
+TrustCertificateDialog_AcceptSelectedButtonLabel=&Trust Selected
TrustCertificateDialog_SelectAll=&Select All
TrustCertificateDialog_DeselectAll=&Deselect All
TrustCertificateDialog_ObjectType=Type

Back to the top