Added Some unit tests and fixed several bugs.
parent
3837b0c53e
commit
dbf5727cee
|
@ -118,7 +118,7 @@ public abstract class BulletinBoardSQLServer implements BulletinBoardServer{
|
||||||
sql = "INSERT INTO MsgTable (MsgId, Msg) VALUES(?,?)";
|
sql = "INSERT INTO MsgTable (MsgId, Msg) VALUES(?,?)";
|
||||||
pstmt = connection.prepareStatement(sql);
|
pstmt = connection.prepareStatement(sql);
|
||||||
pstmt.setBytes(1, msgID);
|
pstmt.setBytes(1, msgID);
|
||||||
pstmt.setBytes(2, msg.toByteArray());
|
pstmt.setBytes(2, msg.getMsg().toByteArray());
|
||||||
pstmt.executeUpdate();
|
pstmt.executeUpdate();
|
||||||
|
|
||||||
rs = pstmt.getGeneratedKeys();
|
rs = pstmt.getGeneratedKeys();
|
||||||
|
|
|
@ -24,24 +24,28 @@ public class SQLiteBulletinBoardServer extends BulletinBoardSQLServer {
|
||||||
* 2. The database tables (if they do not yet exist).
|
* 2. The database tables (if they do not yet exist).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
private void createSchema() throws SQLException {
|
||||||
|
Statement statement = connection.createStatement();
|
||||||
|
statement.setQueryTimeout(TIMEOUT);
|
||||||
|
|
||||||
|
statement.executeUpdate("CREATE TABLE IF NOT EXISTS MsgTable (EntryNum INTEGER PRIMARY KEY, MsgId BLOB UNIQUE, Msg BLOB)");
|
||||||
|
|
||||||
|
statement.executeUpdate("CREATE TABLE IF NOT EXISTS TagTable (TagId INTEGER PRIMARY KEY, Tag varchar(50) UNIQUE)");
|
||||||
|
statement.executeUpdate("CREATE TABLE IF NOT EXISTS MsgTagTable (EntryNum BLOB, TagId INTEGER, FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum), FOREIGN KEY (TagId) REFERENCES TagTable(TagId), UNIQUE (EntryNum, TagID))");
|
||||||
|
|
||||||
|
statement.executeUpdate("CREATE TABLE IF NOT EXISTS SignatureTable (EntryNum BLOB, SignerId BLOB, Signature BLOB UNIQUE, FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum))");
|
||||||
|
statement.executeUpdate("CREATE INDEX IF NOT EXISTS SignerIndex ON SignatureTable(SignerId)");
|
||||||
|
|
||||||
|
statement.close();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() throws CommunicationException {
|
public void init() throws CommunicationException {
|
||||||
|
|
||||||
try{
|
try{
|
||||||
|
|
||||||
connection = DriverManager.getConnection("jdbc:sqlite:local-instances/meerkat.db");
|
connection = DriverManager.getConnection("jdbc:sqlite:local-instances/meerkat.db");
|
||||||
Statement statement = connection.createStatement();
|
createSchema();
|
||||||
statement.setQueryTimeout(TIMEOUT);
|
|
||||||
|
|
||||||
statement.executeUpdate("CREATE TABLE IF NOT EXISTS MsgTable (EntryNum INTEGER PRIMARY KEY, MsgId BLOB UNIQUE, Msg BLOB)");
|
|
||||||
|
|
||||||
statement.executeUpdate("CREATE TABLE IF NOT EXISTS TagTable (TagId INTEGER PRIMARY KEY, Tag varchar(50) UNIQUE)");
|
|
||||||
statement.executeUpdate("CREATE TABLE IF NOT EXISTS MsgTagTable (EntryNum BLOB, TagId INTEGER, FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum), FOREIGN KEY (TagId) REFERENCES TagTable(TagId), UNIQUE (EntryNum, TagID))");
|
|
||||||
|
|
||||||
statement.executeUpdate("CREATE TABLE IF NOT EXISTS SignatureTable (EntryNum BLOB, SignerId BLOB, Signature BLOB UNIQUE, FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum))");
|
|
||||||
statement.executeUpdate("CREATE INDEX IF NOT EXISTS SignerIndex ON SignatureTable(SignerId)");
|
|
||||||
|
|
||||||
statement.close();
|
|
||||||
|
|
||||||
super.init();
|
super.init();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
package meerkat.bulletinboard;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.NoSuchFileException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import meerkat.bulletinboard.sqlserver.SQLiteBulletinBoardServer;
|
||||||
|
|
||||||
|
public class BulletinBoardServerTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAllServers(){
|
||||||
|
GenericBulletinBoardServerTest bbst = new GenericBulletinBoardServerTest();
|
||||||
|
try {
|
||||||
|
try{
|
||||||
|
Path path = Paths.get("local-instances/meerkat.db");
|
||||||
|
Files.delete(path);
|
||||||
|
} catch(NoSuchFileException e){}
|
||||||
|
|
||||||
|
bbst.init(SQLiteBulletinBoardServer.class);
|
||||||
|
bbst.bulkTest();
|
||||||
|
bbst.close();
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println(e.getMessage() + e.getClass());
|
||||||
|
assert false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,178 @@
|
||||||
|
package meerkat.bulletinboard;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.KeyStoreException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.security.SignatureException;
|
||||||
|
import java.security.UnrecoverableKeyException;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.google.protobuf.ByteString;
|
||||||
|
|
||||||
|
import meerkat.comm.CommunicationException;
|
||||||
|
import meerkat.crypto.concrete.ECDSASignature;
|
||||||
|
import meerkat.crypto.concrete.TestECDSASignature;
|
||||||
|
import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage;
|
||||||
|
import meerkat.protobuf.BulletinBoardAPI.FilterType;
|
||||||
|
import meerkat.protobuf.BulletinBoardAPI.MessageFilter;
|
||||||
|
import meerkat.protobuf.BulletinBoardAPI.MessageFilterList;
|
||||||
|
import meerkat.protobuf.BulletinBoardAPI.UnsignedBulletinBoardMessage;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
import static org.hamcrest.CoreMatchers.*;
|
||||||
|
|
||||||
|
public class GenericBulletinBoardServerTest {
|
||||||
|
private BulletinBoardServer bulletinBoardServer;
|
||||||
|
private ECDSASignature signers[];
|
||||||
|
|
||||||
|
private SecureRandom random;
|
||||||
|
|
||||||
|
private static String KEYFILE_EXAMPLE = "/certs/enduser-certs/user1-key-with-password-secret.p12";
|
||||||
|
private static String KEYFILE_PASSWORD = "secret";
|
||||||
|
|
||||||
|
public static String CERT1_PEM_EXAMPLE = "/certs/enduser-certs/user1.crt";
|
||||||
|
|
||||||
|
// private static String KEYFILE_EXAMPLE2 = "/certs/enduser-certs/user2-key.pem";
|
||||||
|
|
||||||
|
public void init(Class<?> cls) throws InstantiationException, IllegalAccessException, CertificateException, KeyStoreException, NoSuchAlgorithmException, IOException, UnrecoverableKeyException, CommunicationException{
|
||||||
|
bulletinBoardServer = (BulletinBoardServer) cls.newInstance();
|
||||||
|
bulletinBoardServer.init();
|
||||||
|
|
||||||
|
signers = new ECDSASignature[2];
|
||||||
|
signers[0] = new ECDSASignature();
|
||||||
|
signers[1] = new ECDSASignature();
|
||||||
|
|
||||||
|
InputStream keyStream = TestECDSASignature.class.getResourceAsStream(KEYFILE_EXAMPLE);
|
||||||
|
char[] password = KEYFILE_PASSWORD.toCharArray();
|
||||||
|
|
||||||
|
KeyStore.Builder keyStore = signers[0].getPKCS12KeyStoreBuilder(keyStream, password);
|
||||||
|
signers[0].loadSigningCertificate(keyStore);
|
||||||
|
|
||||||
|
signers[0].loadVerificationCertificates(TestECDSASignature.class.getResourceAsStream(CERT1_PEM_EXAMPLE));
|
||||||
|
|
||||||
|
random = new SecureRandom();
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte randomByte(){
|
||||||
|
return (byte) ((Math.random() * 256) - 128);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String randomString(){
|
||||||
|
return new BigInteger(130, random).toString(32);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bulkTest() throws CommunicationException, SignatureException, InvalidKeyException, CertificateException, IOException{
|
||||||
|
|
||||||
|
final int TAG_NUM = 5; // Number of tags.
|
||||||
|
final int MESSAGE_NUM = 32; // Number of messages (2^TAG_NUM).
|
||||||
|
final int BYTES_PER_MESSAGE_DATA = 50; // Message size.
|
||||||
|
|
||||||
|
String[] tags = new String[TAG_NUM];
|
||||||
|
byte[][] data = new byte[MESSAGE_NUM][BYTES_PER_MESSAGE_DATA];
|
||||||
|
|
||||||
|
UnsignedBulletinBoardMessage.Builder unsignedMsgBuilder;
|
||||||
|
BulletinBoardMessage.Builder msgBuilder;
|
||||||
|
|
||||||
|
int i,j;
|
||||||
|
|
||||||
|
// Generate random data.
|
||||||
|
|
||||||
|
for (i = 1 ; i <= MESSAGE_NUM ; i++){
|
||||||
|
for (j = 0 ; j < BYTES_PER_MESSAGE_DATA ; j++){
|
||||||
|
data[i-1][j] = randomByte();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0 ; i < TAG_NUM ; i++){
|
||||||
|
tags[i] = randomString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build messages.
|
||||||
|
|
||||||
|
for (i = 1 ; i <= MESSAGE_NUM ; i++){
|
||||||
|
unsignedMsgBuilder = UnsignedBulletinBoardMessage.newBuilder()
|
||||||
|
.setData(ByteString.copyFrom(data[i-1]));
|
||||||
|
|
||||||
|
// Add tags based on bit-representation of message number.
|
||||||
|
|
||||||
|
int copyI = i;
|
||||||
|
for (j = 0 ; j < TAG_NUM ; j++){
|
||||||
|
if (copyI % 2 == 1){
|
||||||
|
unsignedMsgBuilder.addTag(tags[j]);
|
||||||
|
}
|
||||||
|
|
||||||
|
copyI >>>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build message.
|
||||||
|
|
||||||
|
msgBuilder = BulletinBoardMessage.newBuilder()
|
||||||
|
.setMsg(unsignedMsgBuilder.build());
|
||||||
|
|
||||||
|
// Add signatures.
|
||||||
|
|
||||||
|
if (i % 2 == 1){
|
||||||
|
signers[0].updateContent(msgBuilder.getMsg());
|
||||||
|
msgBuilder.addSig(signers[0].sign());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post message.
|
||||||
|
|
||||||
|
bulletinBoardServer.postMessage(msgBuilder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check tag mechanism
|
||||||
|
|
||||||
|
for (i = 0 ; i < TAG_NUM ; i++){
|
||||||
|
|
||||||
|
// Retrieve messages having tag i
|
||||||
|
|
||||||
|
List<BulletinBoardMessage> messages =
|
||||||
|
bulletinBoardServer.readMessages(
|
||||||
|
MessageFilterList.newBuilder()
|
||||||
|
.addFilter(MessageFilter.newBuilder()
|
||||||
|
.setType(FilterType.TAG)
|
||||||
|
.setTag(tags[i])
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.getMessageList();
|
||||||
|
|
||||||
|
// Assert that the number of retrieved messages is correct.
|
||||||
|
|
||||||
|
assertThat(messages.size(), is(MESSAGE_NUM / 2));
|
||||||
|
|
||||||
|
// Assert the identity of the messages.
|
||||||
|
|
||||||
|
for (BulletinBoardMessage msg : messages){
|
||||||
|
|
||||||
|
// Assert serial number and raw data.
|
||||||
|
|
||||||
|
assertThat((msg.getEntryNum() >>> i) % 2 , is((long) 1));
|
||||||
|
assertThat(msg.getMsg().getData().toByteArray(), is(data[(int) msg.getEntryNum() - 1]));
|
||||||
|
|
||||||
|
// Assert signatures.
|
||||||
|
|
||||||
|
if (msg.getEntryNum() % 2 == 1){
|
||||||
|
signers[0].initVerify(msg.getSig(0));
|
||||||
|
signers[0].updateContent(msg.getMsg());
|
||||||
|
assertTrue("Signature did not verify!", signers[0].verify());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close(){
|
||||||
|
signers[0].clearSigningKey();
|
||||||
|
signers[1].clearSigningKey();
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,14 +2,12 @@ package meerkat.crypto.concrete;
|
||||||
|
|
||||||
import com.google.protobuf.ByteString;
|
import com.google.protobuf.ByteString;
|
||||||
import meerkat.protobuf.Crypto;
|
import meerkat.protobuf.Crypto;
|
||||||
|
import meerkat.crypto.concrete.ECDSASignature;
|
||||||
import meerkat.protobuf.BulletinBoardAPI.*;
|
import meerkat.protobuf.BulletinBoardAPI.*;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.security.KeyStore;
|
import java.security.KeyStore;
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
Loading…
Reference in New Issue