diff options
author | Mickael Istria | 2021-11-09 20:20:45 +0000 |
---|---|---|
committer | Mickael Istria | 2021-11-29 10:28:25 +0000 |
commit | f72e589913dd61ad3ad27839a0393ce143d2a9fa (patch) | |
tree | 1bfc8ce9e50e0c9f585ac0906a808772a21fd8e1 | |
parent | 9ab8beb9260b22ae3196a48070b908034a2adae0 (diff) | |
download | rt.equinox.p2-f72e589913dd61ad3ad27839a0393ce143d2a9fa.tar.gz rt.equinox.p2-f72e589913dd61ad3ad27839a0393ce143d2a9fa.tar.xz rt.equinox.p2-f72e589913dd61ad3ad27839a0393ce143d2a9fa.zip |
Bug 577193 - Support addition/removal of trusted PGP keysI20211129-1800
Change-Id: I429645e308d805a4511828dfab18f7864fc01e1f
Reviewed-on: https://git.eclipse.org/r/c/equinox/rt.equinox.p2/+/187562
Tested-by: Equinox Bot <equinox-bot@eclipse.org>
Reviewed-by: Mickael Istria <mistria@redhat.com>
23 files changed, 262 insertions, 102 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 f7fc2091a..49e639b77 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 @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.equinox.p2.artifact.repository;singleton:=true -Bundle-Version: 1.4.300.qualifier +Bundle-Version: 1.4.400.qualifier Bundle-Activator: org.eclipse.equinox.internal.p2.artifact.repository.Activator Bundle-Vendor: %providerName Bundle-Localization: plugin @@ -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.internal.p2.artifact.processors.pgp;x-friends:="org.eclipse.equinox.p2.engine,org.eclipse.equinox.p2.ui.sdk", 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/pom.xml b/bundles/org.eclipse.equinox.p2.artifact.repository/pom.xml index 79eb5804e..896b53571 100644 --- a/bundles/org.eclipse.equinox.p2.artifact.repository/pom.xml +++ b/bundles/org.eclipse.equinox.p2.artifact.repository/pom.xml @@ -9,6 +9,6 @@ </parent> <groupId>org.eclipse.equinox</groupId> <artifactId>org.eclipse.equinox.p2.artifact.repository</artifactId> - <version>1.4.300-SNAPSHOT</version> + <version>1.4.400-SNAPSHOT</version> <packaging>eclipse-plugin</packaging> </project> diff --git a/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/processors/pgp/PGPPublicKeyStore.java b/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/processors/pgp/PGPPublicKeyStore.java new file mode 100644 index 000000000..3aff39c66 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/p2/artifact/processors/pgp/PGPPublicKeyStore.java @@ -0,0 +1,125 @@ +/******************************************************************************* + * Copyright (c) 2021 Red Hat Inc. and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.artifact.processors.pgp; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.function.Consumer; +import org.bouncycastle.bcpg.ArmoredOutputStream; +import org.bouncycastle.openpgp.*; +import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.equinox.internal.p2.artifact.repository.Activator; +import org.eclipse.equinox.internal.p2.core.helpers.LogHelper; + +public class PGPPublicKeyStore { + private Map<Long, PGPPublicKey> keys = new HashMap<>(); + + public PGPPublicKey addKey(PGPPublicKey key) { + if (key == null) { + return null; + } + PGPPublicKey alreadyStoredKey = keys.putIfAbsent(key.getKeyID(), key); + return alreadyStoredKey == null ? key : alreadyStoredKey; + } + + public PGPPublicKey getKey(long id) { + return keys.get(id); + } + + public void addKeys(String... armoredPublicKeys) { + for (String armoredKey : armoredPublicKeys) { + if (armoredKey != null) { + PGPPublicKeyStore.readPublicKeys(armoredKey).forEach(this::addKey); + } + } + } + + /** + * Test only + */ + public void clear() { + keys.clear(); + } + + public Collection<PGPPublicKey> all() { + return Collections.unmodifiableCollection(keys.values()); + } + + public boolean isEmpty() { + return keys.isEmpty(); + } + + public String toArmoredString() throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ArmoredOutputStream armoredOut = new ArmoredOutputStream(out); + // PGPPublicKeyRing ring = new PGPPublicKeyRing(new ArrayList<>(keys.values())); + // ring.encode(armoredOut); + for (PGPPublicKey key : keys.values()) { + key.encode(armoredOut); + } + armoredOut.close(); + out.close(); + return new String(out.toByteArray(), StandardCharsets.US_ASCII); + } + + public void remove(PGPPublicKey selectedKey) { + keys.remove(selectedKey.getKeyID()); + } + + public void add(File file) { + try (InputStream stream = new FileInputStream(file)) { + readPublicKeys(stream).forEach(this::addKey); + } catch (IOException e) { + // TODO: how to log? + } + } + + public static Set<PGPPublicKey> readPublicKeys(InputStream input) throws IOException { + return readPublicKeys(new String(input.readAllBytes(), StandardCharsets.US_ASCII)); + } + + public static Set<PGPPublicKey> readPublicKeys(String armoredPublicKeyring) { + if (armoredPublicKeyring == null) { + return Set.of(); + } + Set<PGPPublicKey> res = new HashSet<>(); + try (InputStream stream = PGPUtil.getDecoderStream(new ByteArrayInputStream( + PGPSignatureVerifier.unnormalizedPGPProperty(armoredPublicKeyring).getBytes()))) { + new JcaPGPObjectFactory(stream).forEach(o -> { + if (o instanceof PGPPublicKeyRingCollection) { + collectKeys((PGPPublicKeyRingCollection) o, res::add); + } + if (o instanceof PGPPublicKeyRing) { + collectKeys((PGPPublicKeyRing) o, res::add); + } + if (o instanceof PGPPublicKey) { + res.add((PGPPublicKey) o); + } + }); + } catch (IOException e) { + LogHelper.log(new Status(IStatus.ERROR, Activator.ID, e.getMessage(), e)); + } + return res; + + } + + private static void collectKeys(PGPPublicKeyRingCollection pgpPublicKeyRingCollection, + Consumer<PGPPublicKey> collector) { + pgpPublicKeyRingCollection.forEach(keyring -> collectKeys(keyring, collector)); + } + + private static void collectKeys(PGPPublicKeyRing pgpPublicKeyRing, Consumer<PGPPublicKey> collector) { + pgpPublicKeyRing.getPublicKeys().forEachRemaining(collector::accept); + } +}
\ No newline at end of file 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 05bbc2398..d752d1b61 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 @@ -15,11 +15,9 @@ import java.util.*; import org.bouncycastle.bcpg.ArmoredInputStream; import org.bouncycastle.openpgp.*; import org.bouncycastle.openpgp.bc.BcPGPObjectFactory; -import org.bouncycastle.openpgp.bc.BcPGPPublicKeyRingCollection; import org.bouncycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider; import org.eclipse.core.runtime.*; import org.eclipse.equinox.internal.p2.artifact.repository.Activator; -import org.eclipse.equinox.internal.p2.core.helpers.LogHelper; import org.eclipse.equinox.internal.provisional.p2.artifact.repository.processing.ProcessingStep; import org.eclipse.equinox.p2.core.IProvisioningAgent; import org.eclipse.equinox.p2.repository.artifact.*; @@ -39,38 +37,7 @@ public final class PGPSignatureVerifier extends ProcessingStep { */ public static final String ID = "org.eclipse.equinox.p2.processing.PGPSignatureCheck"; //$NON-NLS-1$ - public static class PGPPublicKeyStore { - private Map<Long, PGPPublicKey> keys = new HashMap<>(); - - public PGPPublicKey addKey(PGPPublicKey key) { - if (key == null) { - return null; - } - PGPPublicKey alreadyStoredKey = keys.putIfAbsent(key.getKeyID(), key); - return alreadyStoredKey == null ? key : alreadyStoredKey; - } - - public PGPPublicKey getKey(long id) { - return keys.get(id); - } - - public void addKeys(String... armoredPublicKeys) { - for (String armoredKey : armoredPublicKeys) { - if (armoredKey != null) { - readPublicKeys(armoredKey).forEach(this::addKey); - } - } - } - - /** - * Test only - */ - public void clear() { - keys.clear(); - } - } - - public static final PGPPublicKeyStore keystore = new PGPPublicKeyStore(); + public static final PGPPublicKeyStore KNOWN_KEYS = new PGPPublicKeyStore(); public static final String PGP_SIGNER_KEYS_PROPERTY_NAME = "pgp.publicKeys"; //$NON-NLS-1$ public static final String PGP_SIGNATURES_PROPERTY_NAME = "pgp.signatures"; //$NON-NLS-1$ @@ -127,10 +94,10 @@ public final class PGPSignatureVerifier extends ProcessingStep { } IArtifactRepository repository = context.getRepository(); - keystore.addKeys(context.getProperty(PGP_SIGNER_KEYS_PROPERTY_NAME), + KNOWN_KEYS.addKeys(context.getProperty(PGP_SIGNER_KEYS_PROPERTY_NAME), repository != null ? repository.getProperty(PGP_SIGNER_KEYS_PROPERTY_NAME) : null); for (PGPSignature signature : signaturesToVerify) { - PGPPublicKey publicKey = keystore.getKey(signature.getKeyID()); + PGPPublicKey publicKey = KNOWN_KEYS.getKey(signature.getKeyID()); if (publicKey == null) { setStatus(new Status(IStatus.ERROR, Activator.ID, NLS.bind(Messages.Error_publicKeyNotFound, Long.toHexString(signature.getKeyID())))); @@ -152,7 +119,7 @@ public final class PGPSignatureVerifier extends ProcessingStep { * @param armoredPGPBlock the PGP block, in armored form * @return fixed PGP armored blocks */ - private static String unnormalizedPGPProperty(String armoredPGPBlock) { + static String unnormalizedPGPProperty(String armoredPGPBlock) { if (armoredPGPBlock == null) { return null; } @@ -166,22 +133,6 @@ public final class PGPSignatureVerifier extends ProcessingStep { .replace("-----END\nPGP\nPUBLIC\nKEY\nBLOCK-----", "-----END PGP PUBLIC KEY BLOCK-----"); //$NON-NLS-1$ //$NON-NLS-2$ } - public static Set<PGPPublicKey> readPublicKeys(String armoredPublicKeyring) { - if (armoredPublicKeyring == null) { - return Set.of(); - } - Set<PGPPublicKey> res = new HashSet<>(); - try (InputStream stream = PGPUtil - .getDecoderStream(new ByteArrayInputStream(unnormalizedPGPProperty(armoredPublicKeyring).getBytes()))) { - PGPPublicKeyRingCollection pgpPub = new BcPGPPublicKeyRingCollection(stream); - pgpPub.getKeyRings().forEachRemaining(kRing -> kRing.getPublicKeys().forEachRemaining(res::add)); - } catch (IOException | PGPException e) { - LogHelper.log(new Status(IStatus.ERROR, Activator.ID, e.getMessage(), e)); - } - return res; - - } - @Override public void write(int b) { if (signaturesToVerify != null) { diff --git a/bundles/org.eclipse.equinox.p2.engine/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.p2.engine/META-INF/MANIFEST.MF index 439758603..d1e7137aa 100644 --- a/bundles/org.eclipse.equinox.p2.engine/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.equinox.p2.engine/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.equinox.p2.engine;singleton:=true -Bundle-Version: 2.7.200.qualifier +Bundle-Version: 2.7.300.qualifier Bundle-Activator: org.eclipse.equinox.internal.p2.engine.EngineActivator Bundle-Vendor: %providerName Bundle-Localization: plugin diff --git a/bundles/org.eclipse.equinox.p2.engine/pom.xml b/bundles/org.eclipse.equinox.p2.engine/pom.xml index 00514163d..cbf8386be 100644 --- a/bundles/org.eclipse.equinox.p2.engine/pom.xml +++ b/bundles/org.eclipse.equinox.p2.engine/pom.xml @@ -9,6 +9,6 @@ </parent> <groupId>org.eclipse.equinox</groupId> <artifactId>org.eclipse.equinox.p2.engine</artifactId> - <version>2.7.200-SNAPSHOT</version> + <version>2.7.300-SNAPSHOT</version> <packaging>eclipse-plugin</packaging> </project> diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/phases/CertificateChecker.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/phases/CertificateChecker.java index 12c3fd3d2..15943a47c 100644 --- a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/phases/CertificateChecker.java +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/phases/CertificateChecker.java @@ -21,21 +21,21 @@ import java.util.*; import java.util.Map.Entry; import java.util.stream.Collectors; import org.bouncycastle.openpgp.*; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.*; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.equinox.internal.p2.artifact.processors.pgp.PGPPublicKeyStore; import org.eclipse.equinox.internal.p2.artifact.processors.pgp.PGPSignatureVerifier; import org.eclipse.equinox.internal.p2.engine.*; -import org.eclipse.equinox.p2.core.IProvisioningAgent; -import org.eclipse.equinox.p2.core.UIServices; +import org.eclipse.equinox.p2.core.*; import org.eclipse.equinox.p2.core.UIServices.TrustInfo; -import org.eclipse.equinox.p2.engine.IProfile; -import org.eclipse.equinox.p2.engine.IProfileRegistry; +import org.eclipse.equinox.p2.engine.*; import org.eclipse.equinox.p2.repository.artifact.IArtifactDescriptor; import org.eclipse.osgi.service.security.TrustEngine; import org.eclipse.osgi.signedcontent.*; import org.eclipse.osgi.util.NLS; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; +import org.osgi.service.prefs.BackingStoreException; import org.osgi.util.tracker.ServiceTracker; /** @@ -54,7 +54,7 @@ public class CertificateChecker { private Map<IArtifactDescriptor, File> artifacts = new HashMap<>(); private final IProvisioningAgent agent; - private Set<PGPPublicKey> trustedKeys; + private PGPPublicKeyStore trustedKeys; public CertificateChecker() { this(null); @@ -117,7 +117,7 @@ public class CertificateChecker { trustedKeys = buildPGPTrustore(); } if (trustedKeysIds.isEmpty() && !trustedKeys.isEmpty()) { - trustedKeysIds.addAll(trustedKeys.stream() + trustedKeysIds.addAll(trustedKeys.all().stream() .map(PGPPublicKey::getKeyID).map(Long::valueOf).collect(Collectors.toSet())); } if (signatures.stream().map(PGPSignature::getKeyID).noneMatch(trustedKeysIds::contains)) { @@ -221,21 +221,33 @@ public class CertificateChecker { } // If we should persist the trusted certificates, add them to the trust engine if (trustInfo.persistTrust()) { - return persistTrustedCertificates(trustedCertificates); - // do not persist PGP key at the moment + IStatus certifactesStatus = trustInfo.getTrustedCertificates().length == 0 ? null + : persistTrustedCertificates(trustedCertificates); + trustInfo.getTrustedPGPKeys().forEach(trustedKeys::addKey); + IStatus pgpStatus = trustInfo.getTrustedPGPKeys().isEmpty() ? null : persistTrustedKeys(trustedKeys); + if (pgpStatus == null) { + return certifactesStatus; + } + if (certifactesStatus == null) { + return pgpStatus; + } + return new MultiStatus(getClass(), IStatus.OK, new IStatus[] { pgpStatus, certifactesStatus }, + pgpStatus.getMessage() + '\n' + certifactesStatus.getMessage(), null); } return status; } + private PGPPublicKey findKey(long id, IArtifactDescriptor artifact) { - PGPPublicKey key = PGPSignatureVerifier.keystore.getKey(id); + PGPPublicKey key = PGPSignatureVerifier.KNOWN_KEYS.getKey(id); if (key != null) { return key; } // in case keys from artifact were not imported yet in keystore, add them - PGPSignatureVerifier.keystore.addKeys(artifact.getProperty(PGPSignatureVerifier.PGP_SIGNER_KEYS_PROPERTY_NAME)); - return PGPSignatureVerifier.keystore.getKey(id); + PGPSignatureVerifier.KNOWN_KEYS + .addKeys(artifact.getProperty(PGPSignatureVerifier.PGP_SIGNER_KEYS_PROPERTY_NAME)); + return PGPSignatureVerifier.KNOWN_KEYS.getKey(id); } private IStatus persistTrustedCertificates(Certificate[] trustedCertificates) { @@ -286,19 +298,33 @@ public class CertificateChecker { artifacts.putAll(toAdd); } - public Set<PGPPublicKey> buildPGPTrustore() { + public PGPPublicKeyStore buildPGPTrustore() { + PGPPublicKeyStore trustStore = new PGPPublicKeyStore(); IProfile profile = agent.getService(IProfileRegistry.class).getProfile(IProfileRegistry.SELF); - Set<PGPPublicKey> store = new HashSet<>( - PGPSignatureVerifier.readPublicKeys(profile.getProperty(TRUSTED_KEY_STORE_PROPERTY))); + trustStore.addKeys(profile.getProperty(TRUSTED_KEY_STORE_PROPERTY)); + ProfileScope profileScope = new ProfileScope(agent.getService(IAgentLocation.class), profile.getProfileId()); + trustStore.addKeys(profileScope.getNode(EngineActivator.ID).get(TRUSTED_KEY_STORE_PROPERTY, null)); //// SECURITY ISSUE: next lines become an attack vector as we have no guarantee //// the metadata of those IUs is safe/were signed. //// https://bugs.eclipse.org/bugs/show_bug.cgi?id=576705#c4 // profile.query(QueryUtil.ALL_UNITS, new NullProgressMonitor()).forEach( // iu -> // store.addAll(PGPSignatureVerifier.readPublicKeys(iu.getProperty(TRUSTED_KEY_STORE_PROPERTY)))); - store.forEach(PGPSignatureVerifier.keystore::addKey); - return store; + trustStore.all().forEach(PGPSignatureVerifier.KNOWN_KEYS::addKey); + return trustStore; } + public IStatus persistTrustedKeys(PGPPublicKeyStore trustStore) { + IProfile profile = agent.getService(IProfileRegistry.class).getProfile(IProfileRegistry.SELF); + ProfileScope profileScope = new ProfileScope(agent.getService(IAgentLocation.class), profile.getProfileId()); + IEclipsePreferences node = profileScope.getNode(EngineActivator.ID); + try { + node.put(TRUSTED_KEY_STORE_PROPERTY, trustStore.toArmoredString()); + node.flush(); + return Status.OK_STATUS; + } catch (IOException | BackingStoreException ex) { + return new Status(IStatus.ERROR, EngineActivator.ID, ex.getMessage(), ex); + } + } } diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/artifact/repository/PGPVerifierTest.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/artifact/repository/PGPVerifierTest.java index 161675ce2..c010af306 100644 --- a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/artifact/repository/PGPVerifierTest.java +++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/artifact/repository/PGPVerifierTest.java @@ -30,7 +30,7 @@ public class PGPVerifierTest extends AbstractProvisioningTest { @Before public void setUp() throws Exception { super.setUp(); - PGPSignatureVerifier.keystore.clear(); + PGPSignatureVerifier.KNOWN_KEYS.clear(); } private void loadPGPTestRepo(String repoName) throws Exception { diff --git a/bundles/org.eclipse.equinox.p2.ui.sdk/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.p2.ui.sdk/META-INF/MANIFEST.MF index cc9e868d8..988cfdd1b 100644 --- a/bundles/org.eclipse.equinox.p2.ui.sdk/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.equinox.p2.ui.sdk/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %bundleName Bundle-SymbolicName: org.eclipse.equinox.p2.ui.sdk;singleton:=true -Bundle-Version: 1.2.2.qualifier +Bundle-Version: 1.2.3.qualifier Bundle-Activator: org.eclipse.equinox.internal.p2.ui.sdk.ProvSDKUIActivator Bundle-Vendor: %providerName Bundle-Localization: plugin @@ -18,6 +18,7 @@ Import-Package: javax.xml.parsers, org.eclipse.compare.structuremergeviewer;resolution:=optional, org.eclipse.equinox.internal.p2.engine.phases, org.eclipse.equinox.p2.core;version="[2.0.0,3.0.0)", + org.eclipse.equinox.internal.p2.artifact.processors.pgp, org.eclipse.equinox.p2.engine;version="[2.0.0,3.0.0)", org.eclipse.equinox.p2.engine.query;version="[2.0.0,3.0.0)", org.eclipse.equinox.p2.metadata;version="[2.0.0,3.0.0)", diff --git a/bundles/org.eclipse.equinox.p2.ui.sdk/pom.xml b/bundles/org.eclipse.equinox.p2.ui.sdk/pom.xml index 4bbc8001b..32f6d437e 100644 --- a/bundles/org.eclipse.equinox.p2.ui.sdk/pom.xml +++ b/bundles/org.eclipse.equinox.p2.ui.sdk/pom.xml @@ -9,6 +9,6 @@ </parent> <groupId>org.eclipse.equinox</groupId> <artifactId>org.eclipse.equinox.p2.ui.sdk</artifactId> - <version>1.2.2-SNAPSHOT</version> + <version>1.2.3-SNAPSHOT</version> <packaging>eclipse-plugin</packaging> </project> diff --git a/bundles/org.eclipse.equinox.p2.ui.sdk/src/org/eclipse/equinox/internal/p2/ui/sdk/ProvSDKMessages.java b/bundles/org.eclipse.equinox.p2.ui.sdk/src/org/eclipse/equinox/internal/p2/ui/sdk/ProvSDKMessages.java index 4c73980f4..bf0a1956c 100644 --- a/bundles/org.eclipse.equinox.p2.ui.sdk/src/org/eclipse/equinox/internal/p2/ui/sdk/ProvSDKMessages.java +++ b/bundles/org.eclipse.equinox.p2.ui.sdk/src/org/eclipse/equinox/internal/p2/ui/sdk/ProvSDKMessages.java @@ -56,5 +56,8 @@ public class ProvSDKMessages extends NLS { public static String TrustPreferencePage_userColumn; public static String TrustPreferencePage_fileExportTitle; public static String TrustPreferencePage_pgpIntro; + public static String TrustPreferencePage_fileImportTitle; + public static String TrustPreferencePage_addPGPKeyButtonLabel; + public static String TrustPreferencePage_removePGPKeyButtonLabel; } diff --git a/bundles/org.eclipse.equinox.p2.ui.sdk/src/org/eclipse/equinox/internal/p2/ui/sdk/TrustPreferencePage.java b/bundles/org.eclipse.equinox.p2.ui.sdk/src/org/eclipse/equinox/internal/p2/ui/sdk/TrustPreferencePage.java index 4b4c2439c..417ba2d68 100644 --- a/bundles/org.eclipse.equinox.p2.ui.sdk/src/org/eclipse/equinox/internal/p2/ui/sdk/TrustPreferencePage.java +++ b/bundles/org.eclipse.equinox.p2.ui.sdk/src/org/eclipse/equinox/internal/p2/ui/sdk/TrustPreferencePage.java @@ -17,6 +17,7 @@ import org.bouncycastle.bcpg.ArmoredOutputStream; import org.bouncycastle.openpgp.PGPPublicKey; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; +import org.eclipse.equinox.internal.p2.artifact.processors.pgp.PGPPublicKeyStore; import org.eclipse.equinox.internal.p2.engine.phases.CertificateChecker; import org.eclipse.equinox.internal.p2.ui.ProvUIActivator; import org.eclipse.jface.dialogs.IDialogConstants; @@ -33,6 +34,11 @@ import org.eclipse.ui.IWorkbenchPreferencePage; public class TrustPreferencePage extends PreferencePage implements IWorkbenchPreferencePage { + private CertificateChecker certificateChecker; + private PGPPublicKeyStore trustedKeys; + private boolean dirty = false; + private TableViewer viewer; + public TrustPreferencePage() { super(ProvSDKMessages.TrustPreferencePage_title); } @@ -51,7 +57,7 @@ public class TrustPreferencePage extends PreferencePage implements IWorkbenchPre pgpLabel.setText(ProvSDKMessages.TrustPreferencePage_pgpIntro); res.setLayout(new GridLayout(2, false)); - TableViewer viewer = new TableViewer(res); + viewer = new TableViewer(res); viewer.getTable().setHeaderVisible(true); viewer.setContentProvider(new ArrayContentProvider()); TableViewerColumn idColumn = new TableViewerColumn(viewer, SWT.NONE); @@ -75,23 +81,19 @@ public class TrustPreferencePage extends PreferencePage implements IWorkbenchPre userColumn.getColumn().setWidth(400); userColumn.getColumn().setText(ProvSDKMessages.TrustPreferencePage_userColumn); viewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - viewer.setInput( - new CertificateChecker(ProvSDKUIActivator.getDefault().getProvisioningAgent()).buildPGPTrustore()); + certificateChecker = new CertificateChecker(ProvSDKUIActivator.getDefault().getProvisioningAgent()); + trustedKeys = certificateChecker.buildPGPTrustore(); + viewer.setInput(trustedKeys.all()); Composite buttonComposite = createVerticalButtonBar(res); buttonComposite.setLayoutData(new GridData(SWT.DEFAULT, SWT.BEGINNING, false, false)); Button exportButton = new Button(buttonComposite, SWT.PUSH); exportButton.setText(ProvSDKMessages.TrustPreferencePage_export); setVerticalButtonLayoutData(exportButton); exportButton.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> { - ISelection sel = viewer.getSelection(); - if (!(sel instanceof IStructuredSelection)) { - return; - } - Object o = ((IStructuredSelection)sel).getFirstElement(); - if (!(o instanceof PGPPublicKey)) { + PGPPublicKey key = getSelectedKey(); + if (key == null) { return; } - PGPPublicKey key = (PGPPublicKey)o; FileDialog dialog = new FileDialog(getShell(), SWT.SAVE); dialog.setText(ProvSDKMessages.TrustPreferencePage_fileExportTitle); dialog.setFilterExtensions(new String[] { "*.asc" }); //$NON-NLS-1$ @@ -108,11 +110,50 @@ public class TrustPreferencePage extends PreferencePage implements IWorkbenchPre .log(new Status(IStatus.ERROR, ProvUIActivator.PLUGIN_ID, ex.getMessage(), ex)); } })); - viewer.addPostSelectionChangedListener(e -> exportButton.setEnabled(!e.getSelection().isEmpty())); - exportButton.setEnabled(!viewer.getSelection().isEmpty()); + Button addButton = new Button(buttonComposite, SWT.PUSH); + addButton.setText(ProvSDKMessages.TrustPreferencePage_addPGPKeyButtonLabel); + addButton.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> { + FileDialog dialog = new FileDialog(getShell(), SWT.OPEN); + dialog.setText(ProvSDKMessages.TrustPreferencePage_fileImportTitle); + dialog.setFilterExtensions(new String[] { "*.asc" }); //$NON-NLS-1$ + String path = dialog.open(); + if (path == null) { + return; + } + trustedKeys.add(new File(path)); + viewer.setInput(trustedKeys.all()); + dirty = true; + })); + setVerticalButtonLayoutData(addButton); + Button removeButton = new Button(buttonComposite, SWT.PUSH); + removeButton.setText(ProvSDKMessages.TrustPreferencePage_removePGPKeyButtonLabel); + removeButton.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> { + trustedKeys.remove(getSelectedKey()); + viewer.setInput(trustedKeys.all()); + dirty = true; + })); + setVerticalButtonLayoutData(removeButton); + viewer.addPostSelectionChangedListener(e -> { + exportButton.setEnabled(getSelectedKey() != null); + removeButton.setEnabled(getSelectedKey() != null); + }); + exportButton.setEnabled(getSelectedKey() != null); + removeButton.setEnabled(getSelectedKey() != null); return res; } + private PGPPublicKey getSelectedKey() { + ISelection sel = viewer.getSelection(); + if (!(sel instanceof IStructuredSelection)) { + return null; + } + Object o = ((IStructuredSelection) sel).getFirstElement(); + if (!(o instanceof PGPPublicKey)) { + return null; + } + return (PGPPublicKey) o; + } + private Composite createVerticalButtonBar(Composite parent) { // Create composite. Composite composite = new Composite(parent, SWT.NONE); @@ -139,4 +180,13 @@ public class TrustPreferencePage extends PreferencePage implements IWorkbenchPre button.setLayoutData(data); return data; } + + @Override + public boolean performOk() { + if (dirty) { + return certificateChecker.persistTrustedKeys(trustedKeys).isOK(); + } + return true; + } + } diff --git a/bundles/org.eclipse.equinox.p2.ui.sdk/src/org/eclipse/equinox/internal/p2/ui/sdk/messages.properties b/bundles/org.eclipse.equinox.p2.ui.sdk/src/org/eclipse/equinox/internal/p2/ui/sdk/messages.properties index 4e79e3211..0e344af3d 100644 --- a/bundles/org.eclipse.equinox.p2.ui.sdk/src/org/eclipse/equinox/internal/p2/ui/sdk/messages.properties +++ b/bundles/org.eclipse.equinox.p2.ui.sdk/src/org/eclipse/equinox/internal/p2/ui/sdk/messages.properties @@ -36,9 +36,13 @@ UpdateHandler_ProgressTaskName=Checking for updates... RemediationOperation_ResolveJobName=Searching alternate solutions... RemediationOperation_ResolveJobTask=Some items cannot be at the highest version. Searching for the highest common denominator ... TrustPreferencePage_title=Trust -TrustPreferencePage_export=E&xport... +TrustPreferencePage_export=\uD83D\uDCE5 E&xport... TrustPreferencePage_idColumn=Id TrustPreferencePage_userColumn=User TrustPreferencePage_fileExportTitle=Export PGP public key +TrustPreferencePage_fileImportTitle=Import PGP public key to trust +TrustPreferencePage_addPGPKeyButtonLabel=\u2795 &Add... +TrustPreferencePage_removePGPKeyButtonLabel=\uD83D\uDDD1\uFE0F &Remove + TrustPreferencePage_pgpIntro=The following PGP public keys are considered as trusted.\n\ Artifacts that are signed and verified by one of those keys will be trusted and installed without further trust confirmation request.
\ No newline at end of file diff --git a/features/org.eclipse.equinox.p2.core.feature/feature.xml b/features/org.eclipse.equinox.p2.core.feature/feature.xml index fdad4dbc9..f8cffb089 100644 --- a/features/org.eclipse.equinox.p2.core.feature/feature.xml +++ b/features/org.eclipse.equinox.p2.core.feature/feature.xml @@ -2,7 +2,7 @@ <feature id="org.eclipse.equinox.p2.core.feature" label="%featureName" - version="1.6.1200.qualifier" + version="1.6.1300.qualifier" provider-name="%providerName" license-feature="org.eclipse.license" license-feature-version="0.0.0"> diff --git a/features/org.eclipse.equinox.p2.core.feature/pom.xml b/features/org.eclipse.equinox.p2.core.feature/pom.xml index b38d01548..1420cd178 100644 --- a/features/org.eclipse.equinox.p2.core.feature/pom.xml +++ b/features/org.eclipse.equinox.p2.core.feature/pom.xml @@ -20,7 +20,7 @@ </parent> <groupId>org.eclipse.equinox</groupId> <artifactId>org.eclipse.equinox.p2.core.feature</artifactId> - <version>1.6.1200-SNAPSHOT</version> + <version>1.6.1300-SNAPSHOT</version> <packaging>eclipse-feature</packaging> diff --git a/features/org.eclipse.equinox.p2.extras.feature/feature.xml b/features/org.eclipse.equinox.p2.extras.feature/feature.xml index 2449f4144..ac67f7b30 100644 --- a/features/org.eclipse.equinox.p2.extras.feature/feature.xml +++ b/features/org.eclipse.equinox.p2.extras.feature/feature.xml @@ -2,7 +2,7 @@ <feature id="org.eclipse.equinox.p2.extras.feature" label="%featureName" - version="1.4.1400.qualifier" + version="1.4.1500.qualifier" provider-name="%providerName" license-feature="org.eclipse.license" license-feature-version="0.0.0"> diff --git a/features/org.eclipse.equinox.p2.extras.feature/pom.xml b/features/org.eclipse.equinox.p2.extras.feature/pom.xml index 1b751b496..200e682ad 100644 --- a/features/org.eclipse.equinox.p2.extras.feature/pom.xml +++ b/features/org.eclipse.equinox.p2.extras.feature/pom.xml @@ -19,7 +19,7 @@ </parent> <groupId>org.eclipse.equinox</groupId> <artifactId>org.eclipse.equinox.p2.extras.feature</artifactId> - <version>1.4.1400-SNAPSHOT</version> + <version>1.4.1500-SNAPSHOT</version> <packaging>eclipse-feature</packaging> <build> diff --git a/features/org.eclipse.equinox.p2.rcp.feature/feature.xml b/features/org.eclipse.equinox.p2.rcp.feature/feature.xml index a5fe82747..f07c42fa7 100644 --- a/features/org.eclipse.equinox.p2.rcp.feature/feature.xml +++ b/features/org.eclipse.equinox.p2.rcp.feature/feature.xml @@ -2,7 +2,7 @@ <feature id="org.eclipse.equinox.p2.rcp.feature" label="%featureName" - version="1.4.1400.qualifier" + version="1.4.1500.qualifier" provider-name="%providerName" license-feature="org.eclipse.license" license-feature-version="0.0.0"> diff --git a/features/org.eclipse.equinox.p2.rcp.feature/pom.xml b/features/org.eclipse.equinox.p2.rcp.feature/pom.xml index 58a3f6117..7abade620 100644 --- a/features/org.eclipse.equinox.p2.rcp.feature/pom.xml +++ b/features/org.eclipse.equinox.p2.rcp.feature/pom.xml @@ -20,7 +20,7 @@ <groupId>org.eclipse.equinox</groupId> <artifactId>org.eclipse.equinox.p2.rcp.feature</artifactId> - <version>1.4.1400-SNAPSHOT</version> + <version>1.4.1500-SNAPSHOT</version> <packaging>eclipse-feature</packaging> <build> diff --git a/features/org.eclipse.equinox.p2.sdk/feature.xml b/features/org.eclipse.equinox.p2.sdk/feature.xml index fa259be4f..3f87a10f4 100644 --- a/features/org.eclipse.equinox.p2.sdk/feature.xml +++ b/features/org.eclipse.equinox.p2.sdk/feature.xml @@ -2,7 +2,7 @@ <feature id="org.eclipse.equinox.p2.sdk" label="%featureName" - version="3.11.1400.qualifier" + version="3.11.1500.qualifier" provider-name="%providerName" license-feature="org.eclipse.license" license-feature-version="0.0.0"> diff --git a/features/org.eclipse.equinox.p2.sdk/pom.xml b/features/org.eclipse.equinox.p2.sdk/pom.xml index 3fcde857a..ce34c2cd4 100644 --- a/features/org.eclipse.equinox.p2.sdk/pom.xml +++ b/features/org.eclipse.equinox.p2.sdk/pom.xml @@ -20,6 +20,6 @@ </parent> <groupId>org.eclipse.equinox</groupId> <artifactId>org.eclipse.equinox.p2.sdk</artifactId> - <version>3.11.1400-SNAPSHOT</version> + <version>3.11.1500-SNAPSHOT</version> <packaging>eclipse-feature</packaging> </project> diff --git a/features/org.eclipse.equinox.p2.user.ui/feature.xml b/features/org.eclipse.equinox.p2.user.ui/feature.xml index 53903347f..415f30d94 100644 --- a/features/org.eclipse.equinox.p2.user.ui/feature.xml +++ b/features/org.eclipse.equinox.p2.user.ui/feature.xml @@ -2,7 +2,7 @@ <feature id="org.eclipse.equinox.p2.user.ui" label="%featureName" - version="2.4.1400.qualifier" + version="2.4.1500.qualifier" provider-name="%providerName" license-feature="org.eclipse.license" license-feature-version="0.0.0"> diff --git a/features/org.eclipse.equinox.p2.user.ui/pom.xml b/features/org.eclipse.equinox.p2.user.ui/pom.xml index c281a3a27..7840daa87 100644 --- a/features/org.eclipse.equinox.p2.user.ui/pom.xml +++ b/features/org.eclipse.equinox.p2.user.ui/pom.xml @@ -20,7 +20,7 @@ <groupId>org.eclipse.equinox</groupId> <artifactId>org.eclipse.equinox.p2.user.ui</artifactId> - <version>2.4.1400-SNAPSHOT</version> + <version>2.4.1500-SNAPSHOT</version> <packaging>eclipse-feature</packaging> <build> |