blob: 8f3d1508390ccde10631f1794677e104f20553b3 [file] [log] [blame]
/*******************************************************************************
* 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 java.util.stream.Collectors;
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;
import org.eclipse.equinox.p2.repository.spi.PGPPublicKeyService;
public class PGPPublicKeyStore {
private Map<String, PGPPublicKey> keys = new LinkedHashMap<>();
public PGPPublicKey addKey(PGPPublicKey key) {
if (key == null) {
return null;
}
PGPPublicKey alreadyStoredKey = keys.putIfAbsent(PGPPublicKeyService.toHexFingerprint(key), key);
return alreadyStoredKey == null ? key : alreadyStoredKey;
}
public Collection<PGPPublicKey> getKeys(long id) {
return keys.values().stream().filter(key -> key.getKeyID() == id).collect(Collectors.toList());
}
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);
for (PGPPublicKey key : all()) {
key.encode(armoredOut);
}
armoredOut.close();
out.close();
return new String(out.toByteArray(), StandardCharsets.US_ASCII);
}
public void remove(PGPPublicKey selectedKey) {
keys.remove(PGPPublicKeyService.toHexFingerprint(selectedKey));
}
public void add(File file) {
try (InputStream stream = new FileInputStream(file)) {
readPublicKeys(stream).forEach(this::addKey);
} catch (IOException e) {
LogHelper.log(new Status(IStatus.ERROR, Activator.ID, "Could not read PGP key from " + file, e)); //$NON-NLS-1$
}
}
public static Set<PGPPublicKey> readPublicKeys(InputStream input) throws IOException {
return readPublicKeys(new String(input.readAllBytes(), StandardCharsets.US_ASCII));
}
@SuppressWarnings("unchecked")
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(StandardCharsets.US_ASCII)))) {
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 | PGPRuntimeOperationException 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);
}
}