Store shared secrets in the database (the crypto component will be

responsible for wrapping/unwrapping them).
This commit is contained in:
akwizgran
2011-08-11 15:41:52 +01:00
parent 07b34cfbab
commit 151a360587
7 changed files with 138 additions and 57 deletions

View File

@@ -79,12 +79,12 @@ interface Database<T> {
/**
* Adds a new contact to the database with the given transport properties
* and returns an ID for the contact.
* and secret, and returns an ID for the contact.
* <p>
* Locking: contacts write, transports write.
*/
ContactId addContact(T txn, Map<String, Map<String, String>> transports)
throws DbException;
ContactId addContact(T txn, Map<String, Map<String, String>> transports,
byte[] secret) throws DbException;
/**
* Returns false if the given message is already in the database. Otherwise
@@ -273,6 +273,13 @@ interface Database<T> {
Collection<MessageId> getSendableMessages(T txn, ContactId c, int size)
throws DbException;
/**
* Returns the secret shared with the given contact.
* <p>
* Locking: contacts read.
*/
byte[] getSharedSecret(T txn, ContactId c) throws DbException;
/**
* Returns the groups to which the user subscribes.
* <p>

View File

@@ -79,6 +79,7 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " (contactId INT NOT NULL,"
+ " subscriptionsTimestamp BIGINT NOT NULL,"
+ " transportsTimestamp BIGINT NOT NULL,"
+ " secret BINARY NOT NULL,"
+ " PRIMARY KEY (contactId))";
private static final String CREATE_VISIBILITIES =
@@ -432,7 +433,7 @@ abstract class JdbcDatabase implements Database<Connection> {
}
public ContactId addContact(Connection txn,
Map<String, Map<String, String>> transports)
Map<String, Map<String, String>> transports, byte[] secret)
throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
@@ -449,13 +450,14 @@ abstract class JdbcDatabase implements Database<Connection> {
rs.close();
ps.close();
// Create a new contact row
sql = "INSERT INTO contacts"
+ " (contactId, subscriptionsTimestamp, transportsTimestamp)"
+ " VALUES (?, ?, ?)";
sql = "INSERT INTO contacts (contactId, subscriptionsTimestamp,"
+ " transportsTimestamp, secret)"
+ " VALUES (?, ?, ?, ?)";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
ps.setLong(2, 0L);
ps.setLong(3, 0L);
ps.setBytes(4, secret);
int affected = ps.executeUpdate();
if(affected != 1) throw new DbStateException();
ps.close();
@@ -1048,6 +1050,28 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
public byte[] getSharedSecret(Connection txn, ContactId c)
throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT secret FROM contacts WHERE contactId = ?";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
rs = ps.executeQuery();
if(!rs.next()) throw new DbStateException();
byte[] secret = rs.getBytes(1);
if(rs.next()) throw new DbStateException();
rs.close();
ps.close();
return secret;
} catch(SQLException e) {
tryToClose(rs);
tryToClose(ps);
throw new DbException(e);
}
}
public int getSendability(Connection txn, MessageId m) throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;

View File

@@ -103,8 +103,8 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
db.close();
}
public ContactId addContact(Map<String, Map<String, String>> transports)
throws DbException {
public ContactId addContact(Map<String, Map<String, String>> transports,
byte[] secret) throws DbException {
if(LOG.isLoggable(Level.FINE)) LOG.fine("Adding contact");
contactLock.writeLock().lock();
try {
@@ -112,7 +112,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
try {
Txn txn = db.startTransaction();
try {
ContactId c = db.addContact(txn, transports);
ContactId c = db.addContact(txn, transports, secret);
db.commitTransaction(txn);
if(LOG.isLoggable(Level.FINE))
LOG.fine("Added contact " + c);
@@ -550,6 +550,24 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
}
}
public byte[] getSharedSecret(ContactId c) throws DbException {
contactLock.readLock().lock();
try {
if(!containsContact(c)) throw new NoSuchContactException();
Txn txn = db.startTransaction();
try {
byte[] secret = db.getSharedSecret(txn, c);
db.commitTransaction(txn);
return secret;
} catch(DbException e) {
db.abortTransaction(txn);
throw e;
}
} finally {
contactLock.readLock().unlock();
}
}
public Collection<Group> getSubscriptions() throws DbException {
subscriptionLock.readLock().lock();
try {

View File

@@ -86,14 +86,14 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
db.close();
}
public ContactId addContact(Map<String, Map<String, String>> transports)
throws DbException {
public ContactId addContact(Map<String, Map<String, String>> transports,
byte[] secret) throws DbException {
if(LOG.isLoggable(Level.FINE)) LOG.fine("Adding contact");
synchronized(contactLock) {
synchronized(transportLock) {
Txn txn = db.startTransaction();
try {
ContactId c = db.addContact(txn, transports);
ContactId c = db.addContact(txn, transports, secret);
db.commitTransaction(txn);
if(LOG.isLoggable(Level.FINE))
LOG.fine("Added contact " + c);
@@ -422,6 +422,21 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
}
}
public byte[] getSharedSecret(ContactId c) throws DbException {
synchronized(contactLock) {
if(!containsContact(c)) throw new NoSuchContactException();
Txn txn = db.startTransaction();
try {
byte[] secret = db.getSharedSecret(txn, c);
db.commitTransaction(txn);
return secret;
} catch(DbException e) {
db.abortTransaction(txn);
throw e;
}
}
}
public Collection<Group> getSubscriptions() throws DbException {
synchronized(subscriptionLock) {
Txn txn = db.startTransaction();