From: Lucas Werkmeister Date: Tue, 7 Nov 2017 19:36:37 +0000 (+0100) Subject: Merge "add: show more certificates on the "roots" page" X-Git-Url: https://code.wpia.club/?p=gigi.git;a=commitdiff_plain;h=7b9bab0434b96d4bf196a51ab769e33553d3e09e;hp=189f4896bdfa004f3b6a8df7794cc9a2cf0ae09e Merge "add: show more certificates on the "roots" page" --- diff --git a/debian/copyright b/debian/copyright index 7ccbafbb..50f2e57b 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,4 +1,4 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: gigi Source: @@ -22,9 +22,26 @@ Files: src/club/wpia/gigi/database Copyright: 2014-2017 WPIA Software Team License: AGPL-3.0 or BSD +Files: src/club/wpia/gigi/crypto/key/KeyCheckROCA.java +Copyright: 2017, CRoCS, EnigmaBridge Ltd. +License: AGPL-3.0 or MIT + +License: AGPL-3.0 + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + . + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + . + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + License: BSD - Copyright (c) 2014, WPIA - All rights reserved. + Copyright (c) . Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -48,16 +65,23 @@ License: BSD ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -License: AGPL-3.0 - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. +License: MIT + Copyright (c) . - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: . - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + . + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. diff --git a/src/club/wpia/gigi/Gigi.java b/src/club/wpia/gigi/Gigi.java index 19818767..6a0b7936 100644 --- a/src/club/wpia/gigi/Gigi.java +++ b/src/club/wpia/gigi/Gigi.java @@ -395,7 +395,12 @@ public final class Gigi extends HttpServlet { resp.sendError(403); return; } - if (p.beforeTemplate(req, resp)) { + try { + if (p.beforeTemplate(req, resp)) { + return; + } + } catch (CSRFException e) { + resp.sendError(500, "CSRF invalid"); return; } HashMap vars = new HashMap(); diff --git a/src/club/wpia/gigi/crypto/key/KeyCheck.java b/src/club/wpia/gigi/crypto/key/KeyCheck.java new file mode 100644 index 00000000..b6efd542 --- /dev/null +++ b/src/club/wpia/gigi/crypto/key/KeyCheck.java @@ -0,0 +1,62 @@ +package club.wpia.gigi.crypto.key; + +import java.security.PublicKey; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import club.wpia.gigi.GigiApiException; + +public abstract class KeyCheck { + + protected static final Set checks = new LinkedHashSet(); + + public static List getChecks() { + return Collections.list(Collections.enumeration(checks)); + } + + public static void register(KeyCheck check) { + checks.add(check); + } + + public abstract void check(PublicKey key) throws GigiApiException; + + public static void checkKey(PublicKey key) throws GigiApiException { + + if (checks.isEmpty() || checks.size() < 3) { + // Mandatory checks are registered here + register(new KeyCheckPublicKeyFormat()); + register(new KeyCheckSmallFactors()); + register(new KeyCheckROCA()); + } + + if (key == null) { + throw new GigiApiException("Failed key sanity check: No key given!"); + } + + for (KeyCheck kc : checks) { + kc.check(key); + } + + } + + @Override + public boolean equals(Object o) { + if (o == null) { + return false; + } + + if (o == this) { + return true; + } + + return getClass().equals(o.getClass()); + } + + @Override + public int hashCode() { + return getClass().hashCode(); + } + +} diff --git a/src/club/wpia/gigi/crypto/key/KeyCheckPublicKeyFormat.java b/src/club/wpia/gigi/crypto/key/KeyCheckPublicKeyFormat.java new file mode 100644 index 00000000..c85b16cd --- /dev/null +++ b/src/club/wpia/gigi/crypto/key/KeyCheckPublicKeyFormat.java @@ -0,0 +1,36 @@ +package club.wpia.gigi.crypto.key; + +import java.security.PublicKey; +import java.security.interfaces.DSAPublicKey; +import java.security.interfaces.ECPublicKey; +import java.security.interfaces.RSAPublicKey; + +import club.wpia.gigi.GigiApiException; +import club.wpia.gigi.output.template.SprintfCommand; + +public class KeyCheckPublicKeyFormat extends KeyCheck { + + static { + register(new KeyCheckPublicKeyFormat()); + } + + @Override + public void check(PublicKey key) throws GigiApiException { + + if (key instanceof RSAPublicKey) { + return; + } + + if (key instanceof DSAPublicKey) { + return; + } + + if (key instanceof ECPublicKey) { + return; + } + + throw new GigiApiException(SprintfCommand.createSimple("Public Key Format Check: Unknown or unsupported public key algorithm {0}", key.getAlgorithm())); + + } + +} diff --git a/src/club/wpia/gigi/crypto/key/KeyCheckROCA.java b/src/club/wpia/gigi/crypto/key/KeyCheckROCA.java new file mode 100644 index 00000000..e808cdda --- /dev/null +++ b/src/club/wpia/gigi/crypto/key/KeyCheckROCA.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2017, CRoCS, EnigmaBridge Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/* + * Credits: ported to Java by Martin Paljak + */ +/* + * Credits: ported to Gigi KeyCheck interface by Benny Baumann + */ + +package club.wpia.gigi.crypto.key; + +import java.math.BigInteger; +import java.security.PublicKey; +import java.security.interfaces.RSAPublicKey; + +import club.wpia.gigi.GigiApiException; + +/** + * Due to a bug in several chips produced by Infineon several cryptographic + * processors in smartcards and other HSM appliances produced RSA keys with a + * weakness that made them subject for easy factorization. The vulnerability has + * been present in Infineon's library from about 2014 through 2017 making keys + * up to 2048 bit RSA practically factorable and strongly weakens larger RSA + * keys produced with such an implementation. This check implements a + * fingerprinting mechanism detecting such keys using a heuristic found by the + * researchers describing the vulnerability. Any such keys SHALL NOT be + * certified. This implementation is based on the Java port by Martin Paljak. + * + * @see Original ROCA + * vulnerability website + * @see Report by + * ArsTechnica on ROCA + * @see Gist + * by Hanno Böck detailling impacted keys + * @see Java + * port by Martin Paljak + */ +public class KeyCheckROCA extends KeyCheck { + + /** + * List of Lengths of masks for the listed {@link #markers}. + */ + private static final int[] prims = new int[] { + 11, 13, 17, 19, 37, 53, 61, 71, 73, 79, 97, 103, 107, 109, 127, 151, 157 + }; + + private static final BigInteger[] primes = new BigInteger[prims.length]; + + /** + * List of markers used to fingerprint keys vulnerable to ROCA. + * + * This list is reduced according to: + * {@link https://groups.google.com/d/msg/mozilla.dev.security.policy/4RqKdD0FeF4/DcxMqchSAQAJ} + */ + private static final BigInteger[] markers = new BigInteger[] { + new BigInteger("1026"), // 11:402 + new BigInteger("5658"), // 13:161a + new BigInteger("107286"), // 17:1a316 + new BigInteger("199410"), // 19:30af2 + new BigInteger("67109890"), // 37:4000402 + new BigInteger("5310023542746834"), // 53:12dd703303aed2 + new BigInteger("1455791217086302986"), // 61:1434026619900b0a + new BigInteger("20052041432995567486"), // 71:1164729716b1d977e + new BigInteger("6041388139249378920330"), // 73:147811a48004962078a + new BigInteger("207530445072488465666"), // 79:b4010404000640502 + new BigInteger("79228162521181866724264247298"), // 97:1000000006000001800000002 + new BigInteger("1760368345969468176824550810518"), // 103:16380e9115bd964257768fe396 + new BigInteger("50079290986288516948354744811034"), // 107:27816ea9821633397be6a897e1a + new BigInteger("473022961816146413042658758988474"), // 109:1752639f4e85b003685cbe7192ba + new BigInteger("144390480366845522447407333004847678774"), // 127:6ca09850c2813205a04c81430a190536 + new BigInteger("1800793591454480341970779146165214289059119882"), // 151:50c018bc00482458dac35b1a2412003d18030a + new BigInteger("126304807362733370595828809000324029340048915994"), // 157:161fb414d76af63826461899071bd5baca0b7e1a + }; + + static { + for (int i = 0; i < prims.length; i++) { + primes[i] = BigInteger.valueOf(prims[i]); + } + + register(new KeyCheckROCA()); + } + + @Override + public void check(PublicKey key) throws GigiApiException { + + if ( !(key instanceof RSAPublicKey)) { + return; + } + + BigInteger modulus = ((RSAPublicKey) key).getModulus(); + + for (int i = 0; i < primes.length; i++) { + if (BigInteger.ONE.shiftLeft(modulus.remainder(primes[i]).intValue()).and(markers[i]).equals(BigInteger.ZERO)) { + return; + } + } + + throw new GigiApiException("ROCA vulnerability check for public key: Key likely vulnerable as fingerprint matches."); + + } + +} diff --git a/src/club/wpia/gigi/crypto/key/KeyCheckSmallFactors.java b/src/club/wpia/gigi/crypto/key/KeyCheckSmallFactors.java new file mode 100644 index 00000000..a0965344 --- /dev/null +++ b/src/club/wpia/gigi/crypto/key/KeyCheckSmallFactors.java @@ -0,0 +1,52 @@ +package club.wpia.gigi.crypto.key; + +import java.math.BigInteger; +import java.security.PublicKey; +import java.security.interfaces.RSAPublicKey; +import java.util.ArrayList; + +import club.wpia.gigi.GigiApiException; +import club.wpia.gigi.output.template.SprintfCommand; + +public class KeyCheckSmallFactors extends KeyCheck { + + private static final long MAX_CHECKED_SMALL_PRIME_BOUNDARY = 10000; + + private static final BigInteger[] primes; + + static { + ArrayList prims = new ArrayList<>(1024); + + NextPrime: + for (long i = 2; i < MAX_CHECKED_SMALL_PRIME_BOUNDARY; i++) { + for (BigInteger p : prims) { + if (BigInteger.ZERO.equals(BigInteger.valueOf(i).mod(p))) { + continue NextPrime; + } + } + + prims.add(BigInteger.valueOf(i)); + } + + primes = prims.toArray(new BigInteger[0]); + + register(new KeyCheckSmallFactors()); + } + + @Override + public void check(PublicKey key) throws GigiApiException { + if ( !(key instanceof RSAPublicKey)) { + return; + } + + BigInteger modulus = ((RSAPublicKey) key).getModulus(); + + // Check for small prime factors below 10000 + for (BigInteger n : primes) { + if (BigInteger.ZERO.equals(modulus.mod(n))) { + throw new GigiApiException(SprintfCommand.createSimple("Small factors check of public key: Key is divisible by {0}.", n.toString())); + } + } + } + +} diff --git a/src/club/wpia/gigi/pages/account/certs/CertificateRequest.java b/src/club/wpia/gigi/pages/account/certs/CertificateRequest.java index 4158e9ba..8a1bc594 100644 --- a/src/club/wpia/gigi/pages/account/certs/CertificateRequest.java +++ b/src/club/wpia/gigi/pages/account/certs/CertificateRequest.java @@ -16,6 +16,7 @@ import java.util.TreeSet; import club.wpia.gigi.GigiApiException; import club.wpia.gigi.crypto.SPKAC; +import club.wpia.gigi.crypto.key.KeyCheck; import club.wpia.gigi.dbObjects.Certificate; import club.wpia.gigi.dbObjects.Certificate.CSRType; import club.wpia.gigi.dbObjects.Certificate.SANType; @@ -108,7 +109,7 @@ public class CertificateRequest { this(c, csr, (CertificateProfile) null); } - public CertificateRequest(AuthorizationContext ctx, String csr, CertificateProfile cp) throws GeneralSecurityException, IOException, IOException { + public CertificateRequest(AuthorizationContext ctx, String csr, CertificateProfile cp) throws GeneralSecurityException, IOException, IOException, GigiApiException { this.ctx = ctx; if (cp != null) { profile = cp; @@ -190,6 +191,8 @@ public class CertificateRequest { } this.SANs = SANs; pk = parsed.getSubjectPublicKeyInfo(); + KeyCheck.checkKey(pk); + String sign = getSignatureAlgorithm(data); guessDigest(sign); @@ -206,12 +209,13 @@ public class CertificateRequest { throw new GigiApiException("Challenge mismatch"); } pk = parsed.getPubkey(); + KeyCheck.checkKey(pk); + String sign = getSignatureAlgorithm(data); guessDigest(sign); this.SANs = new HashSet<>(); this.csr = "SPKAC=" + cleanedSPKAC; this.csrType = CSRType.SPKAC; - } private static String getSignatureAlgorithm(byte[] data) throws IOException { diff --git a/src/club/wpia/gigi/ping/PingerDaemon.java b/src/club/wpia/gigi/ping/PingerDaemon.java index 51cc9858..d6016c67 100644 --- a/src/club/wpia/gigi/ping/PingerDaemon.java +++ b/src/club/wpia/gigi/ping/PingerDaemon.java @@ -12,7 +12,6 @@ import club.wpia.gigi.database.GigiResultSet; import club.wpia.gigi.dbObjects.Domain; import club.wpia.gigi.dbObjects.DomainPingConfiguration; import club.wpia.gigi.dbObjects.DomainPingType; -import club.wpia.gigi.util.RandomToken; public class PingerDaemon extends Thread { @@ -91,11 +90,6 @@ public class PingerDaemon extends Thread { String config = conf.getInfo(); DomainPinger dp = pingers.get(type); if (dp != null) { - if (dp instanceof EmailPinger) { - String token = null; - token = RandomToken.generateToken(16); - config = config + ":" + token; - } Domain target = conf.getTarget(); System.err.println("Executing " + dp + " on " + target + " (" + System.currentTimeMillis() + ")"); try { diff --git a/tests/club/wpia/gigi/LoginTest.java b/tests/club/wpia/gigi/LoginTest.java index ab2780c4..551d88d2 100644 --- a/tests/club/wpia/gigi/LoginTest.java +++ b/tests/club/wpia/gigi/LoginTest.java @@ -28,7 +28,7 @@ public class LoginTest extends ManagedTest { public void testLoginUnverified() throws IOException { String email = createUniqueName() + "@testmail.org"; registerUser("an", "bn", email, TEST_PASSWORD); - getMailReceiver().receive(); + getMailReceiver().receive(email); assertFalse(isLoggedin(login(email, TEST_PASSWORD))); } diff --git a/tests/club/wpia/gigi/TestUser.java b/tests/club/wpia/gigi/TestUser.java index 7ad3f49d..a2206ee2 100644 --- a/tests/club/wpia/gigi/TestUser.java +++ b/tests/club/wpia/gigi/TestUser.java @@ -10,8 +10,6 @@ import java.util.Locale; import org.hamcrest.CoreMatchers; import org.junit.Test; -import club.wpia.gigi.dbObjects.Verification; -import club.wpia.gigi.dbObjects.Verification.VerificationType; import club.wpia.gigi.dbObjects.Country; import club.wpia.gigi.dbObjects.Country.CountryCodeType; import club.wpia.gigi.dbObjects.Domain; @@ -20,6 +18,8 @@ import club.wpia.gigi.dbObjects.Name; import club.wpia.gigi.dbObjects.NamePart; import club.wpia.gigi.dbObjects.NamePart.NamePartType; import club.wpia.gigi.dbObjects.User; +import club.wpia.gigi.dbObjects.Verification; +import club.wpia.gigi.dbObjects.Verification.VerificationType; import club.wpia.gigi.testUtils.BusinessTest; import club.wpia.gigi.util.DayDate; import club.wpia.gigi.util.Notary; @@ -90,9 +90,9 @@ public class TestUser extends BusinessTest { User u = User.getById(id); new EmailAddress(u, uq + "b@email.org", Locale.ENGLISH); - getMailReceiver().receive().verify(); + getMailReceiver().receive(uq + "b@email.org").verify(); new EmailAddress(u, uq + "c@email.org", Locale.ENGLISH); - getMailReceiver().receive();// no-verify + getMailReceiver().receive(uq + "c@email.org");// no-verify assertEquals(3, u.getEmails().length); assertTrue(u.isValidEmail(uq + "a@email.org")); diff --git a/tests/club/wpia/gigi/api/TestFindAgent.java b/tests/club/wpia/gigi/api/TestFindAgent.java index b1bec53e..753eb779 100644 --- a/tests/club/wpia/gigi/api/TestFindAgent.java +++ b/tests/club/wpia/gigi/api/TestFindAgent.java @@ -15,14 +15,13 @@ import org.json.JSONTokener; import org.junit.Test; import club.wpia.gigi.GigiApiException; -import club.wpia.gigi.api.FindAgent; import club.wpia.gigi.dbObjects.Certificate; +import club.wpia.gigi.dbObjects.Certificate.CSRType; +import club.wpia.gigi.dbObjects.Certificate.SANType; import club.wpia.gigi.dbObjects.CertificateProfile; import club.wpia.gigi.dbObjects.Digest; import club.wpia.gigi.dbObjects.Group; import club.wpia.gigi.dbObjects.User; -import club.wpia.gigi.dbObjects.Certificate.CSRType; -import club.wpia.gigi.dbObjects.Certificate.SANType; import club.wpia.gigi.pages.account.FindAgentAccess; import club.wpia.gigi.testUtils.IOUtils; import club.wpia.gigi.testUtils.RestrictedApiTest; @@ -73,10 +72,9 @@ public class TestFindAgent extends RestrictedApiTest { grant((userUFirst ? us2 : u), Group.LOCATE_AGENT); v = doApi(FindAgent.PATH_MAIL, "from=" + id + "&to=" + u2 + "&subject=the-subject&body=body"); assertEquals(v.getResponseMessage(), 200, v.getResponseCode()); - TestMail mail = getMailReceiver().receive(); + TestMail mail = getMailReceiver().receive(us2.getEmail()); assertEquals("body", mail.getMessage()); assertThat(mail.getSubject(), containsString("the-subject")); - assertEquals(us2.getEmail(), mail.getTo()); } @Test diff --git a/tests/club/wpia/gigi/crypto/key/KeyCheckPublicKeyFormatTest.java b/tests/club/wpia/gigi/crypto/key/KeyCheckPublicKeyFormatTest.java new file mode 100644 index 00000000..e8d3ec64 --- /dev/null +++ b/tests/club/wpia/gigi/crypto/key/KeyCheckPublicKeyFormatTest.java @@ -0,0 +1,117 @@ +package club.wpia.gigi.crypto.key; + +import static org.junit.Assert.*; +import static org.junit.Assume.*; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.PublicKey; + +import org.junit.Test; + +import club.wpia.gigi.GigiApiException; + +public class KeyCheckPublicKeyFormatTest { + + @Test + public void testFormatRSA() throws GeneralSecurityException, IOException { + + // openssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:2048 + // -pkeyopt rsa_keygen_pubexp:7331 2>/dev/null | + // openssl pkey -pubout -outform pem + String sfk = "-----BEGIN PUBLIC KEY-----\n" + // + "MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQEArcAPmy3RnXdwyFg3V9k1\n" + // + "RaFR/peHa3hLsmh25BInRVArbaMctSBaJBVZwQIgBdqjyITQQZP38i6k+WdsETn9\n" + // + "J491UDLKU3E3UG60ZS3BzcJllNdpn4g0IZROxmmUz2JlAXkGtIglmWWDx14qHSNj\n" + // + "ON58mc3ihfn/oWkPk2hk/csDxGQq5jSaBUwa9THBg9UQHHBqQbhp2nGfa5a5VRlI\n" + // + "0QeIy+8GmKlXYMchReUI25ksLOzaqETD0UXiAPyt+vpvkKCDjWGc3kjabn6OkuTt\n" + // + "na7N/52qrEC2ImuanYlzR5gv9jkbFF2PiMIEBD+3B0842rLx0X/lbXhRr1MtuHtN\n" + // + "tQICHKM=\n" + // + "-----END PUBLIC KEY-----\n"; + + PublicKey pk = KeyCheckTest.pkFromString(sfk); + try { + KeyCheck c = new KeyCheckPublicKeyFormat(); + c.check(pk); + } catch (GigiApiException gae) { + throw new Error("Valid key (RSA Public Key) rejected.", gae); + } + + } + + @Test + public void testFormatDSA() throws GeneralSecurityException, IOException { + + // DSA (using OpenSSH) + String sfk = "-----BEGIN PUBLIC KEY-----\n" + // + "MIIBtzCCASsGByqGSM44BAEwggEeAoGBAJpcf099rROPSjbJ5KWk5RF1ngRqXSo7\n" + // + "cmKin9QPxIg0tXmxMGVS2sdtXYtmSJ9fewSAx0vHbojysEGY9ASXEoFpzDye4BbK\n" + // + "yog9oHaUUEjxkSTwKcipu5BgM9b/nvigw/bs4dlEM+egdzf36lXXXJgvaTeXSpu9\n" + // + "gKrKXTSi0jcvAhUAoH2Nbl6mRgAX4l6U5EXeg0zts3MCgYAW16cPIxLzmvrajRVR\n" + // + "aIzAWpN1ApE/kx4CbtWZCdNttHu3c8D6qSnVrWpxY6FzrpeFniwg4vu73Ykh3crH\n" + // + "0rVa20lrdRUAYGzbgInS+GLoPDGu1LukF0evJYZwyt6qsaFkQ54h4StSK+oM/mOi\n" + // + "haLI45Rvlmade3KRQ/7YkV7DZQOBhQACgYEAjVGvOHImKynxgBl+eHeN2Ddqgj1+\n" + // + "AKEOFKuFuedG9tKHtZXx04j982kaDnNc5cZY1KPFPYlS7jVJwcFPuf9Hi1/Aqq+3\n" + // + "GnqaPl+tJtSpY2Chu8iIHIi5OXiwQC9ImtIEASZkkO+RIPLpzgb3GTn306NtMxae\n" + // + "e+mhIx1IrbzMxSA=\n" + // + "-----END PUBLIC KEY-----\n"; + + PublicKey pk = KeyCheckTest.pkFromString(sfk); + try { + KeyCheck c = new KeyCheckPublicKeyFormat(); + c.check(pk); + } catch (GigiApiException gae) { + throw new Error("Valid key (DSA Public Key) rejected.", gae); + } + + } + + @Test + public void testFormatECDSA() throws GeneralSecurityException, IOException { + + // ECDSA (secp256r1 / P-256) + String sfk = "-----BEGIN PUBLIC KEY-----\n" + // + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIQeJlVJLBpevYZjGWPPkD6hSrUEI\n" + // + "G86i9e2p2QGCanQzNNM8Dkqv5Oa13qjxhRZNo2w+lVOBkAZyAptNKKT5Kw==\n" + // + "-----END PUBLIC KEY-----\n"; + + PublicKey pk = KeyCheckTest.pkFromString(sfk); + try { + KeyCheck c = new KeyCheckPublicKeyFormat(); + c.check(pk); + } catch (GigiApiException gae) { + throw new Error("Valid key (ECDSA Public Key on P-256) rejected.", gae); + } + + } + + @Test + public void testFormatGOST() throws GeneralSecurityException, IOException { + + // GOST R 34.10-2001 (256 bits) + // https://lib.void.so/an-example-of-using-openssl-gost-engine-in-cc/ + String sfk = "-----BEGIN PUBLIC KEY-----\n" + // + "MGMwHAYGKoUDAgITMBIGByqFAwICIwEGByqFAwICHgEDQwAEQDv/qpUxeRWXnyF8\n" + // + "YwSUq7qQsL6MtD42GxLxqzLGx3NmpD4rHRay4xgQp91oTtqJjnybsplij0haRq7i\n" + // + "Nf7QEdY=\n" + // + "-----END PUBLIC KEY-----"; + + final PublicKey pk; + try { + pk = KeyCheckTest.pkFromString(sfk); + } catch (GeneralSecurityException gse) { + assumeTrue("Could not load the GOST key due to lack of support", false); + return; + } + + try { + KeyCheck c = new KeyCheckPublicKeyFormat(); + c.check(pk); + fail("Unsupported key (GOST Public Key) accepted."); + } catch (GigiApiException gae) { + // expected + } + + } + +} diff --git a/tests/club/wpia/gigi/crypto/key/KeyCheckROCATest.java b/tests/club/wpia/gigi/crypto/key/KeyCheckROCATest.java new file mode 100644 index 00000000..3812d030 --- /dev/null +++ b/tests/club/wpia/gigi/crypto/key/KeyCheckROCATest.java @@ -0,0 +1,122 @@ +package club.wpia.gigi.crypto.key; + +import static org.junit.Assert.*; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.PublicKey; + +import org.junit.Test; + +import club.wpia.gigi.GigiApiException; + +// Vulnerable keys for this test taken from +// @link https://misissued.com/batch/28/ +public class KeyCheckROCATest { + + @Test + public void testROCASaneKey() throws GeneralSecurityException, IOException { + + // Normal public key generated with OpenSSL: + // openssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:2048 + // -pkeyopt rsa_keygen_pubexp:7331 2>/dev/null | + // openssl pkey -pubout -outform pem + String sfk = "-----BEGIN PUBLIC KEY-----\n" + // + "MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQEArcAPmy3RnXdwyFg3V9k1\n" + // + "RaFR/peHa3hLsmh25BInRVArbaMctSBaJBVZwQIgBdqjyITQQZP38i6k+WdsETn9\n" + // + "J491UDLKU3E3UG60ZS3BzcJllNdpn4g0IZROxmmUz2JlAXkGtIglmWWDx14qHSNj\n" + // + "ON58mc3ihfn/oWkPk2hk/csDxGQq5jSaBUwa9THBg9UQHHBqQbhp2nGfa5a5VRlI\n" + // + "0QeIy+8GmKlXYMchReUI25ksLOzaqETD0UXiAPyt+vpvkKCDjWGc3kjabn6OkuTt\n" + // + "na7N/52qrEC2ImuanYlzR5gv9jkbFF2PiMIEBD+3B0842rLx0X/lbXhRr1MtuHtN\n" + // + "tQICHKM=\n" + // + "-----END PUBLIC KEY-----\n"; + + PublicKey pk = KeyCheckTest.pkFromString(sfk); + try { + KeyCheck c = new KeyCheckROCA(); + c.check(pk); + } catch (GigiApiException gae) { + throw new Error("Valid key (not vulnerable to ROCA vulnerability) rejected.", gae); + } + + } + + @Test + public void testROCAVulnerable1() throws GeneralSecurityException, IOException { + + // D-TRUST Qualified Root CA 1 2014:PN + // https://crt.sh/?id=26311918&opt=cablint + String sfk = "-----BEGIN PUBLIC KEY-----\n" + // + "MIIBJDANBgkqhkiG9w0BAQEFAAOCAREAMIIBDAKCAQEAlT2Gi8cR+hX+0iYaYH0e\n" + // + "Pmxrqq1tNKlvcesp1wwIeixqeQ2/QJkFMEAVq3hX45Cri7Z/p9ch8+Nd7eva80Ym\n" + // + "nn0llfQ2kJDhi1fOTfodR7IN24105y5D6Lf3zre6J2FOxqPH/q0dDJAbTbuaO4kS\n" + // + "yI9xUEhvHo8oZ0L3SGq6VyeeOBXDoBg4xp6xp1w6cZ76/3HhuBc26sgoO9AvDRzp\n" + // + "M74wvzGBSVaA8+SU1O46plY4os4GlHEdcZM/0NcHeiWwJvycPKkurVL9AxDBq9Iw\n" + // + "Dox/+zQzxcS7txvrJeI1ahQwPpzYdJEwFQ6/rCt43KALWt+OoAIvW5TVYllaF62Z\n" + // + "XwIFAJLK1sU=\n" + // + "-----END PUBLIC KEY-----\n"; + + PublicKey pk = KeyCheckTest.pkFromString(sfk); + try { + KeyCheck c = new KeyCheckROCA(); + c.check(pk); + fail("Invalid key (ROCA vulnerable) accepted."); + } catch (GigiApiException gae) { + // expected + } + + } + + @Test + public void testROCAVulnerable2() throws GeneralSecurityException, IOException { + + // D-TRUST Qualified Root CA 2 2014:PN + // https://crt.sh/?id=26310640&opt=cablint + String sfk = "-----BEGIN PUBLIC KEY-----\n" + // + "MIIBJDANBgkqhkiG9w0BAQEFAAOCAREAMIIBDAKCAQEAmDbSRazHfc1YoqH6dXWz\n" + // + "k2zBJadliqHgpft1Z5HqXF6AzXQ8duHLN3Db+SSDUWP+fDv1Ti69wmH5HqrdSGcl\n" + // + "EvoNStTRjFpnzj/7c5AkALWeZlRzcrBjeIFTtSdZvgluA14BnQXmRViC3tgOFMyU\n" + // + "I72wqCGuf7Y8cW/DSfSzBWFTO+A9uoj0oMKEaaLd1iVF4mctKf/atrHzy3Ny1/d9\n" + // + "WgbLLxiGtrNxVh78j9HCS4rs17AEC3OZnosUE3jCzLCHyQjwI+frkmINj5Qy4L3j\n" + // + "GJqxtIBBb9LwaCkkuV3g679/V4BhWKpDt6YIo/YYINRu42GhXSB9x13KhSMGe9vn\n" + // + "eQIFAKY6EqM=\n" + // + "-----END PUBLIC KEY-----\n"; + + PublicKey pk = KeyCheckTest.pkFromString(sfk); + try { + KeyCheck c = new KeyCheckROCA(); + c.check(pk); + fail("Invalid key (ROCA vulnerable) accepted."); + } catch (GigiApiException gae) { + // expected + } + + } + + @Test + public void testROCAVulnerable3() throws GeneralSecurityException, IOException { + + // D-TRUST Qualified Root CA 3 2014:PN + // https://crt.sh/?id=26310642&opt=cablint + String sfk = "-----BEGIN PUBLIC KEY-----\n" + // + "MIIBJDANBgkqhkiG9w0BAQEFAAOCAREAMIIBDAKCAQEAlpwnRwC1ogIM/Wywu3ys\n" + // + "HhREKeT56eDAMO+68dvz/mWL7dzFhIFHdehRpSpICx06tb7YpK6/XX9/0okTKajt\n" + // + "K0paM3mqZWNilpZnCzItFjwYjxKZL8Bgxww0ztqGD/2oHtmviZNO6yeaLYmm2Eqv\n" + // + "hXCVPUCcE17BPjybSZaW3ULaTiIQFYcCB5/utyXu3RT8ss2NBNoD9D4S5r3dMMJY\n" + // + "qUE/oojbg/4Y955M0S+yEUuv2dfbE+BCkZqgM05yk/wNr9L8F2f7cG2h/qjFUBE5\n" + // + "91kZXZ0g3lBhbKx9SUM8/Vq3WMmfDDpV2qk9wXC0sMgVAwTYLN1J3LWow/C+4Ffo\n" + // + "xQIFAI0kKjs=\n" + // + "-----END PUBLIC KEY-----\n"; + + PublicKey pk = KeyCheckTest.pkFromString(sfk); + try { + KeyCheck c = new KeyCheckROCA(); + c.check(pk); + fail("Invalid key (ROCA vulnerable) accepted."); + } catch (GigiApiException gae) { + // expected + } + + } + +} diff --git a/tests/club/wpia/gigi/crypto/key/KeyCheckSmallFactorsTest.java b/tests/club/wpia/gigi/crypto/key/KeyCheckSmallFactorsTest.java new file mode 100644 index 00000000..2d5e4cb9 --- /dev/null +++ b/tests/club/wpia/gigi/crypto/key/KeyCheckSmallFactorsTest.java @@ -0,0 +1,67 @@ +package club.wpia.gigi.crypto.key; + +import static org.junit.Assert.*; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.PublicKey; + +import org.junit.Test; + +import club.wpia.gigi.GigiApiException; + +public class KeyCheckSmallFactorsTest { + + @Test + public void testSmallPrimesSaneKey() throws GeneralSecurityException, IOException { + + // Normal public key generated with OpenSSL: + // openssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:2048 + // -pkeyopt rsa_keygen_pubexp:7331 2>/dev/null | + // openssl pkey -pubout -outform pem + String sfk = "-----BEGIN PUBLIC KEY-----\n" + // + "MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQEArcAPmy3RnXdwyFg3V9k1\n" + // + "RaFR/peHa3hLsmh25BInRVArbaMctSBaJBVZwQIgBdqjyITQQZP38i6k+WdsETn9\n" + // + "J491UDLKU3E3UG60ZS3BzcJllNdpn4g0IZROxmmUz2JlAXkGtIglmWWDx14qHSNj\n" + // + "ON58mc3ihfn/oWkPk2hk/csDxGQq5jSaBUwa9THBg9UQHHBqQbhp2nGfa5a5VRlI\n" + // + "0QeIy+8GmKlXYMchReUI25ksLOzaqETD0UXiAPyt+vpvkKCDjWGc3kjabn6OkuTt\n" + // + "na7N/52qrEC2ImuanYlzR5gv9jkbFF2PiMIEBD+3B0842rLx0X/lbXhRr1MtuHtN\n" + // + "tQICHKM=\n" + // + "-----END PUBLIC KEY-----\n"; + + PublicKey pk = KeyCheckTest.pkFromString(sfk); + try { + KeyCheck c = new KeyCheckSmallFactors(); + c.check(pk); + } catch (GigiApiException gae) { + throw new Error("Valid key (regarding small factors) rejected.", gae); + } + + } + + @Test + public void testSmallPrimes() throws GeneralSecurityException, IOException { + + // The following key is the above one multiplied by 7331. + String sfk = "-----BEGIN PUBLIC KEY-----\n" + // + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQITb6L+6NEZsFNiuTY42LEg\n" + // + "iPqvDa1K+pXftgWEpTPalebLpKX/Ft11V09pQh/bB6QgNzNXxfBVXE2+UhyrsU+c\n" + // + "g+Esd55384MjBFI37W1U50Xi9VS1s3ls3ZoL2+GAbs6yeSzLA9bMt8YMtj2QAGxi\n" + // + "ZYtKKHLd4qYja0OZCkaED8ys4QB4flRWpbJn+4/Yoj5sXmcy2AP/SoPIRf09T/MQ\n" + // + "OerCZ/3p5blhOGZt1I3MqJNcCoK5oKkzkeQ3AkPqOjGo2qSXObJPMYBHKjIs2JHA\n" + // + "ioTVHwAOgsEfu69srVcgOzsleAVSeDNFWUv5BayWVlGpHtJi4mGHDdyLL7r2SfMC\n" + // + "Rj8CAhyj\n" + // + "-----END PUBLIC KEY-----\n"; + + PublicKey pk = KeyCheckTest.pkFromString(sfk); + try { + KeyCheck c = new KeyCheckSmallFactors(); + c.check(pk); + fail("Invalid key (containing small factors) accepted."); + } catch (GigiApiException gae) { + // expected + } + + } + +} diff --git a/tests/club/wpia/gigi/crypto/key/KeyCheckTest.java b/tests/club/wpia/gigi/crypto/key/KeyCheckTest.java new file mode 100644 index 00000000..aaca8b87 --- /dev/null +++ b/tests/club/wpia/gigi/crypto/key/KeyCheckTest.java @@ -0,0 +1,39 @@ +package club.wpia.gigi.crypto.key; + +import static org.junit.Assert.*; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.PublicKey; + +import org.junit.Test; + +import sun.security.util.DerValue; +import sun.security.x509.X509Key; +import club.wpia.gigi.GigiApiException; +import club.wpia.gigi.util.PEM; + +public class KeyCheckTest { + + public static PublicKey pkFromString(String pub) throws GeneralSecurityException, IOException { + byte[] data = PEM.decode("PUBLIC KEY", pub); + DerValue der = new DerValue(data); + PublicKey key = X509Key.parse(der); + + return key; + } + + @Test + public void testNullKey() { + try { + KeyCheck.checkKey(null); + fail("Providing a null key should fail!"); + } catch (GigiApiException gae) { + // Expected failure + } + + // Check that at least one key check has been loaded + assertFalse(KeyCheck.getChecks().isEmpty()); + } + +} diff --git a/tests/club/wpia/gigi/dbObjects/TestVerificationMail.java b/tests/club/wpia/gigi/dbObjects/TestVerificationMail.java index 43efda4a..f9e43c71 100644 --- a/tests/club/wpia/gigi/dbObjects/TestVerificationMail.java +++ b/tests/club/wpia/gigi/dbObjects/TestVerificationMail.java @@ -9,13 +9,9 @@ import org.junit.Test; import club.wpia.gigi.GigiApiException; import club.wpia.gigi.database.GigiPreparedStatement; -import club.wpia.gigi.dbObjects.Country; -import club.wpia.gigi.dbObjects.Name; -import club.wpia.gigi.dbObjects.NamePart; -import club.wpia.gigi.dbObjects.User; -import club.wpia.gigi.dbObjects.Verification.VerificationType; import club.wpia.gigi.dbObjects.Country.CountryCodeType; import club.wpia.gigi.dbObjects.NamePart.NamePartType; +import club.wpia.gigi.dbObjects.Verification.VerificationType; import club.wpia.gigi.testUtils.BusinessTest; import club.wpia.gigi.util.DayDate; import club.wpia.gigi.util.Notary; @@ -83,7 +79,7 @@ public class TestVerificationMail extends BusinessTest { // verify preferred name only enterVerification(firstName); - message = getMailReceiver().receive().getMessage(); + message = applicantMail(); assertThat(message, containsString("RA-Agent Marianne Mustermann verified your name(s):")); assertThat(message, containsString("John Doe: with 10 to total 10 Verification Points." + "\n" + requiresMore(40))); @@ -91,7 +87,7 @@ public class TestVerificationMail extends BusinessTest { newAgent(); enterVerification(firstName, secondName); - message = getMailReceiver().receive().getMessage(); + message = applicantMail(); assertThat(message, containsString("RA-Agent Marianne Mustermann verified your name(s):")); assertThat(message, containsString("John Doe: with 10 to total 20 Verification Points." + "\n" + requiresMore(30))); assertThat(message, containsString("James Doe: with 10 to total 10 Verification Points." + "\n" + requiresMore(40))); @@ -100,7 +96,7 @@ public class TestVerificationMail extends BusinessTest { newAgent(); enterVerification(firstName, secondName, thirdName); - message = getMailReceiver().receive().getMessage(); + message = applicantMail(); assertThat(message, containsString("RA-Agent Marianne Mustermann verified your name(s):")); assertThat(message, containsString("John Doe: with 10 to total 30 Verification Points." + "\n" + requiresMore(20))); assertThat(message, containsString("James Doe: with 10 to total 20 Verification Points." + "\n" + requiresMore(30))); @@ -110,7 +106,7 @@ public class TestVerificationMail extends BusinessTest { newAgent(); enterVerification(firstName); - message = getMailReceiver().receive().getMessage(); + message = applicantMail(); assertThat(message, containsString("RA-Agent Marianne Mustermann verified your name(s):")); assertThat(message, containsString("John Doe: with 10 to total 40 Verification Points." + "\n" + requiresMore(10))); @@ -118,7 +114,7 @@ public class TestVerificationMail extends BusinessTest { newAgent(); enterVerification(firstName, secondName, thirdName); - message = getMailReceiver().receive().getMessage(); + message = applicantMail(); assertThat(message, containsString("RA-Agent Marianne Mustermann verified your name(s):")); assertThat(message, containsString("John Doe: with 10 to total 50 Verification Points." + "\n" + "You can now issue client certificates with this name.")); assertThat(message, containsString("James Doe: with 10 to total 30 Verification Points." + "\n" + requiresMore(20))); @@ -129,7 +125,7 @@ public class TestVerificationMail extends BusinessTest { newAgent(); enterVerification(firstName, secondName, thirdName); - message = getMailReceiver().receive().getMessage(); + message = applicantMail(); assertThat(message, containsString("RA-Agent Marianne Mustermann verified your name(s):")); assertThat(message, containsString("John Doe: with 10 to total 60 Verification Points.")); assertThat(message, containsString("James Doe: with 10 to total 40 Verification Points." + "\n" + requiresMore(10))); @@ -140,7 +136,7 @@ public class TestVerificationMail extends BusinessTest { newAgent(); enterVerification(firstName, secondName, thirdName); - message = getMailReceiver().receive().getMessage(); + message = applicantMail(); assertThat(message, containsString("RA-Agent Marianne Mustermann verified your name(s):")); assertThat(message, containsString("John Doe: with 10 to total 70 Verification Points.")); assertThat(message, containsString("James Doe: with 10 to total 50 Verification Points." + "\n" + "You can now issue client certificates with this name.")); @@ -151,7 +147,7 @@ public class TestVerificationMail extends BusinessTest { newAgent(); enterVerification(firstName, secondName, thirdName); - message = getMailReceiver().receive().getMessage(); + message = applicantMail(); assertThat(message, containsString("RA-Agent Marianne Mustermann verified your name(s):")); assertThat(message, containsString("John Doe: with 10 to total 80 Verification Points.")); assertThat(message, containsString("James Doe: with 10 to total 60 Verification Points.")); @@ -162,7 +158,7 @@ public class TestVerificationMail extends BusinessTest { newAgent(); enterVerification(firstName, secondName, thirdName); - message = getMailReceiver().receive().getMessage(); + message = applicantMail(); assertThat(message, containsString("RA-Agent Marianne Mustermann verified your name(s):")); assertThat(message, containsString("John Doe: with 10 to total 90 Verification Points.")); assertThat(message, containsString("James Doe: with 10 to total 70 Verification Points.")); @@ -173,7 +169,7 @@ public class TestVerificationMail extends BusinessTest { newAgent(); enterVerification(firstName, secondName, thirdName); - message = getMailReceiver().receive().getMessage(); + message = applicantMail(); assertThat(message, containsString("RA-Agent Marianne Mustermann verified your name(s):")); assertThat(message, containsString("John Doe: with 10 to total 100 Verification Points.")); assertThat(message, containsString("James Doe: with 10 to total 80 Verification Points.")); @@ -184,7 +180,7 @@ public class TestVerificationMail extends BusinessTest { newAgent(); enterVerification(firstName, secondName, thirdName); - message = getMailReceiver().receive().getMessage(); + message = applicantMail(); assertThat(message, containsString("RA-Agent Marianne Mustermann verified your name(s):")); assertThat(message, containsString("John Doe: with 10 to total 110 Verification Points.")); assertThat(message, containsString("James Doe: with 10 to total 90 Verification Points.")); @@ -206,24 +202,24 @@ public class TestVerificationMail extends BusinessTest { // verify preferred name only 5 times newAgent(); enterVerification(firstName); - message = getMailReceiver().receive().getMessage(); + message = applicantMail(); newAgent(); enterVerification(firstName); - message = getMailReceiver().receive().getMessage(); + message = applicantMail(); newAgent(); enterVerification(firstName); - message = getMailReceiver().receive().getMessage(); + message = applicantMail(); newAgent(); enterVerification(firstName); - message = getMailReceiver().receive().getMessage(); + message = applicantMail(); newAgent(); enterVerification(firstName); - message = getMailReceiver().receive().getMessage(); + message = applicantMail(); assertThat(message, containsString("RA-Agent Marianne Mustermann verified your name(s):")); assertThat(message, containsString("John Doe: with 10 to total 50 Verification Points." + "\n" + "You can now issue client certificates with this name.")); assertThat(message, containsString(requiresMoreTotal(50))); @@ -231,7 +227,7 @@ public class TestVerificationMail extends BusinessTest { // verify preferred name second name newAgent(); enterVerification(secondName); - message = getMailReceiver().receive().getMessage(); + message = applicantMail(); assertThat(message, containsString("RA-Agent Marianne Mustermann verified your name(s):")); assertThat(message, containsString("James Doe: with 10 to total 10 Verification Points." + "\n" + requiresMore(40))); assertThat(message, containsString(requiresMoreTotal(40))); @@ -239,19 +235,19 @@ public class TestVerificationMail extends BusinessTest { // verify preferred name second name 4 more times newAgent(); enterVerification(secondName); - message = getMailReceiver().receive().getMessage(); + message = applicantMail(); newAgent(); enterVerification(secondName); - message = getMailReceiver().receive().getMessage(); + message = applicantMail(); newAgent(); enterVerification(secondName); - message = getMailReceiver().receive().getMessage(); + message = applicantMail(); newAgent(); enterVerification(secondName); - message = getMailReceiver().receive().getMessage(); + message = applicantMail(); assertThat(message, containsString("RA-Agent Marianne Mustermann verified your name(s):")); assertThat(message, containsString("James Doe: with 10 to total 50 Verification Points." + "\n" + "You can now issue client certificates with this name.")); assertThat(message, containsString("You can now apply for RA Agent status or code signing ability.")); @@ -259,14 +255,14 @@ public class TestVerificationMail extends BusinessTest { // get more than 100 VP in total newAgent(); enterVerification(secondName); - message = getMailReceiver().receive().getMessage(); + message = applicantMail(); assertThat(message, containsString("RA-Agent Marianne Mustermann verified your name(s):")); assertThat(message, containsString("James Doe: with 10 to total 60 Verification Points.")); // verify third name newAgent(); enterVerification(thirdName); - message = getMailReceiver().receive().getMessage(); + message = applicantMail(); assertThat(message, containsString("RA-Agent Marianne Mustermann verified your name(s):")); assertThat(message, containsString("James John Doe: with 10 to total 10 Verification Points." + "\n" + requiresMore(40))); @@ -300,7 +296,7 @@ public class TestVerificationMail extends BusinessTest { // add second Verification result first name 50 VP enterVerification(15, firstName); - message = getMailReceiver().receive().getMessage(); + message = applicantMail(); assertThat(message, containsString("RA-Agent Marianne Mustermann verified your name(s):")); assertThat(message, containsString("John Doe: with 15 to total 50 Verification Points." + "\n" + "You can now issue client certificates with this name.")); assertThat(message, containsString(requiresMoreTotal(50))); @@ -326,10 +322,14 @@ public class TestVerificationMail extends BusinessTest { // add second Verification result first name 100 VP, second name 50 VP enterVerification(15, firstName, secondName); - message = getMailReceiver().receive().getMessage(); + message = applicantMail(); assertThat(message, containsString("RA-Agent Marianne Mustermann verified your name(s):")); assertThat(message, containsString("John Doe: with 15 to total 100 Verification Points.")); assertThat(message, containsString("James Doe: with 15 to total 50 Verification Points." + "\n" + "You can now issue client certificates with this name.")); assertThat(message, containsString("You can now apply for RA Agent status or code signing ability.")); } + + private String applicantMail() { + return getMailReceiver().receive(applicant.getEmail()).getMessage(); + } } diff --git a/tests/club/wpia/gigi/pages/TestVerify.java b/tests/club/wpia/gigi/pages/TestVerify.java index d1b799b5..34723f90 100644 --- a/tests/club/wpia/gigi/pages/TestVerify.java +++ b/tests/club/wpia/gigi/pages/TestVerify.java @@ -19,7 +19,7 @@ public class TestVerify extends ClientBusinessTest { @Test public void testVerify() throws GigiApiException { EmailAddress ea = new EmailAddress(u, "test@example.com", Locale.ENGLISH); - TestMail tm = getMailReceiver().receive(); + TestMail tm = getMailReceiver().receive(ea.getAddress()); Pattern p = Pattern.compile(".*hash=(.*)"); Matcher m = p.matcher(tm.extractLink()); assertTrue(m.matches()); diff --git a/tests/club/wpia/gigi/pages/account/TestCertificateAdd.java b/tests/club/wpia/gigi/pages/account/TestCertificateAdd.java index 854cca7a..8d46cf2d 100644 --- a/tests/club/wpia/gigi/pages/account/TestCertificateAdd.java +++ b/tests/club/wpia/gigi/pages/account/TestCertificateAdd.java @@ -68,6 +68,12 @@ public class TestCertificateAdd extends ClientTest { KeyPair kp = generateKeypair(); + /** + * This KeyPair is used for testing the KeyCheck for proper rejection of + * invalid keys. The generated keys suffers from small factors. + */ + KeyPair kpBroken = generateBrokenKeypair(); + String csrf; public TestCertificateAdd() throws GeneralSecurityException, IOException { @@ -383,4 +389,17 @@ public class TestCertificateAdd extends ClientTest { X509Certificate parsedLoginEnabled = createCertWithValidity("&validFrom=now&validity=1m", true); assertEquals(u, CertificateOwner.getByEnabledSerial(parsedLoginEnabled.getSerialNumber().toString(16).toLowerCase())); } + + @Test + public void testInvalidKeyInCSR() throws IOException, GeneralSecurityException { + PKCS10Attributes atts = buildAtts(new ObjectIdentifier[] { + CertificateRequest.OID_KEY_USAGE_SSL_SERVER + }, new DNSName(uniq + ".tld")); + + String pem = generatePEMCSR(kpBroken, "CN=a." + uniq + ".tld", atts); + + HttpURLConnection huc = post(CertificateAdd.PATH, "CSR=" + URLEncoder.encode(pem, "UTF-8")); + assertThat(IOUtils.readURL(huc), hasError()); + } + } diff --git a/tests/club/wpia/gigi/pages/account/TestMailManagement.java b/tests/club/wpia/gigi/pages/account/TestMailManagement.java index 84ad60de..1a42d204 100644 --- a/tests/club/wpia/gigi/pages/account/TestMailManagement.java +++ b/tests/club/wpia/gigi/pages/account/TestMailManagement.java @@ -47,6 +47,7 @@ public class TestMailManagement extends ClientTest { String newMail = createUniqueName() + "uni@example.org"; assertNull(addMail(newMail)); assertTrue(existsEmail(newMail)); + getMailReceiver().receive(newMail); } @Test @@ -62,6 +63,7 @@ public class TestMailManagement extends ClientTest { String newMail = u + "uni@eXample.org"; assertNull(addMail(newMail)); assertTrue(existsEmail(newMail.toLowerCase())); + getMailReceiver().receive(newMail.toLowerCase()); String newMail2 = u + "uni@eXamPlE.org"; assertNotNull(addMail(newMail2)); @@ -71,6 +73,7 @@ public class TestMailManagement extends ClientTest { assertNull(addMail(newMail3)); assertTrue(existsEmail(newMail.toLowerCase())); assertTrue(existsEmail(newMail3.toLowerCase())); + getMailReceiver().receive(newMail3.toLowerCase()); } private String addMail(String newMail) throws IOException, MalformedURLException, UnsupportedEncodingException { @@ -100,7 +103,7 @@ public class TestMailManagement extends ClientTest { EmailAddress addr = new EmailAddress(u, createUniqueName() + "test@test.tld", Locale.ENGLISH); assertNotNull(executeBasicWebInteraction(cookie, path, "default=" + addr.getId())); assertNotEquals(User.getById(u.getId()).getEmail(), addr.getAddress()); - getMailReceiver().clearMails(); + getMailReceiver().receive(addr.getAddress()); } @Test @@ -116,7 +119,7 @@ public class TestMailManagement extends ClientTest { assertNotEquals(id, -1); assertNotNull(executeBasicWebInteraction(cookie, path, "default=" + id)); assertNotEquals(User.getById(u.getId()).getEmail(), u2.getEmail()); - getMailReceiver().clearMails(); + getMailReceiver().assertEmpty(); } @Test diff --git a/tests/club/wpia/gigi/pages/account/TestPasswordResetExternal.java b/tests/club/wpia/gigi/pages/account/TestPasswordResetExternal.java index 35c482d8..1efc5f73 100644 --- a/tests/club/wpia/gigi/pages/account/TestPasswordResetExternal.java +++ b/tests/club/wpia/gigi/pages/account/TestPasswordResetExternal.java @@ -35,10 +35,9 @@ public class TestPasswordResetExternal extends ClientTest { String error = fetchStartErrorMessage(IOUtils.readURL(uc)); assertNull(error); - TestMail mail = getMailReceiver().receive(); + TestMail mail = getMailReceiver().receive(this.u.getEmail()); assertThat(mail.getSubject(), containsString("Verification")); - mail = getMailReceiver().receive(); - assertEquals(mail.getTo(), this.u.getEmail()); + mail = getMailReceiver().receive(this.u.getEmail()); String link = mail.extractLink(); String npw = TEST_PASSWORD + "'"; System.out.println(link); diff --git a/tests/club/wpia/gigi/pages/admin/TestSEAdminNotificationMail.java b/tests/club/wpia/gigi/pages/admin/TestSEAdminNotificationMail.java index 8a439a31..9bcaa825 100644 --- a/tests/club/wpia/gigi/pages/admin/TestSEAdminNotificationMail.java +++ b/tests/club/wpia/gigi/pages/admin/TestSEAdminNotificationMail.java @@ -27,15 +27,17 @@ public class TestSEAdminNotificationMail extends ClientTest { private int targetID; + private String targetEmail; + public TestSEAdminNotificationMail() throws IOException, GigiApiException { grant(u, Group.SUPPORTER); cookie = login(email, TEST_PASSWORD); assertEquals(302, post(cookie, SupportEnterTicketPage.PATH, "ticketno=a20140808.8&setTicket=action", 0).getResponseCode()); - String email = createUniqueName() + "@example.com"; + targetEmail = createUniqueName() + "@example.com"; String fname = "Först"; String lname = "Secönd"; - targetID = createVerifiedUser(fname, lname, email, TEST_PASSWORD); + targetID = createVerifiedUser(fname, lname, targetEmail, TEST_PASSWORD); } @Test @@ -44,22 +46,19 @@ public class TestSEAdminNotificationMail extends ClientTest { executeBasicWebInteraction(cookie, SupportUserDetailsPage.PATH + targetID + "/", "dobd=1&dobm=2&doby=2000&detailupdate", 0); // mail to support - String message = getMailReceiver().receive().getMessage(); + String message = getMailReceiver().receive(ServerConstants.getSupportMailAddress()).getMessage(); assertThat(message, containsString("The DoB was changed")); assertThat(message, containsString("supporter " + u.getPreferredName().toString() + " triggered:")); // mail to user - message = getMailReceiver().receive().getMessage(); + message = getMailReceiver().receive(targetEmail).getMessage(); assertThat(message, containsString("The DoB in your account was changed to 2000-02-01.")); } @Test public void testPasswordReset() throws MalformedURLException, IOException { executeBasicWebInteraction(cookie, SupportUserDetailsPage.PATH + targetID + "/", "aword=SecretWord&resetPass", 0); - TestMail tm; - String targetMail = ServerConstants.getSupportMailAddress(); - do { - tm = getMailReceiver().receive(); - } while ( !tm.getTo().equals(targetMail)); + getMailReceiver().receive(targetEmail); + TestMail tm = getMailReceiver().receive(ServerConstants.getSupportMailAddress()); assertThat(tm.getMessage(), containsString("A password reset was triggered and an email was sent to user.")); } @@ -72,10 +71,10 @@ public class TestSEAdminNotificationMail extends ClientTest { Group.CODESIGNING.getName().output(pw, Language.getInstance(Locale.ENGLISH), new HashMap()); // mail to support - String message = getMailReceiver().receive().getMessage(); + String message = getMailReceiver().receive(ServerConstants.getSupportMailAddress()).getMessage(); assertThat(message, containsString("The group permission '" + sw.toString() + "' was granted.")); // mail to user - message = getMailReceiver().receive().getMessage(); + message = getMailReceiver().receive(targetEmail).getMessage(); assertThat(message, containsString("The group permission '" + sw.toString() + "' was granted to your account.")); } @@ -88,10 +87,10 @@ public class TestSEAdminNotificationMail extends ClientTest { Group.CODESIGNING.getName().output(pw, Language.getInstance(Locale.ENGLISH), new HashMap()); // mail to support - String message = getMailReceiver().receive().getMessage(); + String message = getMailReceiver().receive(ServerConstants.getSupportMailAddress()).getMessage(); assertThat(message, containsString("The group permission '" + sw.toString() + "' was revoked.")); // mail to user - message = getMailReceiver().receive().getMessage(); + message = getMailReceiver().receive(targetEmail).getMessage(); assertThat(message, containsString("The group permission '" + sw.toString() + "' was revoked from your account.")); } @@ -105,13 +104,13 @@ public class TestSEAdminNotificationMail extends ClientTest { User target = User.getById(targetID); // mail to support - String message = getMailReceiver().receive().getMessage(); + String message = getMailReceiver().receive(ServerConstants.getSupportMailAddress()).getMessage(); assertThat(message, containsString("The group permission '" + sw.toString() + "' was granted.")); // mail to user - message = getMailReceiver().receive().getMessage(); + message = getMailReceiver().receive(targetEmail).getMessage(); assertThat(message, containsString("The group permission '" + sw.toString() + "' was granted to your account.")); // mail to board - message = getMailReceiver().receive().getMessage(); + message = getMailReceiver().receive(ServerConstants.getBoardMailAddress()).getMessage(); assertThat(message, containsString("The group permission '" + sw.toString() + "' was granted for '" + target.getPreferredName().toString() + "'.")); } @@ -125,13 +124,13 @@ public class TestSEAdminNotificationMail extends ClientTest { User target = User.getById(targetID); // mail to support - String message = getMailReceiver().receive().getMessage(); + String message = getMailReceiver().receive(ServerConstants.getSupportMailAddress()).getMessage(); assertThat(message, containsString("The group permission '" + sw.toString() + "' was revoked.")); // mail to user - message = getMailReceiver().receive().getMessage(); + message = getMailReceiver().receive(targetEmail).getMessage(); assertThat(message, containsString("The group permission '" + sw.toString() + "' was revoked from your account.")); // mail to board - message = getMailReceiver().receive().getMessage(); + message = getMailReceiver().receive(ServerConstants.getBoardMailAddress()).getMessage(); assertThat(message, containsString("The group permission '" + sw.toString() + "' was revoked for '" + target.getPreferredName().toString() + "'.")); } @@ -141,10 +140,10 @@ public class TestSEAdminNotificationMail extends ClientTest { User user = User.getById(targetID); // mail to support - String message = getMailReceiver().receive().getMessage(); + String message = getMailReceiver().receive(ServerConstants.getSupportMailAddress()).getMessage(); assertThat(message, containsString("All certificates in the account " + user.getPreferredName().toString())); // mail to user - message = getMailReceiver().receive().getMessage(); + message = getMailReceiver().receive(targetEmail).getMessage(); assertThat(message, containsString("All certificates in your account have been revoked.")); } } diff --git a/tests/club/wpia/gigi/pages/admin/TestSEAdminPageCertSearch.java b/tests/club/wpia/gigi/pages/admin/TestSEAdminPageCertSearch.java index dd7d1970..e61f559e 100644 --- a/tests/club/wpia/gigi/pages/admin/TestSEAdminPageCertSearch.java +++ b/tests/club/wpia/gigi/pages/admin/TestSEAdminPageCertSearch.java @@ -39,7 +39,7 @@ public class TestSEAdminPageCertSearch extends ClientTest { cookie = login(email, TEST_PASSWORD); assertEquals(302, post(cookie, SupportEnterTicketPage.PATH, "ticketno=a20140808.8&setTicket=action", 0).getResponseCode()); - certMail = uniq + "_certOwner@example.com"; + certMail = uniq + "_certowner@example.com"; int id = createVerifiedUser("fn", "ln", certMail, TEST_PASSWORD); User u1 = User.getById(id); KeyPair kp = generateKeypair(); @@ -73,22 +73,11 @@ public class TestSEAdminPageCertSearch extends ClientTest { public void testRevoke() throws IOException { URLConnection conn = post(Certificates.SUPPORT_PATH + "/" + c.getSerial(), "action=revoke"); assertEquals("https://" + ServerConstants.getHostNamePortSecure(Host.WWW) + Certificates.SUPPORT_PATH + "/" + c.getSerial(), conn.getHeaderField("Location")); - boolean hadSupport = false; - boolean hadUser = false; for (int i = 0; i < 2; i++) { - TestMail tm = getMailReceiver().receive(); - if (tm.getTo().equals(ServerConstants.getSupportMailAddress())) { - hadSupport = true; - } else if (tm.getTo().equals(certMail)) { - hadUser = true; - } else { - throw new Error("Unknown mail:" + tm.getTo()); - } + TestMail tm = getMailReceiver().receive(i == 0 ? ServerConstants.getSupportMailAddress() : certMail); assertThat(tm.getMessage(), CoreMatchers.containsString(certMail)); assertThat(tm.getMessage(), CoreMatchers.containsString(c.getSerial())); } - assertTrue(hadSupport); - assertTrue(hadUser); assertEquals(CertificateStatus.REVOKED, c.getStatus()); } diff --git a/tests/club/wpia/gigi/pages/admin/TestSEAdminPageDetails.java b/tests/club/wpia/gigi/pages/admin/TestSEAdminPageDetails.java index 909dd038..72930b30 100644 --- a/tests/club/wpia/gigi/pages/admin/TestSEAdminPageDetails.java +++ b/tests/club/wpia/gigi/pages/admin/TestSEAdminPageDetails.java @@ -56,7 +56,7 @@ public class TestSEAdminPageDetails extends ClientTest { int id = createVerifiedUser(fname, lname, email, TEST_PASSWORD); String email2 = createUniqueName() + "@example.com"; EmailAddress ea = new EmailAddress(User.getById(id), email2, Locale.ENGLISH); - getMailReceiver().receive().verify(); + getMailReceiver().receive(email2).verify(); // Refresh email Object ObjectCache.clearAllCaches(); ea = EmailAddress.getById(ea.getId()); @@ -108,6 +108,10 @@ public class TestSEAdminPageDetails extends ClientTest { assertEquals(3, logCountAdmin(id)); assertEquals(3, logCountUser(clientCookie)); + // discarding all 6 mails + for (int i = 0; i < 6; i++) { + getMailReceiver().receive(null); + } } @Test diff --git a/tests/club/wpia/gigi/pages/main/KeyCompromiseTest.java b/tests/club/wpia/gigi/pages/main/KeyCompromiseTest.java index af9cbb64..46ffe0dd 100644 --- a/tests/club/wpia/gigi/pages/main/KeyCompromiseTest.java +++ b/tests/club/wpia/gigi/pages/main/KeyCompromiseTest.java @@ -187,6 +187,7 @@ public class KeyCompromiseTest extends ClientTest { if (error == null) { assertThat(result, hasNoError()); assertRevoked(result); + getMailReceiver().receive(u.getEmail()); } else if ("error".equals(error)) { assertThat(result, hasError()); assertNotEquals(CertificateStatus.REVOKED, cert.getStatus()); diff --git a/tests/club/wpia/gigi/pages/main/KeyCompromiseTestMessage.java b/tests/club/wpia/gigi/pages/main/KeyCompromiseTestMessage.java index 06a5ba51..7dfb4155 100644 --- a/tests/club/wpia/gigi/pages/main/KeyCompromiseTestMessage.java +++ b/tests/club/wpia/gigi/pages/main/KeyCompromiseTestMessage.java @@ -92,7 +92,7 @@ public class KeyCompromiseTestMessage extends ClientTest { String data = IOUtils.readURL(rc); assertThat(data, hasError()); assertThat(data, CoreMatchers.containsString(HTMLEncoder.encodeHTML("message may not contain '---'"))); - assertNull(getMailReceiver().poll()); + assertNull(getMailReceiver().poll(null)); assertEquals(CertificateStatus.ISSUED, cert.getStatus()); } @@ -108,7 +108,7 @@ public class KeyCompromiseTestMessage extends ClientTest { private TestMail reportCompromiseAndCheck(String params) throws IOException, UnsupportedEncodingException, CertificateEncodingException, GeneralSecurityException { HttpURLConnection huc = reportCompromise(params); assertThat(IOUtils.readURL(huc), hasNoError()); - TestMail rc = getMailReceiver().receive(); + TestMail rc = getMailReceiver().receive(email); assertEquals(u.getEmail(), rc.getTo()); assertThat(rc.getMessage(), CoreMatchers.containsString(cert.getSerial())); assertEquals(CertificateStatus.REVOKED, cert.getStatus()); diff --git a/tests/club/wpia/gigi/pages/main/RegisterPageTest.java b/tests/club/wpia/gigi/pages/main/RegisterPageTest.java index aee9ad5b..d9de3a91 100644 --- a/tests/club/wpia/gigi/pages/main/RegisterPageTest.java +++ b/tests/club/wpia/gigi/pages/main/RegisterPageTest.java @@ -45,14 +45,14 @@ public class RegisterPageTest extends ManagedTest { public void testSuccess() throws IOException, InterruptedException { long uniq = System.currentTimeMillis(); registerUser("ab", "b", "correct" + uniq + "@email.de", TEST_PASSWORD); - assertSuccessfullRegMail(); + assertSuccessfullRegMail("correct" + uniq + "@email.de"); String defaultSignup = "fname=" + URLEncoder.encode("ab", "UTF-8") + "&lname=" + URLEncoder.encode("b", "UTF-8") + "&pword1=" + URLEncoder.encode(TEST_PASSWORD, "UTF-8") + "&pword2=" + URLEncoder.encode(TEST_PASSWORD, "UTF-8") + "&day=1&month=1&year=1910&tos_agree=1&mname=mn&suffix=sf&email="; String query = defaultSignup + URLEncoder.encode("correct3_" + uniq + "@email.de", "UTF-8") + "&general=1&country=1®ional=1&radius=1&name-type=western"; String data = fetchStartErrorMessage(runRegister(query)); assertNull(data); - assertSuccessfullRegMail(); + assertSuccessfullRegMail("correct3_" + uniq + "@email.de"); getMailReceiver().setEmailCheckError("400 Greylisted"); getMailReceiver().setApproveRegex(Pattern.compile("a")); @@ -60,12 +60,12 @@ public class RegisterPageTest extends ManagedTest { data = fetchStartErrorMessage(runRegister(query)); assertNotNull(data); - assertNull(getMailReceiver().poll()); + assertNull(getMailReceiver().poll(null)); } - private void assertSuccessfullRegMail() { - String link = getMailReceiver().receive().extractLink(); + private void assertSuccessfullRegMail(String mail) { + String link = getMailReceiver().receive(mail).extractLink(); assertTrue(link, link.startsWith("https://")); } @@ -188,6 +188,7 @@ public class RegisterPageTest extends ManagedTest { public void testDoubleMail() throws IOException { long uniq = System.currentTimeMillis(); registerUser("RegisterTest", "User", "testmail" + uniq + "@example.com", TEST_PASSWORD); + getMailReceiver().receive("testmail" + uniq + "@example.com"); try { registerUser("RegisterTest", "User", "testmail" + uniq + "@example.com", TEST_PASSWORD); throw new Error("Registering a user with the same email needs to fail."); @@ -225,6 +226,7 @@ public class RegisterPageTest extends ManagedTest { assertNull(data); User u = User.getByEmail(email); assertEquals("DE", u.getResidenceCountry().getCode()); + getMailReceiver().receive(email); } @Test @@ -239,5 +241,6 @@ public class RegisterPageTest extends ManagedTest { assertNull(data); User u = User.getByEmail(email); assertEquals(null, u.getResidenceCountry()); + getMailReceiver().receive(email); } } diff --git a/tests/club/wpia/gigi/pages/wot/TestVerification.java b/tests/club/wpia/gigi/pages/wot/TestVerification.java index 7a6aed4e..5b61f231 100644 --- a/tests/club/wpia/gigi/pages/wot/TestVerification.java +++ b/tests/club/wpia/gigi/pages/wot/TestVerification.java @@ -101,6 +101,7 @@ public class TestVerification extends ManagedTest { String body = executeSuccess("date=" + validVerificationDateString() + "&location=testcase&countryCode=DE&certify=1&rules=1&assertion=1&points=10"); assertThat(body, containsString("10")); assertThat(body, containsString(applicantM)); + getMailReceiver().receive(applicantM); } @Test @@ -129,6 +130,7 @@ public class TestVerification extends ManagedTest { uc.getOutputStream().write(("date=" + validVerificationDateString() + "&location=testcase&countryCode=DE&certify=1&rules=1&assertion=1&points=10").getBytes("UTF-8")); uc.getOutputStream().flush(); assertEquals(500, uc.getResponseCode()); + uc.getErrorStream().close(); } @Test @@ -138,6 +140,7 @@ public class TestVerification extends ManagedTest { uc.getOutputStream().write(("date=" + validVerificationDateString() + "&location=testcase&countryCode=DE&certify=1&rules=1&assertion=1&points=10&csrf=aragc").getBytes("UTF-8")); uc.getOutputStream().flush(); assertEquals(500, uc.getResponseCode()); + uc.getErrorStream().close(); } @Test @@ -163,6 +166,7 @@ public class TestVerification extends ManagedTest { String error = fetchStartErrorMessage(IOUtils.readURL(uc)); if (succeed) { assertNull(error); + getMailReceiver().receive(applicantM); } else { assertTrue(error, !error.startsWith("")); assertThat(error, containsString("changed his personal details")); @@ -184,11 +188,13 @@ public class TestVerification extends ManagedTest { c.add(Calendar.HOUR_OF_DAY, 12); executeSuccess("date=" + sdf.format(new Date(c.getTimeInMillis())) + "&location=testcase&countryCode=DE&certify=1&rules=1&assertion=1&points=10"); + getMailReceiver().receive(applicantM); } @Test public void testVerifyFormPastInRange() throws IOException { executeSuccess("date=" + validVerificationDateString() + "&location=testcase&countryCode=DE&certify=1&rules=1&assertion=1&points=10"); + getMailReceiver().receive(applicantM); } @Test @@ -200,6 +206,7 @@ public class TestVerification extends ManagedTest { c.add(Calendar.DAY_OF_MONTH, 1); executeSuccess("date=" + sdf.format(new Date(c.getTimeInMillis())) + "&location=testcase&countryCode=DE&certify=1&rules=1&assertion=1&points=10"); + getMailReceiver().receive(applicantM); } @Test @@ -234,7 +241,8 @@ public class TestVerification extends ManagedTest { @Test public void testVerifyListingValid() throws IOException, GigiApiException { String uniqueLoc = createUniqueName(); - execute("date=" + validVerificationDateString() + "&location=" + uniqueLoc + "&countryCode=DE&certify=1&rules=1&assertion=1&points=10"); + executeSuccess("date=" + validVerificationDateString() + "&location=" + uniqueLoc + "&countryCode=DE&certify=1&rules=1&assertion=1&points=10"); + getMailReceiver().receive(applicantM); String cookie = login(applicantM, TEST_PASSWORD); URLConnection url = get(cookie, Points.PATH); @@ -248,6 +256,8 @@ public class TestVerification extends ManagedTest { public void testAgentListingValid() throws IOException, GigiApiException { String uniqueLoc = createUniqueName(); executeSuccess("date=" + validVerificationDateString() + "&location=" + uniqueLoc + "&countryCode=DE&certify=1&rules=1&assertion=1&points=10"); + getMailReceiver().receive(applicantM); + String cookie = login(agentM, TEST_PASSWORD); URLConnection url = get(cookie, Points.PATH); String resp = IOUtils.readURL(url); @@ -315,6 +325,7 @@ public class TestVerification extends ManagedTest { // enter second entry String uniqueLoc = createUniqueName(); executeSuccess("date=" + validVerificationDateString() + "&location=" + uniqueLoc + "&countryCode=DE&certify=1&rules=1&assertion=1&points=10"); + getMailReceiver().receive(applicantM); // enter third entry on the same day URLConnection uc = get(cookie, VerifyPage.PATH); @@ -331,7 +342,7 @@ public class TestVerification extends ManagedTest { @Test public void testRANotificationSet() throws IOException, GigiApiException { - getMailReceiver().clearMails(); + getMailReceiver().assertEmpty(); User users[] = User.findByEmail(agentM); assertTrue("user RA Agent not found", users != null && users.length > 0); @@ -346,18 +357,15 @@ public class TestVerification extends ManagedTest { // enter verification String uniqueLoc = createUniqueName(); executeSuccess("date=" + validVerificationDateString() + "&location=" + uniqueLoc + "&countryCode=DE&certify=1&rules=1&assertion=1&points=10"); - TestMail tm; - - do { - tm = getMailReceiver().receive(); - } while ( !tm.getTo().equals(targetMail)); + getMailReceiver().receive(applicantM); + TestMail tm = getMailReceiver().receive(targetMail); assertThat(tm.getMessage(), containsString("You entered a verification for the account with email address " + applicantM)); } @Test public void testRANotificationNotSet() throws IOException, GigiApiException { - getMailReceiver().clearMails(); + getMailReceiver().assertEmpty(); User users[] = User.findByEmail(agentM); assertTrue("user RA Agent not found", users != null && users.length > 0); @@ -373,7 +381,7 @@ public class TestVerification extends ManagedTest { TestMail tm; - tm = getMailReceiver().receive(); + tm = getMailReceiver().receive(applicantM); assertThat(tm.getMessage(), not(containsString("You entered a verification for the account with email address " + applicantM))); } diff --git a/tests/club/wpia/gigi/ping/TestDNS.java b/tests/club/wpia/gigi/ping/TestDNS.java index 4285e8bd..f970cb25 100644 --- a/tests/club/wpia/gigi/ping/TestDNS.java +++ b/tests/club/wpia/gigi/ping/TestDNS.java @@ -75,7 +75,7 @@ public class TestDNS extends PingTest { "&adddomain&csrf=" + csrf; String p2 = sendDomainForm(content); - TestMail mail = getMailReceiver().receive(); + TestMail mail = getMailReceiver().receive("postmaster@" + test); if (emailVariant == 0) { mail.verify(); } diff --git a/tests/club/wpia/gigi/ping/TestHTTP.java b/tests/club/wpia/gigi/ping/TestHTTP.java index 8dc041f6..ae29f974 100644 --- a/tests/club/wpia/gigi/ping/TestHTTP.java +++ b/tests/club/wpia/gigi/ping/TestHTTP.java @@ -76,7 +76,7 @@ public class TestHTTP extends PingTest { "&adddomain&csrf=" + csrf; String p2 = sendDomainForm(content); - TestMail mail = getMailReceiver().receive(); + TestMail mail = getMailReceiver().receive("postmaster@" + test); if (emailVariant == 0) { mail.verify(); } @@ -175,7 +175,7 @@ public class TestHTTP extends PingTest { } waitForPings(2); - TestMail mail = getMailReceiver().receive(); + TestMail mail = getMailReceiver().receive("postmaster@" + test); mail.verify(); String newcontent = IOUtils.readURL(get(p2)); diff --git a/tests/club/wpia/gigi/ping/TestSSL.java b/tests/club/wpia/gigi/ping/TestSSL.java index 9b93c77d..e4c5de01 100644 --- a/tests/club/wpia/gigi/ping/TestSSL.java +++ b/tests/club/wpia/gigi/ping/TestSSL.java @@ -45,11 +45,11 @@ import club.wpia.gigi.GigiApiException; import club.wpia.gigi.database.DatabaseConnection; import club.wpia.gigi.database.DatabaseConnection.Link; import club.wpia.gigi.dbObjects.Certificate; +import club.wpia.gigi.dbObjects.Certificate.CSRType; import club.wpia.gigi.dbObjects.CertificateProfile; import club.wpia.gigi.dbObjects.Digest; import club.wpia.gigi.dbObjects.Job; import club.wpia.gigi.dbObjects.User; -import club.wpia.gigi.dbObjects.Certificate.CSRType; import club.wpia.gigi.testUtils.IOUtils; import club.wpia.gigi.testUtils.PingTest; import club.wpia.gigi.testUtils.TestEmailReceiver.TestMail; @@ -206,7 +206,7 @@ public class TestSSL extends PingTest { boolean secondsSucceeds = sslVariant != 0; // assertTrue(secondsSucceeds ^ accept2); - TestMail mail = getMailReceiver().receive(); + TestMail mail = getMailReceiver().receive("postmaster@" + test); if (emailVariant == 0) { mail.verify(); } diff --git a/tests/club/wpia/gigi/template/TestTemplateMail.java b/tests/club/wpia/gigi/template/TestTemplateMail.java index c6607140..940c157b 100644 --- a/tests/club/wpia/gigi/template/TestTemplateMail.java +++ b/tests/club/wpia/gigi/template/TestTemplateMail.java @@ -30,7 +30,7 @@ public class TestTemplateMail extends BusinessTest { public void testSimple() throws IOException { vars.put("var", "val"); testExecuteMail(vars, "Subject: subj\n\nl"); - TestMail tm = getMailReceiver().receive(); + TestMail tm = getMailReceiver().receive(TEST_MAIL); assertEquals(MailTemplate.SUBJECT_TAG + "subj", tm.getSubject()); assertThat(tm.getMessage(), startsWith("vall")); } @@ -40,7 +40,7 @@ public class TestTemplateMail extends BusinessTest { vars.put("var", "val\">"); vars.put("var2", "sl\">"); testExecuteMail(vars, "Subject: ab\n\nl"); - TestMail tm = getMailReceiver().receive(); + TestMail tm = getMailReceiver().receive(TEST_MAIL); assertEquals(MailTemplate.SUBJECT_TAG + "aval\">b", tm.getSubject()); assertThat(tm.getMessage(), startsWith("sl\">l")); @@ -49,7 +49,7 @@ public class TestTemplateMail extends BusinessTest { @Test public void testTranslate() throws IOException { testExecuteMail(vars, "Subject: ab\n\ncl"); - TestMail tm = getMailReceiver().receive(); + TestMail tm = getMailReceiver().receive(TEST_MAIL); assertEquals(MailTemplate.SUBJECT_TAG + "aa> 1; + int lr = BigInteger.valueOf(r_lv).bitLength(); + int lq = keySize - lp - lr; + + BigInteger e = BigInteger.valueOf(7331); + + keyPair = null; + while (keyPair == null) { + // generate two random primes of size lp/lq + BigInteger p, q, r, n; + + p = BigInteger.probablePrime(lp, random); + r = BigInteger.valueOf(r_lv); + do { + q = BigInteger.probablePrime(lq, random); + + // convention is for p > q > r + if (p.compareTo(q) < 0) { + BigInteger tmp = p; + p = q; + q = tmp; + } + + // modulus n = p * q * r + n = p.multiply(q).multiply(r); + + // even with correctly sized p, q and r, there is a chance + // that n will be one bit short. re-generate the smaller + // prime if so. + } while (n.bitLength() < keySize); + + // phi = (p - 1) * (q - 1) * (r - 1) must be relative prime to e + // otherwise RSA just won't work ;-) + BigInteger p1 = p.subtract(BigInteger.ONE); + BigInteger q1 = q.subtract(BigInteger.ONE); + BigInteger r1 = r.subtract(BigInteger.ONE); + BigInteger phi = p1.multiply(q1).multiply(r1); + + // generate new p and q until they work. typically + if (e.gcd(phi).equals(BigInteger.ONE) == false) { + continue; + } + + // private exponent d is the inverse of e mod phi + BigInteger d = e.modInverse(phi); + + RSAPublicKeySpec publicSpec = new RSAPublicKeySpec(n, e); + RSAPrivateKeySpec privateSpec = new RSAPrivateKeySpec(n, d); + PublicKey publicKey = factory.generatePublic(publicSpec); + PrivateKey privateKey = factory.generatePrivate(privateSpec); + keyPair = new KeyPair(publicKey, privateKey); + } + // -----END SHAMELESSLY ADAPTED BLOCK----- + + try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f))) { + oos.writeObject(keyPair); + oos.close(); + } catch (IOException ioe) { + ioe.printStackTrace(); + } + } + return keyPair; + } + public static String generatePEMCSR(KeyPair kp, String dn) throws GeneralSecurityException, IOException { return generatePEMCSR(kp, dn, new PKCS10Attributes()); } @@ -249,7 +346,7 @@ public abstract class ConfiguredTest { public void verify(Domain d) { try { d.addPing(DomainPingType.EMAIL, "admin"); - TestMail testMail = getMailReceiver().receive(); + TestMail testMail = getMailReceiver().receive("admin@" + d.getSuffix()); testMail.verify(); assertTrue(d.isVerified()); } catch (GigiApiException e) { diff --git a/tests/club/wpia/gigi/testUtils/MailReceiver.java b/tests/club/wpia/gigi/testUtils/MailReceiver.java index 4d1bc104..139c5547 100644 --- a/tests/club/wpia/gigi/testUtils/MailReceiver.java +++ b/tests/club/wpia/gigi/testUtils/MailReceiver.java @@ -6,14 +6,14 @@ import club.wpia.gigi.testUtils.TestEmailReceiver.TestMail; public interface MailReceiver { - void clearMails(); + void assertEmpty(); - TestMail receive(); + TestMail receive(String to); void setApproveRegex(Pattern compiled); void setEmailCheckError(String string); - TestMail poll(); + TestMail poll(String to); } diff --git a/tests/club/wpia/gigi/testUtils/ManagedTest.java b/tests/club/wpia/gigi/testUtils/ManagedTest.java index 3eeda2ca..a2eb449f 100644 --- a/tests/club/wpia/gigi/testUtils/ManagedTest.java +++ b/tests/club/wpia/gigi/testUtils/ManagedTest.java @@ -291,7 +291,7 @@ public class ManagedTest extends ConfiguredTest { public static int createVerifiedUser(String firstName, String lastName, String email, String password) { registerUser(firstName, lastName, email, password); try { - ter.receive().verify(); + ter.receive(email).verify(); try (GigiPreparedStatement ps = new GigiPreparedStatement("SELECT `id` FROM `users` WHERE `email`=?")) { ps.setString(1, email); @@ -496,11 +496,10 @@ public class ManagedTest extends ConfiguredTest { public EmailAddress createVerifiedEmail(User u, String email) throws InterruptedException, GigiApiException { EmailAddress addr = new EmailAddress(u, email, Locale.ENGLISH); - TestMail testMail = getMailReceiver().receive(); - assertEquals(addr.getAddress(), testMail.getTo()); + TestMail testMail = getMailReceiver().receive(addr.getAddress()); String hash = testMail.extractLink().substring(testMail.extractLink().lastIndexOf('=') + 1); addr.verify(hash); - getMailReceiver().clearMails(); + getMailReceiver().assertEmpty(); return addr; } diff --git a/tests/club/wpia/gigi/testUtils/TestEmailReceiver.java b/tests/club/wpia/gigi/testUtils/TestEmailReceiver.java index 01dbe78e..9bba9b31 100644 --- a/tests/club/wpia/gigi/testUtils/TestEmailReceiver.java +++ b/tests/club/wpia/gigi/testUtils/TestEmailReceiver.java @@ -1,5 +1,7 @@ package club.wpia.gigi.testUtils; +import static org.junit.Assert.*; + import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; @@ -83,6 +85,10 @@ public final class TestEmailReceiver extends EmailProvider implements Runnable, uc.getInputStream().close(); } + @Override + public String toString() { + return "TestMail: " + subject + " for " + to; + } } private Socket s; @@ -130,7 +136,7 @@ public final class TestEmailReceiver extends EmailProvider implements Runnable, * @see #poll() */ @Override - public TestMail receive() { + public TestMail receive(String to) { TestMail poll; try { @@ -142,6 +148,9 @@ public final class TestEmailReceiver extends EmailProvider implements Runnable, if (poll == null) { throw new AssertionError("Mail receiving timed out"); } + if (to != null) { + assertEquals(to, poll.getTo()); + } return poll; } @@ -154,8 +163,12 @@ public final class TestEmailReceiver extends EmailProvider implements Runnable, * has been sent. * @see #receive() */ - public TestMail poll() { - return mails.poll(); + public TestMail poll(String to) { + TestMail tm = mails.poll(); + if (tm != null && to != null) { + assertEquals(to, tm.getTo()); + } + return tm; } @Override @@ -226,19 +239,21 @@ public final class TestEmailReceiver extends EmailProvider implements Runnable, * Removes all queued mails. */ @Override - public void clearMails() { + public void assertEmpty() { + int originalSize = mails.size(); mails.clear(); + assertEquals("test case should consume all produced emails", 0, originalSize); } /** * Resets this class to its initial state * - * @see #clearMails() + * @see #assertEmpty() * @see #setApproveRegex(Pattern) * @see #setEmailCheckError(String) */ public void reset() { - clearMails(); + assertEmpty(); error = "FAIL"; approveRegex = Pattern.compile(".*"); }