package de.is24.infrastructure.gridfs.http.security; import org.bouncycastle.bcpg.ArmoredOutputStream; import org.bouncycastle.bcpg.BCPGOutputStream; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPrivateKey; import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignatureGenerator; import org.bouncycastle.openpgp.PGPUtil; import org.bouncycastle.openpgp.bc.BcPGPSecretKeyRingCollection; import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor; import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.Resource; import org.springframework.stereotype.Service; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.security.Security; import java.util.Iterator; import static org.apache.commons.io.IOUtils.closeQuietly; @Service public class PGPSigner { static { if (Security.getProvider("BC") == null) { Security.addProvider(new BouncyCastleProvider()); } } public static final int BUFFER_SIZE = 1024; private final Resource keyRingResource; private final String password; private final PGPPrivateKey privateKey; private final int algorithm; @Autowired public PGPSigner(@Value("${security.signature.private.keyfile:classpath:/gpg/secring.gpg}") Resource keyRingResource, @Value("${security.signature.private.password:yum-repo-server}") String password) { this.keyRingResource = keyRingResource; this.password = password; if (isActive()) { PGPSecretKey secretKey = findFirstSecretKey(readKeyRings(keyRingResource)); algorithm = secretKey.getPublicKey().getAlgorithm(); privateKey = readKey(secretKey); } else { privateKey = null; algorithm = 0; } } private PGPPrivateKey readKey(PGPSecretKey secretKey) { try { PBESecretKeyDecryptor secretKeyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider("BC").build(this.password.toCharArray()); return secretKey.extractPrivateKey(secretKeyDecryptor); } catch (PGPException e) { throw new IllegalArgumentException("Could not read private key from key ring file", e); } } private PGPSecretKey findFirstSecretKey(PGPSecretKeyRingCollection keyRings) { @SuppressWarnings("unchecked") Iterator<PGPSecretKeyRing> iter = keyRings.getKeyRings(); while (iter.hasNext()) { PGPSecretKeyRing keyRing = iter.next(); @SuppressWarnings("unchecked") Iterator<PGPSecretKey> keyIter = keyRing.getSecretKeys(); while (keyIter.hasNext()) { PGPSecretKey key = keyIter.next(); if (key.isSigningKey()) { return key; } } } throw new IllegalArgumentException("Can't find signing key in key rings."); } private BcPGPSecretKeyRingCollection readKeyRings(Resource resource) { try { InputStream keyInputStream = new BufferedInputStream(resource.getInputStream()); InputStream decoderStream = PGPUtil.getDecoderStream(keyInputStream); try { return new BcPGPSecretKeyRingCollection(decoderStream); } finally { closeQuietly(decoderStream); closeQuietly(keyInputStream); } } catch (IOException e) { throw new IllegalArgumentException("Could not read key ring file: " + keyRingResource, e); } catch (PGPException e) { throw new IllegalArgumentException("Could not extract key rings.", e); } } public boolean isActive() { return keyRingResource != null; } public byte[] sign(byte[] content) { if (!isActive()) { throw new IllegalStateException("Key file not given during initialisation."); } ByteArrayOutputStream buffer = new ByteArrayOutputStream(BUFFER_SIZE); BCPGOutputStream outputStream = new BCPGOutputStream(new ArmoredOutputStream(new BufferedOutputStream(buffer))); try { PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(new JcaPGPContentSignerBuilder(algorithm, PGPUtil.SHA1).setProvider("BC")); signatureGenerator.init(PGPSignature.BINARY_DOCUMENT, privateKey); signatureGenerator.update(content); signatureGenerator.generate().encode(outputStream); } catch (Exception e) { throw new IllegalStateException("Could not sign content.", e); } finally { closeQuietly(outputStream); } return buffer.toByteArray(); } }