import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
+import java.math.BigInteger;
import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
import java.security.Signature;
+import java.security.spec.RSAPrivateKeySpec;
+import java.security.spec.RSAPublicKeySpec;
import java.sql.SQLException;
+import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import org.junit.AfterClass;
import org.junit.BeforeClass;
+import club.wpia.gigi.Gigi;
import club.wpia.gigi.GigiApiException;
import club.wpia.gigi.database.DatabaseConnection;
import club.wpia.gigi.database.DatabaseConnection.Link;
import club.wpia.gigi.database.GigiPreparedStatement;
import club.wpia.gigi.database.SQLFileManager.ImportType;
+import club.wpia.gigi.dbObjects.CATS;
import club.wpia.gigi.dbObjects.CATS.CATSType;
import club.wpia.gigi.dbObjects.CertificateProfile;
+import club.wpia.gigi.dbObjects.Contract;
+import club.wpia.gigi.dbObjects.Contract.ContractType;
import club.wpia.gigi.dbObjects.Domain;
import club.wpia.gigi.dbObjects.DomainPingType;
import club.wpia.gigi.dbObjects.User;
+import club.wpia.gigi.passwords.PasswordStrengthChecker;
import club.wpia.gigi.testUtils.TestEmailReceiver.TestMail;
import club.wpia.gigi.util.DatabaseManager;
import club.wpia.gigi.util.DomainAssessment;
import club.wpia.gigi.util.Notary;
import club.wpia.gigi.util.PEM;
import club.wpia.gigi.util.PasswordHash;
+import club.wpia.gigi.util.RandomToken;
import club.wpia.gigi.util.ServerConstants;
import club.wpia.gigi.util.TimeConditions;
import sun.security.pkcs10.PKCS10;
public static Properties initEnvironment() throws IOException {
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
if (envInited) {
+ try {
+ synchronized (ConfiguredTest.class) {
+ if (l == null) {
+ l = DatabaseConnection.newLink(false);
+ }
+ }
+ } catch (InterruptedException e) {
+ throw new Error(e);
+ }
return generateProps();
}
envInited = true;
TimeConditions.init(props);
DomainAssessment.init(props);
PasswordHash.init(props);
+ Gigi.setPasswordChecker(new PasswordStrengthChecker());
if ( !DatabaseConnection.isInited()) {
DatabaseConnection.init(testProps);
try {
synchronized (ConfiguredTest.class) {
- l = DatabaseConnection.newLink(false);
+ if (l == null) {
+ l = DatabaseConnection.newLink(false);
+ }
}
} catch (InterruptedException e) {
throw new Error(e);
mainProps.setProperty("name.www", testProps.getProperty("name.www"));
mainProps.setProperty("name.static", testProps.getProperty("name.static"));
mainProps.setProperty("name.api", testProps.getProperty("name.api"));
+ mainProps.setProperty("name.suffix", testProps.getProperty("name.suffix"));
mainProps.setProperty("appName", "SomeCA");
mainProps.setProperty("appIdentifier", "someca");
return keyPair;
}
+ public static KeyPair generateBrokenKeypair() throws GeneralSecurityException {
+ KeyPair keyPair = null;
+ File f = new File("testBrokenKeypair");
+ if (f.exists()) {
+ try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f))) {
+ keyPair = (KeyPair) ois.readObject();
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ } else {
+ // -----BEGIN SHAMELESSLY ADAPTED BLOCK-----
+ /**
+ * Modified original RSA key generator to use three primes with one
+ * prime set to fixed value to allow simple checking for such faulty
+ * keys.
+ *
+ * @link sun.security.rsa.RSAKeyPairGenerator#generateKeyPair
+ */
+
+ KeyFactory factory = KeyFactory.getInstance("RSA");
+ Random random = new SecureRandom();
+ int keySize = 4096;
+ long r_lv = 7331;
+
+ // The generated numbers p q and r fall into the
+ // following ranges:
+ // - p: 2^(lp-1) < p < 2^lp
+ // - q: 2^(lq-1) < q < 2^lq
+ // - r: 2^12 < r < 2^13
+ // Thus the generated number has at least lp+lq+11 bit and
+ // can have at most lp+lq+13 bit.
+ // Thus for random selection of p and q the algorithm will
+ // at some point select a number of length n=n/2+lr+(n-n/2-lr)=>n
+ // bit.
+ int lp = (keySize + 1) >> 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;
+
+ r = BigInteger.valueOf(r_lv);
+ do {
+ p = BigInteger.probablePrime(lp, random);
+ q = BigInteger.probablePrime(lq, random);
+
+ // 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
+ // primes 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());
}
}
public static void makeAgent(int uid) {
+ addChallenge(uid, CATSType.AGENT_CHALLENGE);
+ add100Points(uid);
+ insertRAContract(uid);
+ }
+
+ public static void addChallenge(int uid, CATSType ct) {
try (GigiPreparedStatement ps1 = new GigiPreparedStatement("INSERT INTO cats_passed SET user_id=?, variant_id=?, language='en_EN', version='1'")) {
ps1.setInt(1, uid);
- ps1.setInt(2, CATSType.AGENT_CHALLENGE.getId());
+ ps1.setInt(2, ct.getId());
ps1.execute();
}
+ }
+ public static void addChallengeInPast(int uid, CATSType ct) {
+ try (GigiPreparedStatement ps1 = new GigiPreparedStatement("INSERT INTO cats_passed SET user_id=?, variant_id=?, pass_date=?, language='en_EN', version='1'")) {
+ ps1.setInt(1, uid);
+ ps1.setInt(2, ct.getId());
+ ps1.setTimestamp(3, new Timestamp(new Date(System.currentTimeMillis() - 24L * 60 * 60 * (CATS.TEST_MONTHS + 1) * 31 * 1000L).getTime()));
+ ps1.execute();
+ }
+ }
+
+ public static void add100Points(int uid) {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+ try (GigiPreparedStatement ps2 = new GigiPreparedStatement("INSERT INTO `notary` SET `from`=?, `to`=?, points='100', `date`=?")) {
+ ps2.setInt(1, uid);
+ ps2.setInt(2, User.getById(uid).getPreferredName().getId());
+ ps2.setString(3, sdf.format(new Date(System.currentTimeMillis())));
+ ps2.execute();
+ }
+ }
+
+ public static void insertRAContract(int uid) {
+ // insert signed RA Contract
+ try (GigiPreparedStatement ps = new GigiPreparedStatement("INSERT INTO `user_contracts` SET `memid`=?, `token`=?, `document`=?::`contractType`,`agentname`=?")) {
+ ps.setInt(1, uid);
+ ps.setString(2, RandomToken.generateToken(32));
+ ps.setEnum(3, ContractType.RA_AGENT_CONTRACT);
+ ps.setString(4, User.getById(uid).getPreferredName().toString());
+ ps.execute();
+ }
+ }
+
+ public static void insertVerificationPoints(int uid) {
+ // insert Verification Points
try (GigiPreparedStatement ps2 = new GigiPreparedStatement("INSERT INTO `notary` SET `from`=?, `to`=?, points='100'")) {
ps2.setInt(1, uid);
ps2.setInt(2, User.getById(uid).getPreferredName().getId());
}
}
+ public static void insertPassedTest(int uid) {
+ // insert passed test
+ try (GigiPreparedStatement ps1 = new GigiPreparedStatement("INSERT INTO cats_passed SET user_id=?, variant_id=?, language='en_EN', version='1'")) {
+ ps1.setInt(1, uid);
+ ps1.setInt(2, CATSType.AGENT_CHALLENGE.getId());
+ ps1.execute();
+ }
+ }
+
public MailReceiver getMailReceiver() {
throw new Error("Feature requires Business or ManagedTest.");
}
public void verify(Domain d) {
try {
d.addPing(DomainPingType.EMAIL, "admin");
- TestMail testMail = getMailReceiver().receive();
+ TestMail testMail = getMailReceiver().receive("admin@" + d.getSuffix());
testMail.verify();
+ // Enforce successful ping :-)
+ d.addPing(DomainPingType.HTTP, "a:b");
+ try (GigiPreparedStatement gps = new GigiPreparedStatement("INSERT INTO `domainPinglog` SET `configId`=(SELECT `id` FROM `pingconfig` WHERE `domainid`=? AND `type`='http'), state='success', needsAction=false")) {
+ gps.setInt(1, d.getId());
+ gps.execute();
+ }
assertTrue(d.isVerified());
} catch (GigiApiException e) {
throw new Error(e);
c.add(Calendar.MONTH, -Notary.LIMIT_MAX_MONTHS_VERIFICATION + 1);
return sdf.format(new Date(c.getTimeInMillis()));
}
+
+ public void signRAContract(User u) throws GigiApiException {
+ new Contract(u, ContractType.RA_AGENT_CONTRACT);
+ getMailReceiver().receive(u.getEmail());
+ }
}