diff --git a/scm-webapp/src/main/java/sonia/scm/security/gpg/GpgKey.java b/scm-webapp/src/main/java/sonia/scm/security/gpg/GpgKey.java index 2855a0d265..e2552e1e39 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/gpg/GpgKey.java +++ b/scm-webapp/src/main/java/sonia/scm/security/gpg/GpgKey.java @@ -24,29 +24,27 @@ package sonia.scm.security.gpg; -import org.bouncycastle.bcpg.ArmoredInputStream; +import org.bouncycastle.openpgp.PGPCompressedData; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPObjectFactory; import org.bouncycastle.openpgp.PGPPublicKey; +import org.bouncycastle.openpgp.PGPPublicKeyRing; import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignatureList; -import org.bouncycastle.openpgp.operator.PGPContentVerifierBuilderProvider; +import org.bouncycastle.openpgp.PGPUtil; +import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory; import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.security.PublicKey; -import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.Optional; import java.util.Set; -import static sonia.scm.security.gpg.PgpPublicKeyExtractor.getFromRawKey; - public class GpgKey implements PublicKey { private static final Logger LOG = LoggerFactory.getLogger(GpgKey.class); @@ -90,35 +88,59 @@ public class GpgKey implements PublicKey { public boolean verify(InputStream stream, byte[] signature) { boolean verified = false; try { - ArmoredInputStream armoredInputStream = new ArmoredInputStream(new ByteArrayInputStream(signature)); - PGPObjectFactory pgpObjectFactory = new PGPObjectFactory(armoredInputStream, null); - PGPSignature pgpSignature = ((PGPSignatureList) pgpObjectFactory.nextObject()).get(0); - - PGPContentVerifierBuilderProvider provider = new JcaPGPContentVerifierBuilderProvider(); - - Optional pgpPublicKey = getFromRawKey(raw); - - if (pgpPublicKey.isPresent()) { - pgpSignature.init(provider, pgpPublicKey.get()); - - char[] buffer = new char[1024]; - int bytesRead = 0; - BufferedReader in = new BufferedReader(new InputStreamReader(stream)); - - while (bytesRead != -1) { - bytesRead = in.read(buffer, 0, 1024); - pgpSignature.update(new String(buffer).getBytes(StandardCharsets.UTF_8)); - } - - verified = pgpSignature.verify(); - } - + verified = verify(stream, asDecodedStream(signature)); } catch (IOException | PGPException e) { LOG.error("Could not verify GPG key", e); } return verified; } + + private boolean verify(InputStream stream, InputStream signature) throws IOException, PGPException { + PGPObjectFactory pgpObjectFactory = new JcaPGPObjectFactory(signature); + Object o = pgpObjectFactory.nextObject(); + if (o instanceof PGPSignatureList) { + return verify(stream, ((PGPSignatureList) o).get(0)); + } else if (o instanceof PGPCompressedData) { + return verify(stream, ((PGPCompressedData) o).getDataStream()); + } else { + LOG.warn("could not find valid signature, only found {}", o); + return false; + } + } + + private boolean verify(InputStream stream, PGPSignature signature) throws IOException, PGPException { + PGPPublicKey publicKey = findKey(signature); + if (publicKey != null) { + JcaPGPContentVerifierBuilderProvider provider = new JcaPGPContentVerifierBuilderProvider(); + signature.init(provider, publicKey); + + int bytesRead; + byte[] buffer = new byte[1024]; + while ((bytesRead = stream.read(buffer, 0, buffer.length)) != -1) { + signature.update(buffer, 0, bytesRead); + } + + return signature.verify(); + } else { + LOG.warn("failed to parse public gpg key"); + } + return false; + } + + private PGPPublicKey findKey(PGPSignature signature) throws IOException { + PGPObjectFactory pgpObjectFactory = new JcaPGPObjectFactory(asDecodedStream(raw)); + PGPPublicKeyRing keyRing = (PGPPublicKeyRing) pgpObjectFactory.nextObject(); + return keyRing.getPublicKey(signature.getKeyID()); + } + + private InputStream asDecodedStream(String content) throws IOException { + return asDecodedStream(content.getBytes(StandardCharsets.US_ASCII)); + } + + private InputStream asDecodedStream(byte[] bytes) throws IOException { + return PGPUtil.getDecoderStream(new ByteArrayInputStream(bytes)); + } } diff --git a/scm-webapp/src/main/java/sonia/scm/security/gpg/PublicKeyStore.java b/scm-webapp/src/main/java/sonia/scm/security/gpg/PublicKeyStore.java index 7308ea6cfe..cb606af1ca 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/gpg/PublicKeyStore.java +++ b/scm-webapp/src/main/java/sonia/scm/security/gpg/PublicKeyStore.java @@ -49,8 +49,6 @@ import static sonia.scm.security.gpg.PgpPublicKeyExtractor.getFromRawKey; @Singleton public class PublicKeyStore { - private static final Logger LOG = LoggerFactory.getLogger(PublicKeyStore.class); - private static final String STORE_NAME = "gpg_public_keys"; private static final String SUBKEY_STORE_NAME = "gpg_public_sub_keys"; diff --git a/scm-webapp/src/test/java/sonia/scm/security/gpg/DefaultGPGTest.java b/scm-webapp/src/test/java/sonia/scm/security/gpg/DefaultGPGTest.java index d98aa56b85..a3b4b46582 100644 --- a/scm-webapp/src/test/java/sonia/scm/security/gpg/DefaultGPGTest.java +++ b/scm-webapp/src/test/java/sonia/scm/security/gpg/DefaultGPGTest.java @@ -52,7 +52,7 @@ class DefaultGPGTest { @Test void shouldFindIdInSignature() throws IOException { - String raw = GPGTestHelper.readResource("signature.asc"); + String raw = GPGTestHelper.readResourceAsString("signature.asc"); String publicKeyId = gpg.findPublicKeyId(raw.getBytes()); assertThat(publicKeyId).isEqualTo("0x1F17B79A09DAD5B9"); @@ -60,7 +60,7 @@ class DefaultGPGTest { @Test void shouldFindPublicKey() throws IOException { - String raw = GPGTestHelper.readResource("subkeys.asc"); + String raw = GPGTestHelper.readResourceAsString("subkeys.asc"); RawGpgKey key1 = new RawGpgKey("42", "key_42", "trillian", raw, ImmutableSet.of("trillian", "zaphod"), Instant.now()); when(store.findById("42")).thenReturn(Optional.of(key1)); @@ -76,8 +76,8 @@ class DefaultGPGTest { @Test void shouldFindKeysForUsername() throws IOException { - String raw = GPGTestHelper.readResource("single.asc"); - String raw2= GPGTestHelper.readResource("subkeys.asc"); + String raw = GPGTestHelper.readResourceAsString("single.asc"); + String raw2= GPGTestHelper.readResourceAsString("subkeys.asc"); RawGpgKey key1 = new RawGpgKey("1", "1", "trillian", raw, Collections.emptySet(), Instant.now()); RawGpgKey key2 = new RawGpgKey("2", "2", "trillian", raw2, Collections.emptySet(), Instant.now()); diff --git a/scm-webapp/src/test/java/sonia/scm/security/gpg/GPGTestHelper.java b/scm-webapp/src/test/java/sonia/scm/security/gpg/GPGTestHelper.java index dde8e21d52..b295139a65 100644 --- a/scm-webapp/src/test/java/sonia/scm/security/gpg/GPGTestHelper.java +++ b/scm-webapp/src/test/java/sonia/scm/security/gpg/GPGTestHelper.java @@ -36,7 +36,13 @@ final class GPGTestHelper { } @SuppressWarnings("UnstableApiUsage") - static String readResource(String fileName) throws IOException { + static byte[] readResourceAsBytes(String fileName) throws IOException { + URL resource = Resources.getResource("sonia/scm/security/gpg/" + fileName); + return Resources.toByteArray(resource); + } + + @SuppressWarnings("UnstableApiUsage") + static String readResourceAsString(String fileName) throws IOException { URL resource = Resources.getResource("sonia/scm/security/gpg/" + fileName); return Resources.toString(resource, StandardCharsets.UTF_8); } diff --git a/scm-webapp/src/test/java/sonia/scm/security/gpg/GpgKeyTest.java b/scm-webapp/src/test/java/sonia/scm/security/gpg/GpgKeyTest.java index 3e399ae9be..a830784988 100644 --- a/scm-webapp/src/test/java/sonia/scm/security/gpg/GpgKeyTest.java +++ b/scm-webapp/src/test/java/sonia/scm/security/gpg/GpgKeyTest.java @@ -35,19 +35,14 @@ class GpgKeyTest { @Test void shouldVerifyPublicKey() throws IOException { - StringBuilder longContent = new StringBuilder(); - for (int i = 1; i < 10000; i++) { - longContent.append(i); - } + String rawPublicKey = GPGTestHelper.readResourceAsString("subkeys.asc"); + GpgKey publicKey = new GpgKey("1", "trillian", rawPublicKey, Collections.emptySet()); - String raw = GPGTestHelper.readResource("pubKeyEH.asc"); - String signature = GPGTestHelper.readResource("signature.asc"); + byte[] content = GPGTestHelper.readResourceAsBytes("slarti.txt"); + byte[] signature = GPGTestHelper.readResourceAsBytes("slarti.txt.asc"); - GpgKey key = new GpgKey("1", "trillian", raw, Collections.emptySet()); - - boolean verified = key.verify(longContent.toString().getBytes(), signature.getBytes()); - - //assertThat(verified).isTrue(); + boolean verified = publicKey.verify(content, signature); + assertThat(verified).isTrue(); } } diff --git a/scm-webapp/src/test/java/sonia/scm/security/gpg/KeysTest.java b/scm-webapp/src/test/java/sonia/scm/security/gpg/KeysTest.java index 07a482cbfb..b78a0c5795 100644 --- a/scm-webapp/src/test/java/sonia/scm/security/gpg/KeysTest.java +++ b/scm-webapp/src/test/java/sonia/scm/security/gpg/KeysTest.java @@ -38,21 +38,21 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import static sonia.scm.security.gpg.GPGTestHelper.readResource; +import static sonia.scm.security.gpg.GPGTestHelper.readResourceAsString; @ExtendWith(MockitoExtension.class) class KeysTest { @Test void shouldResolveSingleId() throws IOException { - String rawPublicKey = readResource("single.asc"); + String rawPublicKey = readResourceAsString("single.asc"); Keys keys = Keys.resolve(rawPublicKey); assertThat(keys.getMaster()).isEqualTo("0x975922F193B07D6E"); } @Test void shouldResolveIdsFromSubkeys() throws IOException { - String rawPublicKey = readResource("subkeys.asc"); + String rawPublicKey = readResourceAsString("subkeys.asc"); Keys keys = Keys.resolve(rawPublicKey); assertThat(keys.getMaster()).isEqualTo("0x13B13D4C8A9350A1"); assertThat(keys.getSubs()).containsOnly("0x247E908C6FD35473", "0xE50E1DD8B90D3A6B", "0xBF49759E43DD0E60"); diff --git a/scm-webapp/src/test/java/sonia/scm/security/gpg/PgpPublicKeyExtractorTest.java b/scm-webapp/src/test/java/sonia/scm/security/gpg/PgpPublicKeyExtractorTest.java index a49f5cfb6b..ca50d58367 100644 --- a/scm-webapp/src/test/java/sonia/scm/security/gpg/PgpPublicKeyExtractorTest.java +++ b/scm-webapp/src/test/java/sonia/scm/security/gpg/PgpPublicKeyExtractorTest.java @@ -36,7 +36,7 @@ class PgpPublicKeyExtractorTest { @Test void shouldExtractPublicKeyFromRawKey() throws IOException { - String raw = GPGTestHelper.readResource("pubKeyEH.asc"); + String raw = GPGTestHelper.readResourceAsString("pubKeyEH.asc"); Optional publicKey = PgpPublicKeyExtractor.getFromRawKey(raw); diff --git a/scm-webapp/src/test/java/sonia/scm/security/gpg/PublicKeyCollectionMapperTest.java b/scm-webapp/src/test/java/sonia/scm/security/gpg/PublicKeyCollectionMapperTest.java index b82261c4ad..5fe72825c4 100644 --- a/scm-webapp/src/test/java/sonia/scm/security/gpg/PublicKeyCollectionMapperTest.java +++ b/scm-webapp/src/test/java/sonia/scm/security/gpg/PublicKeyCollectionMapperTest.java @@ -104,7 +104,7 @@ class PublicKeyCollectionMapperTest { } private RawGpgKey createPublicKey(String displayName) throws IOException { - String raw = GPGTestHelper.readResource("single.asc"); + String raw = GPGTestHelper.readResourceAsString("single.asc"); return new RawGpgKey(displayName, displayName, "trillian", raw, Collections.emptySet(), Instant.now()); } diff --git a/scm-webapp/src/test/java/sonia/scm/security/gpg/PublicKeyMapperTest.java b/scm-webapp/src/test/java/sonia/scm/security/gpg/PublicKeyMapperTest.java index 90af5bd984..13f299e826 100644 --- a/scm-webapp/src/test/java/sonia/scm/security/gpg/PublicKeyMapperTest.java +++ b/scm-webapp/src/test/java/sonia/scm/security/gpg/PublicKeyMapperTest.java @@ -69,7 +69,7 @@ class PublicKeyMapperTest { void shouldMapKeyToDto() throws IOException { when(subject.isPermitted("user:changePublicKeys:trillian")).thenReturn(true); - String raw = GPGTestHelper.readResource("single.asc"); + String raw = GPGTestHelper.readResourceAsString("single.asc"); RawGpgKey key = new RawGpgKey("1", "key_42", "trillian", raw, Collections.emptySet(), Instant.now()); RawGpgKeyDto dto = mapper.map(key); @@ -83,7 +83,7 @@ class PublicKeyMapperTest { @Test void shouldNotAppendDeleteLink() throws IOException { - String raw = GPGTestHelper.readResource("single.asc"); + String raw = GPGTestHelper.readResourceAsString("single.asc"); RawGpgKey key = new RawGpgKey("1", "key_42", "trillian", raw, Collections.emptySet(), Instant.now()); RawGpgKeyDto dto = mapper.map(key); diff --git a/scm-webapp/src/test/java/sonia/scm/security/gpg/PublicKeyResourceTest.java b/scm-webapp/src/test/java/sonia/scm/security/gpg/PublicKeyResourceTest.java index 45cf1b0fa3..ff11515014 100644 --- a/scm-webapp/src/test/java/sonia/scm/security/gpg/PublicKeyResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/security/gpg/PublicKeyResourceTest.java @@ -112,7 +112,7 @@ class PublicKeyResourceTest { @Test void shouldAddToStore() throws URISyntaxException, IOException { - String raw = GPGTestHelper.readResource("single.asc"); + String raw = GPGTestHelper.readResourceAsString("single.asc"); UriInfo uriInfo = mock(UriInfo.class); UriBuilder builder = mock(UriBuilder.class); diff --git a/scm-webapp/src/test/java/sonia/scm/security/gpg/PublicKeyStoreTest.java b/scm-webapp/src/test/java/sonia/scm/security/gpg/PublicKeyStoreTest.java index b57cf1430d..d44f8e2cf7 100644 --- a/scm-webapp/src/test/java/sonia/scm/security/gpg/PublicKeyStoreTest.java +++ b/scm-webapp/src/test/java/sonia/scm/security/gpg/PublicKeyStoreTest.java @@ -80,21 +80,21 @@ class PublicKeyStoreTest { @Test void shouldThrowAuthorizationExceptionOnAdd() throws IOException { doThrow(AuthorizationException.class).when(subject).checkPermission("user:changePublicKeys:zaphod"); - String rawKey = GPGTestHelper.readResource("single.asc"); + String rawKey = GPGTestHelper.readResourceAsString("single.asc"); assertThrows(AuthorizationException.class, () -> keyStore.add("zaphods key", "zaphod", rawKey)); } @Test void shouldOnlyStorePublicKeys() throws IOException { - String rawKey = GPGTestHelper.readResource("single.asc").replace("PUBLIC", "PRIVATE"); + String rawKey = GPGTestHelper.readResourceAsString("single.asc").replace("PUBLIC", "PRIVATE"); assertThrows(NotPublicKeyException.class, () -> keyStore.add("SCM Package Key", "trillian", rawKey)); } @Test void shouldReturnStoredKey() throws IOException { - String rawKey = GPGTestHelper.readResource("single.asc"); + String rawKey = GPGTestHelper.readResourceAsString("single.asc"); Instant now = Instant.now(); RawGpgKey key = keyStore.add("SCM Package Key", "trillian", rawKey); @@ -107,7 +107,7 @@ class PublicKeyStoreTest { @Test void shouldFindStoredKeyById() throws IOException { - String rawKey = GPGTestHelper.readResource("single.asc"); + String rawKey = GPGTestHelper.readResourceAsString("single.asc"); keyStore.add("SCM Package Key", "trillian", rawKey); Optional key = keyStore.findById("0x975922F193B07D6E"); assertThat(key).isPresent(); @@ -115,7 +115,7 @@ class PublicKeyStoreTest { @Test void shouldDeleteKey() throws IOException { - String rawKey = GPGTestHelper.readResource("single.asc"); + String rawKey = GPGTestHelper.readResourceAsString("single.asc"); keyStore.add("SCM Package Key", "trillian", rawKey); Optional key = keyStore.findById("0x975922F193B07D6E"); @@ -139,10 +139,10 @@ class PublicKeyStoreTest { @Test void shouldFindAllKeysForUser() throws IOException { - String singleKey = GPGTestHelper.readResource("single.asc"); + String singleKey = GPGTestHelper.readResourceAsString("single.asc"); keyStore.add("SCM Single Key", "trillian", singleKey); - String multiKey = GPGTestHelper.readResource("subkeys.asc"); + String multiKey = GPGTestHelper.readResourceAsString("subkeys.asc"); keyStore.add("SCM Multi Key", "trillian", multiKey); List keys = keyStore.findByUsername("trillian"); diff --git a/scm-webapp/src/test/resources/sonia/scm/security/gpg/pubKeyEH.asc b/scm-webapp/src/test/resources/sonia/scm/security/gpg/pubKeyEH.asc deleted file mode 100644 index d8cfe4c4e2..0000000000 --- a/scm-webapp/src/test/resources/sonia/scm/security/gpg/pubKeyEH.asc +++ /dev/null @@ -1,109 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- - -mQINBFzSf+cBEAC5TUM5APC5CZ34QoO77aCdB+0UZdUDRpsX02ddRK9wKjpDQCVo -p8yZD0UI8Rps4lrf23bq0ZCF11GvfUT4VcaZ04Mw8mFEc6dBpD/PeMhMrvaqnzgd -cihnUg2WEA+fqPW3hPbYdTol1oaqqSG9I7ZqXc+5CUzUGIu836T/8eV4SkDbqsFN -DTC8woJEisGAu7kAqq7SEk/fTaD9lleQbjNWSO+t7s9JoQAO0vPYoeWB4wTbsWle -F9EfPgn9FBouH84AayAqEXndda1UfbrUCMEeXerLgDPhMxO+u2rh8EfUkMl30wlf -G+vzpnmQ6s8qRMt8oNYAq3p5c/RmH4fpuR253xrEbwIXeepymY0Gn2ITaIqTqz24 -umrzsRZgzns8/q7gzpBfmQyuzgHdjseEqiwWq5yVIKN0Fo3NICCl4PLtRRQJVIkZ -LnFunNoM/pc0/nLHvP0HBxmcsS8p6yRjiCkvrfT3Aqt9iT/TlLfpwfDWtLMGLn1s -zlneo1dH8uxnilmN2sOoOUi5x1ub5F+JtO0QkRdXyOXEWeshenKLB7x6gRjQsMb4 -Rp04CFOWcspjiRLEvNnsB+Y89gf7UblAO1ozdqJCe5IOup6FxJ8NwV1FVg+olljz -2wR77EQkFlUopIbWZsHULgAdGZuO0PXPYfZnsZy++HHH2M/yqtxJFs4U/wARAQAB -tC5FZHVhcmQgSGVpbWJ1Y2ggPGVkdWFyZC5oZWltYnVjaEBjbG91ZG9ndS5jb20+ -iQJOBBMBCgA4FiEEzowT/MI47P540iwUOa1L7VVSfxwFAlzSf+cCGwMFCwkIBwMF -FQoJCAsFFgIDAQACHgECF4AACgkQOa1L7VVSfxyWNxAApHArwG1H+NJgj0fWx2mX -qJl+K2a7HgCZdq2EYCwH5gLtznGzW6dhf3agCMVV2ot4QO47ITi0Ku6hj88xXZbY -PU6rZregrBlLQvc5OTO5cLQlipoD/5r3OWIX3zEqPBZDymo8EGTMFPOZOA1M5Sti -eO6GCGVprJCtDVAppJ6iI/2u+Ot3meeSsmepaHfr3MCGSUzRMtNzmtftI2ynGpC4 -fVBjA++jlFazEel+UgPNBmX60t9TLXldrtaCNKv8pfKy7x/ltSvrx9XkUY+12mmI -UQSeeg/D3+JjkkNmiMsZMr/qhrimjy9v88QyQFYQJurdbQkmM/d1/vQ4ACNiWzL+ -33jiR2rb6THM/kacamcfaJsrzhemMz+77W+41sdm3gzBp+FFncAF4oNvzyFPS743 -9mxa8EhckB2kUUfvYRsnHRmG0YUPU6sCggKlPI3YOm/qtp5tMF25nO2ei+EkOEVD -QnY+3ShDJRoNwrH3DRgBiDkzRCc5t9B/glUjvQ4wdQey9X+p1+zxtFjge5Deb8QC -b/bJ3BtykGsZWZ5pCuSiSt7ocXIwjPETylRr4iRLm+0SF5NWs2SYDtIM3zjP861g -x4gIJo/H2LnTg9SXUNTxVB+/uB2cKVwWOrI5Wr4bPBwoBLBeVock2dfDHXxIVNTC -IBh5/IjkQyU6lzigrOwQTxm5Ag0EXNKCPgEQANFOtLka8agVJ2yp4lElwl6ai0EN -8opLlIGeUrHkEvJHwG5rL/SfWhtjauetSb+6dIpwd2JzS8yvdPL3ZU7+9W3CncVA -0tv1pFQ7KzL7WrMOBpIdpbA1RpsoGhNJ8nfvVuLKG3A/PoUVEAjjg5erEAkJtcvZ -ro9Yy2EJj90Y4OW2pUdNOewdH/s18DE8CmNOyuLRMjlFLOECK1UHVavoZ1g+QUxl -XONZNpuWCQUKwm6MgoKRXlorjoroVSHFS3PS1MvGWuElklgIz8Vn5AwP3uP2RtBE -BxVYb++3J3utiYqF0LweKG6gFGV+r8ivwicenvqBhP5y8r+vJeXhNBWnI8VzcK34 -ndW67XAUgRRasbNq197GeHkWxEiN5XGPCMGflpzBccPV9h3xjYu388QsWDjJH6Gm -Xtf3RnOfZMLytQAVugTPGWw5E9yCHMGMH4jLYYhyMnDUAujkxw7giAsDLhBjb0DY -CRjWLawMbXTi0fzbTZhyGosv1tt+rkQNwchwHAYsIbWYE588k+H8/b+2HlozoZ0b -bFoPhsL+37TvwASNC7tjikFGZafUACQGrZE8UXDmUNKRnV+zoH2ABvarVFQ2U0Cd -ZcIK2TlovSMOe1ZHqIXfZlYh+dSV6eIQihfjCO7bOTPY+qZNxZKuVqhY8wMyPe23 -D1mMQDbMc549QXRPABEBAAGJBGwEGAEKACAWIQTOjBP8wjjs/njSLBQ5rUvtVVJ/ -HAUCXNKCPgIbAgJACRA5rUvtVVJ/HMF0IAQZAQoAHRYhBAIm60A4n2K8gBT40B8X -t5oJ2tW5BQJc0oI+AAoJEB8Xt5oJ2tW5FOIQAI0Uxnku6qEUaSZ6CyZPkhp7XnPE -SosUjRQVzt4BGoA2zRINQesL1RNIE3s+zUhBhkwhb8CHnE0foWs0Mfkokq3Syh65 -hCRR4+4f4urG0vRLVqYvGPxuaBJOKxBSgLj36DEL2rpPIhIUfod22CMQPEEccbSs -i4nQKUv1QpiEfwAITc9zki5aSwV1LbrtmcPw7ji6r4GdFrA3iuG2HLGN7wS1ZTlN -SxA/bpF3S27UP12GLiiVZ2cjfFH3Q5aXs4GoDyFKbxWGM8jDFueOXCatVNSLxLS3 -G8AxU4aJ4K1GQA1wTtaB24GnFr3qKmOxL7kV/n9BQPyv+rgG8d6yaHrum1PU8rmc -H7Pt1lBQbIKZG5Tg1hr5Pb3LSE8Y77F+5x6XO8DLOZACqBDch71k4YWl7QBcFbS9 -hxdplh7u2UtiVxXiWQSmgM7LqE/zlNN3ofLweIxHTBZxQwRF6d7ychgt4Cx1uqak -+5/CNqn1OXznGzng2rFKWxvgZXy1UuBw1fmF1pYhvS34l0sgZ4L6q7gIFqSZtniq -8Pj0a+eYvVBDoQKQz1W8PUvQhAIoAb/Diev2OPb+RJdc0AZ1DgJFSbUCJointmtb -A6Fmfcoe0whyj1xteyJVwFcdCPYE7Ad/1o2JRjRjdYJuRpTFAz0lJf+/Dg3fRAOc -5i9syFWA/cRw6ptJ01UP/0zvyXay0PHYi6Gnmg/CLej3DVya/LpCb/qUjKlyoo5M -RZhEB2/HNgFOOTqcrSDAUH0Fa1Wct48NAyMAz/i7DGk+jLFlLXevn7Fht7m7FQRg -pQvDcHZY03hYDmHB16tDWAB5C1EeJuUs6eBDT2upaxMaaaMVoPWCG7oqFxGWrogQ -bsgwg7/7KBmJTcOWy9+XDu63RcuAFYgopfKI4j6tGObY2CU62ZTF30VtPKpYgM01 -qJKoZi4CDvp9XIvVfJAtJ+2QTcliir4EqnHNE6YngAz2+3J5pTwjNZVBsPrPaeyP -I0wglhpgc3hFkyZz15CZuSzcveo3tmpMabUbB8/AzeyKpLi0wz36H+AqZb38/sPn -xTmR2OJV8ANBhjovbQe8axkRryy5z4lY83K0DnHXe1H6rSLFlvGEc82heSlYcA6y -LU8iHi2uN1q85HCwYsSfBl9t406SyhZf9GkE0iECcVDsUOo3aY2o2uRwxk+4QUVs -9jsmkHLVrEImPKmq7FQIIHerpUf4wTApLJD5rKp5xt2J+/n3xIC6RgQ90GPTxL36 -vdG1Zazfd7LniQ2gsay8P7busPVgpL27Mki5ZvxpPccFqvTPO+z+QaxEmBxSfwP6 -rYvW1oe1WlgNgqOb6ikVpK3uwO8gz/T2uMl4ZaAtrowv3SsMk93cFslxPbWrJrIG -uQINBFzSgocBEADQB1zj8Qk3qYelDNH6BsuNg0VGhAq/EtcD+1M9jDSv5rcLhHMF -ZgIWJVloDlrvkSjoKXOzz775HgTdd5E1NrltFrgJVP5FPBp9Xk58vPsyfb40XIU6 -2KkjZA3g9JBukOAszV2qAMWr68oVCWmWCd5VyhTgzKfKvgf/V1KVVHRqjO2Au4so -JDhscM2FGQtiGgZHT9OQV6/nbZ+tHllJOgZCIJr+UI5Xxf92a/WzoVSXlXDKKE6Z -UR+hZraKJblQOlAav71P0ckBtHIGI2TFjBLEZtHl9Je0/baH2v3mInkBC+uEwaEg -idJb1qVFHb7ykJeC3lZNxUiNQ/7NPSnhNxyBlNugXzrPbLNbQWAr3YDgEP4MUCyM -1KKIoTUlHWUWM/Xx/T6mJtLrRkEYI8Sfb28ozKUm8i6nvefvly45dEplUQ0B1+aP -bhOGg7caxAFaLNoymPzk9H+5aKl+LYvtU421q+LD7QBvGgfQqQ7C34IygQGqqw3b -50VpLKUrTuRptvOjvrJKejc6u0B6K6cM6VzR+p+N7Y7nstzSXZ8cMR51GvtZlrly -xNYjA+8WXU2S8EN4KI5rXRpBow1tPGPFTWV0VZD1VLNlnbBusNvMgghfBC8VQQpx -Sgt+z6z487GyOSbAXOEArrI5eqk+uwhkVFEG9NfJZvCkqS/PZxLPWKxLnQARAQAB -iQI2BBgBCgAgFiEEzowT/MI47P540iwUOa1L7VVSfxwFAlzSgocCGwwACgkQOa1L -7VVSfxzVXg//ZX3u7sz6W8vILxOYa/Z/Rk0rbLR3R1m7EkzKkchOjmNYp3swjxv8 -0VYZixWYQnXFedUYHs4lWiRm+FKftvR7Rw6FswPpG1C9hGzn6jfea3KguvWGzOce -gxWhlkGNMdCf0Y96GRneKnNgSzsZnSTYAxbY8uxs5YUtAaoueU3joBegAedTRhr+ -Z7ey06yahs/2sOkT0bKKhUlHA0/j9kVtrBJKs8YaE6B6IoszotY/yiBWY411IJJC -DUW0VP0rARsq1FvScoChgEOKVguhSmGRqyDw49kI8fS5qvmwEpqNtHxvC7IwZXV8 -M7rSbvjJKaaJMwn8ZvC2UWLqAgTWMEbEWbg3J5tNqWnVfQtMA7WyfFgVZe6vldLU -htKe+DZiR13mX5W5fmTMGZGICn18NHvNKrHS4/wCqO7dEnJaWscrIT9HSufRh851 -Sv+eOatlrADJUajL0OQVZPEf6kfuJCk4udXoar5zlFLeeN6HlM8qVHMwtYc+AM/u -l95SkJtnOcwaViPbpAoKaqvKL0G7HlxBCFdR7fLEaPg9e6BeSKsNeieeRM7gatwJ -6eVLPO3udE3DBAkoubcVFqeVc+K7WBc/ZLfPk/bovYgH6sZUfLma5KDZl6hpomXt -G2yHHNrM6zX8dr8tB0OGPdse6SsvGxFekXVUCeEtH7eznyjA0dKhI3K5Ag0EXNKD -QQEQAMomsfVJfDYS9AY/y8SPQ0cGHuUU6+QSBZ3xSs7isPPyl4Uj+oYu/NvCd+nE -atTkqTqWLGhS8kDd1F6RtFAWWBTKONtQNLrVL7HgyxCOXEsnIDiQsXoenqMiPHS5 -R4C1uMmX/9bARHrrONDJwKPxFVUcwuq1y3wgGSf0knRp5CpZwKpOhHRiAE2pcW3c -xxaX4PDlXjlckabonouaFEKdoRa2JmPGiM/JaNOm4DXxa7Fb4FG+eWnOJ+UEXj+f -7OxXOYZ8DGyoFQqx12K5m7GuhNPxqCesK6clM8lYA1i0rC+5HcLni+o/WAII/dOt -89SxB1MqHaoBjJfV+xWXyDSYDamqtzQlqGOYIhDb2GyAlBUGtfe1iG8Mq/bt7kZc -fqcf464LenKCyySPTM5Ga3ucT0eBIXhv2IQHk5yWBHF8xVtM0MqqjxKbDdXy7hEY -C9vB8aQWY3Vx505TdcqyWCO1H7Q2c9Gr7ANidTzaQ7/rBZgqCQbevrHWVPY8Z4PB -Ep5Xgif+COrZ15g47Hj+SmdRC08avNupTIyNSK4G2guhe04o3O8WFyZBWGGPyesf -adoU4lsQalVCq9nCDpVoOgnN1qKsXCo4ON4GNrwo6TslMiuy/NrUB8KAZA1CCMYI -ydpCcITnQ7mgtXA58lUmoMGtMirMwbkXJCe8A4l6dHZMiFpzABEBAAGJAjYEGAEK -ACAWIQTOjBP8wjjs/njSLBQ5rUvtVVJ/HAUCXNKDQQIbIAAKCRA5rUvtVVJ/HMsr -D/0Yqb63eMSTCXO0MYEcinx65rr73R09jSQ0LHDy3DhqXlEf5lt71bw0TnknQa4M -xR7SjDPwefVIEPDDjcvDjCVJvhiG8sbFFvSJVevYo2Ejg/wvI6Jn9UsBTvcnOKfp -r6HY9eLJC5fqVKC9BlRBQLeQAxxQFAjyZwzgo91GqwGQvifdoGIKx2RrhqJnF7SI -+ydHlmHp3BXOdoeZ7vM5ytTqUMSAIbYLkcEA/40gmgC/jfpt3nRxO6CjbQcgEtoB -MI5qqBQNoAVcKvv2MQiiOw7hXzDbdpoo2iSNNtYzfyKobWiDB5xvjcTyTdSoJbsk -stwgHyLn44dkXN6tBaBT15HvXIyFBmIzmVAlouHk/7DXfSBxdHM5dDSEwAKyctTI -WIbdfWDjhqBG9wgFkT5RjiP0XTGa3BPS0n7y9dtWJdU2rsghb6YCLV+N88m5vl05 -pFUalZ4aeobQwYBdoHClw4xC6JHIV5eAeeL7id+27CZwiLwpkk8nRtHFSJA1xA// -ErfvvyxvBOudu7Pz8CcU0BeioxTSsnTboKCKa3KCmj2iD/omscmQl+UFrkB+whe4 -WRQf+6WtlcVbpfQYn8CKcW0VOUvIQzWc7/DmbqYeAbTxNOyZlPB3A9A/6YGuhA0m -8dT4uylSer7yYboU4q/yWyRM8DQStdpZxu0r5ySIpi6cOA== -=6sgk ------END PGP PUBLIC KEY BLOCK----- diff --git a/scm-webapp/src/test/resources/sonia/scm/security/gpg/signature.asc b/scm-webapp/src/test/resources/sonia/scm/security/gpg/signature.asc deleted file mode 100644 index f3e756a16d..0000000000 --- a/scm-webapp/src/test/resources/sonia/scm/security/gpg/signature.asc +++ /dev/null @@ -1,16 +0,0 @@ ------BEGIN PGP SIGNATURE----- - - iQIzBAABCgAdFiEEAibrQDifYryAFPjQHxe3mgna1bkFAl8gSFMACgkQHxe3mgna - 1bk0Hg/9HaN7aRkRo1FH5xPnswGFAidHG+XQBFYTK3EhR2g6m4iRCij58qIEMQVh - gV6FTtz6xGB/Oq32e5+gp9dYTp6lTrfm35hjg7uzwiC7OQx3QswZn7GUX/ZmuLk0 - nqz4ryiVxeMWst47JkKAm9PY6GC+UITaL3tptNF//MBPAwEfNnDP7O667BTvnROh - 9XaSlIdYlbGxs5YzQK8BMB56YdutTDMtHl92oOjDA7r238dScmlNUSw3IQIsNPkz - 4WZwGM7HVxw7PjbRoMbwXbNEJ87F4SuBqhWM7BjHEUFS21wH8APtVZrNzd2znveq - oemn/+9pn0LG3Mg/2FASqHA6X+HS79YT9fb0O3HUvHzlaJmev88h4JSGcTJZG5+o - a9LEPW56clJYmCq/ghKAyV+bJfUkIAP9i75p4zi8Il4ACJnf9oVRg6RuOTXK5cnf - bvSzEtBWlXT1ELV52uo9gwcQMqgkQ89p8pTHcYHD3UhfdsuCfzlTGP/aQ/6OUBGg - k6AFS1kAwalAp2VEOBIJUXylM60VfdLaLfWpgg4T8mq4WIV3ROXTV0o2XciuF4r0 - 2oXtyc84J7nnGJlJ4HqHBqzMNHF4giqVNhKQzBAQ1OEjePBfkW6RMDcYxkLilUrU - LzguRD1ybuS9xYQK60s2S68sNoAFkY8NTn9z8je1BO7ajzQn/fw= - =smHD - -----END PGP SIGNATURE----- diff --git a/scm-webapp/src/test/resources/sonia/scm/security/gpg/slarti.txt b/scm-webapp/src/test/resources/sonia/scm/security/gpg/slarti.txt new file mode 100644 index 0000000000..cef9ef5b9f --- /dev/null +++ b/scm-webapp/src/test/resources/sonia/scm/security/gpg/slarti.txt @@ -0,0 +1,9 @@ +Slartibartfast is a Magrathean, and a designer of planets.[2] His favourite part of the job is creating coastlines, the most notable of which are the fjords found on the coast of Norway on planet Earth,[3] for which he won an award. While trapped on prehistoric Earth, Arthur Dent and Ford Prefect see Slartibartfast's signature deep inside a glacier in ancient Norway. + +When Earth Mk. II is being made, Slartibartfast is assigned to the continent of Africa. He is unhappy about this because he has begun "doing it with fjords again" (arguing that they give a continent a lovely baroque feel), but has been told by his superiors that they are "not equatorial enough". In relation to this, he expresses the view that he would "far rather be happy than right any day." + +In any event, the new Earth is not required and, much to Slartibartfast's disgust, its owners suggested that he take a quick skiing holiday on his glaciers before dismantling them. + +Slartibartfast's aircar is later found near the place where Zaphod Beeblebrox, Ford Prefect, Trillian and Arthur Dent are attacked by cops, who are suddenly killed in a way similar to how the cleaning staff in Slartibartfast's study have perished. There is a note pointing to one of the controls in the aircar saying "This is the probably the best button to press." + +In Life, the Universe and Everything Slartibartfast has joined the Campaign for Real Time (or "CamTim" as the volunteers casually refer to it, a reference to CAMRA) which tries to preserve events as they happened before time travelling was invented. He picks up Arthur and Ford from Lord's Cricket Ground with his Starship Bistromath, after which they head out to stop the robots of Krikkit from bringing together the pieces of the Wikkit Gate. diff --git a/scm-webapp/src/test/resources/sonia/scm/security/gpg/slarti.txt.asc b/scm-webapp/src/test/resources/sonia/scm/security/gpg/slarti.txt.asc new file mode 100644 index 0000000000..f2262dd80d --- /dev/null +++ b/scm-webapp/src/test/resources/sonia/scm/security/gpg/slarti.txt.asc @@ -0,0 +1,16 @@ +-----BEGIN PGP SIGNATURE----- + +iQIzBAABCgAdFiEE5uxwNFYM4xFJsy3eJH6QjG/TVHMFAl8ii3QACgkQJH6QjG/T +VHPIWQ//fz+n5HLeIDWMeMhvkNes8dwGzdfHme/Yyb1vocqGj3VK+xr3YVjum09h +NjKJvumazdALTUXnXNW9T57LVD3kAJpAnwCHFtIQvPmg0EVn1oz7WDh+YVVA2Ko4 +fGgH0dB64N2FUEmCYU8aV8wKUOgQ8Fh5FcSggzC5UegU9yZou+B38AfI55od1Ay/ +jk5tEExEwsErjjhDZFho/D/Ybp43otj4WtVy+fPHaZYW7TzKRVBi7ngqAlyCFGwO +W/xEy11nv1apXV+l3iGxJkU2jlCi7ORbxH2ooSyhrC33rWxAtdYxgMElF7lRbnoc +Pg8EQXZ8zmEwgm9u6+Ng0/qsu/wajV+QKSDMRJMhmFN0zpdvyscvaFcowcu6jW25 +Smz/Gs5B2oASDh/L/sLxUdSfCHVM7gk6HYHWNZgSajtpgLeJy8/wxOSYmB2TD72A +ktZN2v5adkaHM8rEXLPdD0BtCMGs82pxgHEK42ncW6RFFdiOkgb6KPhkmhlxl0XU +r64mfHj3n/dNBR5LoSbDFtHD2LakN8CPcubURneA/psfUiUdfktl6KcDYsuS1fJk ++XdxAdVUIqf3MwQU3od1nklu5Sybv5+Q2MZOstGn7opGuQXndKFtnC4WOMfo0w+X +HTZilw/HDYN0wgzLl5YpHWmZ5MQl5/aN1nn5js3vOhgEF3+qhvQ= +=3ZJK +-----END PGP SIGNATURE-----