Move validator's signature verification into ClientHelper

This commit is contained in:
Torsten Grote
2016-10-18 13:35:27 -02:00
parent 1e36f21cc8
commit 8dc529cc3f
7 changed files with 64 additions and 116 deletions

View File

@@ -6,6 +6,7 @@ import org.briarproject.api.data.BdfList;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
import org.briarproject.api.db.Transaction; import org.briarproject.api.db.Transaction;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.InvalidMessageException;
import org.briarproject.api.sync.Message; import org.briarproject.api.sync.Message;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
@@ -81,4 +82,8 @@ public interface ClientHelper {
byte[] sign(BdfList toSign, byte[] privateKey) byte[] sign(BdfList toSign, byte[] privateKey)
throws FormatException, GeneralSecurityException; throws FormatException, GeneralSecurityException;
void verifySignature(byte[] sig, byte[] publicKey, BdfList signed)
throws InvalidMessageException;
} }

View File

@@ -6,10 +6,6 @@ import org.briarproject.api.blogs.BlogFactory;
import org.briarproject.api.blogs.MessageType; import org.briarproject.api.blogs.MessageType;
import org.briarproject.api.clients.BdfMessageContext; import org.briarproject.api.clients.BdfMessageContext;
import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.clients.ClientHelper;
import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.KeyParser;
import org.briarproject.api.crypto.PublicKey;
import org.briarproject.api.crypto.Signature;
import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.data.BdfDictionary;
import org.briarproject.api.data.BdfEntry; import org.briarproject.api.data.BdfEntry;
import org.briarproject.api.data.BdfList; import org.briarproject.api.data.BdfList;
@@ -24,7 +20,6 @@ import org.briarproject.api.sync.MessageId;
import org.briarproject.api.system.Clock; import org.briarproject.api.system.Clock;
import org.briarproject.clients.BdfMessageValidator; import org.briarproject.clients.BdfMessageValidator;
import java.security.GeneralSecurityException;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@@ -48,18 +43,15 @@ import static org.briarproject.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH
class BlogPostValidator extends BdfMessageValidator { class BlogPostValidator extends BdfMessageValidator {
private final CryptoComponent crypto;
private final GroupFactory groupFactory; private final GroupFactory groupFactory;
private final MessageFactory messageFactory; private final MessageFactory messageFactory;
private final BlogFactory blogFactory; private final BlogFactory blogFactory;
BlogPostValidator(CryptoComponent crypto, GroupFactory groupFactory, BlogPostValidator(GroupFactory groupFactory, MessageFactory messageFactory,
MessageFactory messageFactory, BlogFactory blogFactory, BlogFactory blogFactory, ClientHelper clientHelper,
ClientHelper clientHelper, MetadataEncoder metadataEncoder, MetadataEncoder metadataEncoder, Clock clock) {
Clock clock) {
super(clientHelper, metadataEncoder, clock); super(clientHelper, metadataEncoder, clock);
this.crypto = crypto;
this.groupFactory = groupFactory; this.groupFactory = groupFactory;
this.messageFactory = messageFactory; this.messageFactory = messageFactory;
this.blogFactory = blogFactory; this.blogFactory = blogFactory;
@@ -109,7 +101,7 @@ class BlogPostValidator extends BdfMessageValidator {
BdfList signed = BdfList.of(g.getId(), m.getTimestamp(), postBody); BdfList signed = BdfList.of(g.getId(), m.getTimestamp(), postBody);
Blog b = blogFactory.parseBlog(g, ""); // description doesn't matter Blog b = blogFactory.parseBlog(g, ""); // description doesn't matter
Author a = b.getAuthor(); Author a = b.getAuthor();
verifySignature(sig, a.getPublicKey(), signed); clientHelper.verifySignature(sig, a.getPublicKey(), signed);
// Return the metadata and dependencies // Return the metadata and dependencies
BdfDictionary meta = new BdfDictionary(); BdfDictionary meta = new BdfDictionary();
@@ -150,7 +142,7 @@ class BlogPostValidator extends BdfMessageValidator {
currentId); currentId);
Blog b = blogFactory.parseBlog(g, ""); // description doesn't matter Blog b = blogFactory.parseBlog(g, ""); // description doesn't matter
Author a = b.getAuthor(); Author a = b.getAuthor();
verifySignature(sig, a.getPublicKey(), signed); clientHelper.verifySignature(sig, a.getPublicKey(), signed);
// Return the metadata and dependencies // Return the metadata and dependencies
BdfDictionary meta = new BdfDictionary(); BdfDictionary meta = new BdfDictionary();
@@ -267,26 +259,6 @@ class BlogPostValidator extends BdfMessageValidator {
return new BdfMessageContext(meta, dependencies); return new BdfMessageContext(meta, dependencies);
} }
private void verifySignature(byte[] sig, byte[] publicKey, BdfList signed)
throws InvalidMessageException {
try {
// Parse the public key
KeyParser keyParser = crypto.getSignatureKeyParser();
PublicKey key = keyParser.parsePublicKey(publicKey);
// Verify the signature
Signature signature = crypto.getSignature();
signature.initVerify(key);
signature.update(clientHelper.toByteArray(signed));
if (!signature.verify(sig)) {
throw new InvalidMessageException("Invalid signature");
}
} catch (GeneralSecurityException e) {
throw new InvalidMessageException("Invalid public key");
} catch (FormatException e) {
throw new InvalidMessageException(e);
}
}
static BdfDictionary authorToBdfDictionary(Author a) { static BdfDictionary authorToBdfDictionary(Author a) {
return BdfDictionary.of( return BdfDictionary.of(
new BdfEntry(KEY_AUTHOR_ID, a.getId()), new BdfEntry(KEY_AUTHOR_ID, a.getId()),

View File

@@ -5,7 +5,6 @@ import org.briarproject.api.blogs.BlogManager;
import org.briarproject.api.blogs.BlogPostFactory; import org.briarproject.api.blogs.BlogPostFactory;
import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.clients.ClientHelper;
import org.briarproject.api.contact.ContactManager; import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.data.MetadataEncoder; import org.briarproject.api.data.MetadataEncoder;
import org.briarproject.api.identity.AuthorFactory; import org.briarproject.api.identity.AuthorFactory;
import org.briarproject.api.identity.IdentityManager; import org.briarproject.api.identity.IdentityManager;
@@ -64,14 +63,14 @@ public class BlogsModule {
@Provides @Provides
@Singleton @Singleton
BlogPostValidator provideBlogPostValidator( BlogPostValidator provideBlogPostValidator(
ValidationManager validationManager, CryptoComponent crypto, ValidationManager validationManager, GroupFactory groupFactory,
GroupFactory groupFactory, MessageFactory messageFactory, MessageFactory messageFactory, BlogFactory blogFactory,
BlogFactory blogFactory, ClientHelper clientHelper, ClientHelper clientHelper, MetadataEncoder metadataEncoder,
MetadataEncoder metadataEncoder, Clock clock) { Clock clock) {
BlogPostValidator validator = new BlogPostValidator(crypto, BlogPostValidator validator = new BlogPostValidator(groupFactory,
groupFactory, messageFactory, blogFactory, clientHelper, messageFactory, blogFactory, clientHelper, metadataEncoder,
metadataEncoder, clock); clock);
validationManager.registerMessageValidator(CLIENT_ID, validator); validationManager.registerMessageValidator(CLIENT_ID, validator);
return validator; return validator;

View File

@@ -5,6 +5,7 @@ import org.briarproject.api.clients.ClientHelper;
import org.briarproject.api.crypto.CryptoComponent; import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.KeyParser; import org.briarproject.api.crypto.KeyParser;
import org.briarproject.api.crypto.PrivateKey; import org.briarproject.api.crypto.PrivateKey;
import org.briarproject.api.crypto.PublicKey;
import org.briarproject.api.crypto.Signature; import org.briarproject.api.crypto.Signature;
import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.data.BdfDictionary;
import org.briarproject.api.data.BdfList; import org.briarproject.api.data.BdfList;
@@ -19,6 +20,7 @@ import org.briarproject.api.db.DbException;
import org.briarproject.api.db.Metadata; import org.briarproject.api.db.Metadata;
import org.briarproject.api.db.Transaction; import org.briarproject.api.db.Transaction;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.InvalidMessageException;
import org.briarproject.api.sync.Message; import org.briarproject.api.sync.Message;
import org.briarproject.api.sync.MessageFactory; import org.briarproject.api.sync.MessageFactory;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
@@ -320,4 +322,26 @@ class ClientHelperImpl implements ClientHelper {
signature.update(toByteArray(toSign)); signature.update(toByteArray(toSign));
return signature.sign(); return signature.sign();
} }
@Override
public void verifySignature(byte[] sig, byte[] publicKey, BdfList signed)
throws InvalidMessageException {
try {
// Parse the public key
KeyParser keyParser = cryptoComponent.getSignatureKeyParser();
PublicKey key = keyParser.parsePublicKey(publicKey);
// Verify the signature
Signature signature = cryptoComponent.getSignature();
signature.initVerify(key);
signature.update(toByteArray(signed));
if (!signature.verify(sig)) {
throw new InvalidMessageException("Invalid signature");
}
} catch (GeneralSecurityException e) {
throw new InvalidMessageException("Invalid public key");
} catch (FormatException e) {
throw new InvalidMessageException(e);
}
}
} }

View File

@@ -54,11 +54,11 @@ public class ForumModule {
@Provides @Provides
@Singleton @Singleton
ForumPostValidator provideForumPostValidator( ForumPostValidator provideForumPostValidator(
ValidationManager validationManager, CryptoComponent crypto, ValidationManager validationManager, AuthorFactory authorFactory,
AuthorFactory authorFactory, ClientHelper clientHelper, ClientHelper clientHelper, MetadataEncoder metadataEncoder,
MetadataEncoder metadataEncoder, Clock clock) { Clock clock) {
ForumPostValidator validator = new ForumPostValidator(crypto, ForumPostValidator validator = new ForumPostValidator(authorFactory,
authorFactory, clientHelper, metadataEncoder, clock); clientHelper, metadataEncoder, clock);
validationManager.registerMessageValidator( validationManager.registerMessageValidator(
ForumManagerImpl.CLIENT_ID, validator); ForumManagerImpl.CLIENT_ID, validator);
return validator; return validator;

View File

@@ -4,10 +4,6 @@ import org.briarproject.api.FormatException;
import org.briarproject.api.UniqueId; import org.briarproject.api.UniqueId;
import org.briarproject.api.clients.BdfMessageContext; import org.briarproject.api.clients.BdfMessageContext;
import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.clients.ClientHelper;
import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.KeyParser;
import org.briarproject.api.crypto.PublicKey;
import org.briarproject.api.crypto.Signature;
import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.data.BdfDictionary;
import org.briarproject.api.data.BdfList; import org.briarproject.api.data.BdfList;
import org.briarproject.api.data.MetadataEncoder; import org.briarproject.api.data.MetadataEncoder;
@@ -20,7 +16,6 @@ import org.briarproject.api.sync.MessageId;
import org.briarproject.api.system.Clock; import org.briarproject.api.system.Clock;
import org.briarproject.clients.BdfMessageValidator; import org.briarproject.clients.BdfMessageValidator;
import java.security.GeneralSecurityException;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@@ -32,14 +27,11 @@ import static org.briarproject.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH
class ForumPostValidator extends BdfMessageValidator { class ForumPostValidator extends BdfMessageValidator {
private final CryptoComponent crypto;
private final AuthorFactory authorFactory; private final AuthorFactory authorFactory;
ForumPostValidator(CryptoComponent crypto, AuthorFactory authorFactory, ForumPostValidator(AuthorFactory authorFactory, ClientHelper clientHelper,
ClientHelper clientHelper, MetadataEncoder metadataEncoder, MetadataEncoder metadataEncoder, Clock clock) {
Clock clock) {
super(clientHelper, metadataEncoder, clock); super(clientHelper, metadataEncoder, clock);
this.crypto = crypto;
this.authorFactory = authorFactory; this.authorFactory = authorFactory;
} }
@@ -81,23 +73,10 @@ class ForumPostValidator extends BdfMessageValidator {
} }
// Verify the signature, if any // Verify the signature, if any
if (author != null) { if (author != null) {
try { // Serialise the data to be signed
// Parse the public key BdfList signed = BdfList.of(g.getId(), m.getTimestamp(), parent,
KeyParser keyParser = crypto.getSignatureKeyParser(); authorList, contentType, forumPostBody);
PublicKey key = keyParser.parsePublicKey(author.getPublicKey()); clientHelper.verifySignature(sig, author.getPublicKey(), signed);
// Serialise the data to be signed
BdfList signed = BdfList.of(g.getId(), m.getTimestamp(), parent,
authorList, contentType, forumPostBody);
// Verify the signature
Signature signature = crypto.getSignature();
signature.initVerify(key);
signature.update(clientHelper.toByteArray(signed));
if (!signature.verify(sig)) {
throw new InvalidMessageException("Invalid signature");
}
} catch (GeneralSecurityException e) {
throw new InvalidMessageException("Invalid public key");
}
} }
// Return the metadata and dependencies // Return the metadata and dependencies
BdfDictionary meta = new BdfDictionary(); BdfDictionary meta = new BdfDictionary();

View File

@@ -7,9 +7,6 @@ import org.briarproject.api.blogs.Blog;
import org.briarproject.api.blogs.BlogFactory; import org.briarproject.api.blogs.BlogFactory;
import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.clients.ClientHelper;
import org.briarproject.api.crypto.CryptoComponent; import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.KeyParser;
import org.briarproject.api.crypto.PublicKey;
import org.briarproject.api.crypto.Signature;
import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.data.BdfDictionary;
import org.briarproject.api.data.BdfEntry; import org.briarproject.api.data.BdfEntry;
import org.briarproject.api.data.BdfList; import org.briarproject.api.data.BdfList;
@@ -20,7 +17,6 @@ import org.briarproject.api.sync.ClientId;
import org.briarproject.api.sync.Group; import org.briarproject.api.sync.Group;
import org.briarproject.api.sync.GroupFactory; import org.briarproject.api.sync.GroupFactory;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.InvalidMessageException;
import org.briarproject.api.sync.Message; import org.briarproject.api.sync.Message;
import org.briarproject.api.sync.MessageFactory; import org.briarproject.api.sync.MessageFactory;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
@@ -37,9 +33,9 @@ import static org.briarproject.api.blogs.BlogConstants.KEY_AUTHOR;
import static org.briarproject.api.blogs.BlogConstants.KEY_AUTHOR_ID; import static org.briarproject.api.blogs.BlogConstants.KEY_AUTHOR_ID;
import static org.briarproject.api.blogs.BlogConstants.KEY_AUTHOR_NAME; import static org.briarproject.api.blogs.BlogConstants.KEY_AUTHOR_NAME;
import static org.briarproject.api.blogs.BlogConstants.KEY_COMMENT; import static org.briarproject.api.blogs.BlogConstants.KEY_COMMENT;
import static org.briarproject.api.blogs.BlogConstants.KEY_ORIGINAL_MSG_ID;
import static org.briarproject.api.blogs.BlogConstants.KEY_ORIGINAL_PARENT_MSG_ID; import static org.briarproject.api.blogs.BlogConstants.KEY_ORIGINAL_PARENT_MSG_ID;
import static org.briarproject.api.blogs.BlogConstants.KEY_PARENT_MSG_ID; import static org.briarproject.api.blogs.BlogConstants.KEY_PARENT_MSG_ID;
import static org.briarproject.api.blogs.BlogConstants.KEY_ORIGINAL_MSG_ID;
import static org.briarproject.api.blogs.BlogConstants.KEY_PUBLIC_KEY; import static org.briarproject.api.blogs.BlogConstants.KEY_PUBLIC_KEY;
import static org.briarproject.api.blogs.BlogConstants.KEY_READ; import static org.briarproject.api.blogs.BlogConstants.KEY_READ;
import static org.briarproject.api.blogs.MessageType.COMMENT; import static org.briarproject.api.blogs.MessageType.COMMENT;
@@ -94,9 +90,8 @@ public class BlogPostValidatorTest extends BriarTestCase {
message = new Message(messageId, group.getId(), timestamp, raw); message = new Message(messageId, group.getId(), timestamp, raw);
MetadataEncoder metadataEncoder = context.mock(MetadataEncoder.class); MetadataEncoder metadataEncoder = context.mock(MetadataEncoder.class);
validator = new BlogPostValidator(cryptoComponent, groupFactory, validator = new BlogPostValidator(groupFactory, messageFactory,
messageFactory, blogFactory, clientHelper, metadataEncoder, blogFactory, clientHelper, metadataEncoder, clock);
clock);
context.assertIsSatisfied(); context.assertIsSatisfied();
} }
@@ -108,7 +103,7 @@ public class BlogPostValidatorTest extends BriarTestCase {
BdfList signed = BdfList signed =
BdfList.of(blog.getId(), message.getTimestamp(), body); BdfList.of(blog.getId(), message.getTimestamp(), body);
expectCrypto(signed, sigBytes, true); expectCrypto(signed, sigBytes);
final BdfDictionary result = final BdfDictionary result =
validator.validateMessage(message, group, m).getDictionary(); validator.validateMessage(message, group, m).getDictionary();
@@ -135,18 +130,6 @@ public class BlogPostValidatorTest extends BriarTestCase {
validator.validateMessage(message, group, m).getDictionary(); validator.validateMessage(message, group, m).getDictionary();
} }
@Test(expected = InvalidMessageException.class)
public void testValidateBlogPostWithBadSignature()
throws IOException, GeneralSecurityException {
final byte[] sigBytes = TestUtils.getRandomBytes(42);
BdfList m = BdfList.of(POST.getInt(), body, sigBytes);
BdfList signed =
BdfList.of(blog.getId(), message.getTimestamp(), body);
expectCrypto(signed, sigBytes, false);
validator.validateMessage(message, group, m).getDictionary();
}
@Test @Test
public void testValidateProperBlogComment() public void testValidateProperBlogComment()
throws IOException, GeneralSecurityException { throws IOException, GeneralSecurityException {
@@ -162,7 +145,7 @@ public class BlogPostValidatorTest extends BriarTestCase {
BdfList signed = BdfList signed =
BdfList.of(blog.getId(), message.getTimestamp(), comment, BdfList.of(blog.getId(), message.getTimestamp(), comment,
pOriginalId, currentId); pOriginalId, currentId);
expectCrypto(signed, sigBytes, true); expectCrypto(signed, sigBytes);
final BdfDictionary result = final BdfDictionary result =
validator.validateMessage(message, group, m).getDictionary(); validator.validateMessage(message, group, m).getDictionary();
@@ -189,7 +172,7 @@ public class BlogPostValidatorTest extends BriarTestCase {
BdfList signed = BdfList signed =
BdfList.of(blog.getId(), message.getTimestamp(), null, BdfList.of(blog.getId(), message.getTimestamp(), null,
originalId, currentId); originalId, currentId);
expectCrypto(signed, sigBytes, true); expectCrypto(signed, sigBytes);
final BdfDictionary result = final BdfDictionary result =
validator.validateMessage(message, group, m).getDictionary(); validator.validateMessage(message, group, m).getDictionary();
@@ -208,7 +191,7 @@ public class BlogPostValidatorTest extends BriarTestCase {
BdfList signed = BdfList signed =
BdfList.of(blog.getId(), message.getTimestamp(), body); BdfList.of(blog.getId(), message.getTimestamp(), body);
expectCrypto(signed, sigBytes, true); expectCrypto(signed, sigBytes);
final BdfList originalList = BdfList.of(POST.getInt(), body, sigBytes); final BdfList originalList = BdfList.of(POST.getInt(), body, sigBytes);
final byte[] originalBody = TestUtils.getRandomBytes(42); final byte[] originalBody = TestUtils.getRandomBytes(42);
@@ -247,7 +230,7 @@ public class BlogPostValidatorTest extends BriarTestCase {
BdfList signed = BdfList.of(blog.getId(), message.getTimestamp(), BdfList signed = BdfList.of(blog.getId(), message.getTimestamp(),
comment, originalId, oldId); comment, originalId, oldId);
expectCrypto(signed, sigBytes, true); expectCrypto(signed, sigBytes);
final BdfList originalList = BdfList.of(COMMENT.getInt(), comment, final BdfList originalList = BdfList.of(COMMENT.getInt(), comment,
originalId, oldId, sigBytes); originalId, oldId, sigBytes);
@@ -275,27 +258,13 @@ public class BlogPostValidatorTest extends BriarTestCase {
context.assertIsSatisfied(); context.assertIsSatisfied();
} }
private void expectCrypto(final BdfList signed, final byte[] sig, private void expectCrypto(final BdfList signed, final byte[] sig)
final boolean pass) throws IOException, GeneralSecurityException { throws IOException, GeneralSecurityException {
final Signature signature = context.mock(Signature.class);
final KeyParser keyParser = context.mock(KeyParser.class);
final PublicKey publicKey = context.mock(PublicKey.class);
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(blogFactory).parseBlog(group, ""); oneOf(blogFactory).parseBlog(group, "");
will(returnValue(blog)); will(returnValue(blog));
oneOf(cryptoComponent).getSignatureKeyParser(); oneOf(clientHelper)
will(returnValue(keyParser)); .verifySignature(sig, author.getPublicKey(), signed);
oneOf(keyParser).parsePublicKey(blog.getAuthor().getPublicKey());
will(returnValue(publicKey));
oneOf(cryptoComponent).getSignature();
will(returnValue(signature));
oneOf(signature).initVerify(publicKey);
oneOf(clientHelper).toByteArray(signed);
will(returnValue(sig));
oneOf(signature).update(sig);
oneOf(signature).verify(sig);
will(returnValue(pass));
}}); }});
} }