Monday 26 April 2010

Accepted to GSoC!

Awesome! My summer of code application got accepted by SIP Communicator! It's going to be a hot summer!
In fact, the dev team decided that using environment specific password storage is not a such a good idea after all, and it would be much better to do something more generic. I agree, and in fact Java provides with the means to do so.
Since implementing only the generic password storage is clearly not enough for the whole summer, I'll also be doing another project, call recording. I really don't know much how to go about doing this right now, but I'm sure I'll think of something and it's always nice to learn something new like Java Media Framework API.
Right now however I'll concentrate on the password storage and try to accomplish that as soon as possible. First thing first, I should make and overview of the new requirements. Stay tuned.

Saturday 3 April 2010

SIP Communicator GSoC 2010 Application Part 5

The Result

It's time to think about how to put everything together. Clearly there must be some generic solution that allows easily adding new external password storage utilities such as KWallet or OSX utility. Well, the obvious way to do this is to use something like the following from the ProtocolProviderFactory.storePassword (which I talked about in Part 2). Just a sketch:

public static class PasswordStore {
public void storePassword(String account, String password) {
Runtime runtime = Runtime.getRuntime();
if (OSUtils.IS_LINUX) {
// can we check if gnome is running in some other way?
if (runtime.exec(new String[] { "which", "gnome-keyring" })
.waitFor() == 0) {
password = new GnomeKeyring().storePassword(account,
password);
// probably add a property that says we're using
// gnome-keyring,
// this would make loading easier
} else if (runtime.exec(new String[] { "which", "kwallet" })
.waitFor() == 0) {
// store to KWallet
}
} else if (OSUtils.IS_MAC) {
// osx storage
} else {
// fall back to default behaviour (base-64 encode)
}
}
}

I did a quick search in the code and it seems that OSUtils.IS_* is used everywhere to check the OS type. I didn't find anything to check what desktop environment is used, but inside BrowserLauncherImpl I found similar code that finds browsers using unix which command, that's one way I guess, but maybe there's a better solution.
Anyway, the idea is that when the password is stored a new property is written in the configuration that tells what storage mechanism is used. With this property present, password loading is easy. Sketch:

public static class PasswordLoad {
public String loadPassword(String account) {
String password = null;
String property = configurationService.getString(storageType);
if (property.equals("gnome-keyring")) {
password = new GnomeKeyRing().loadPassword(account);
} else {
// fall back to default and get password from the properties
}
return password;
}
}

Clearly, default behavior should be used when no other option is possible. Also, maybe when the password was not found in gnome-keyring we should also look in the configuration, just in case.

Concerning KWallet, I haven't researched it much (being a gnome user), but there is this thing. A whole java library for KWallet, excellent! So, I guess it should not be a problem to talk to it. I certainly can do that if gnome-keyring is already working and integrated.

Well, that seems to be it. I've described in 5 parts what I would do to implement a secure password storage with GnomeKeyring for SIP Communicator. I think the application is complete and I really need some feedback from the development team. If they like it and my application becomes accepted I'll continue posting on my progress here.

SIP Communicator GSoC 2010 Application Part 4

The Progress

I managed to get JNI to talk to GnomeKeyring via libgnome-keyring. Basically I can store, delete, load passwords, check GK availability and list it's keyrings. Here's the code:
First the java part:

package example;


public class GnomeKeyring {
public native void setApplicationName(String name);
public native String[] getKeyRingNames();
public native boolean isKeyRingAvailable();
public native boolean storePassword(String account, String pass);
public native boolean deletePassword(String account);
public native String loadPassword(String account);

static {
System.loadLibrary("gk-native");
}

public GnomeKeyring(String appName) {
setApplicationName(appName);
}

public static void main(String[] args) {
String libPath = System.getProperty("java.library.path");
System.out.println("java.library.path = " + libPath);

GnomeKeyring gk = new GnomeKeyring("SIP Communicator");

System.out.println("Keyring available? " + gk.isKeyRingAvailable());
System.out.println("Keyrings: ");
for (String s : gk.getKeyRingNames()) {
System.out.println(s);
}
if (gk.storePassword("dmitri@msn.com", "secret")) {
System.out.println("Password stored OK");
}
System.out.println("Pass found: " + gk.loadPassword("dmitri@msn.com"));
if (gk.deletePassword("dmitri@msn.com")) {
System.out.println("Password deleted OK");
}
}

}


Pretty simple, it loads the custom shared library gk-native and calls native methods.

The C part is bigger:


#include <jni.h>
#include <stdio.h>
#include <gnome-keyring.h>
#include <glib.h>
#include <libintl.h>
#include "GnomeKeyring.h"

JNIEXPORT jstring JNICALL Java_example_GnomeKeyring_loadPassword
(JNIEnv *env, jobject obj, jstring jaccount) {
gchar *password;
jstring jpass = NULL;
const char *account = (*env)->GetStringUTFChars(env, jaccount, 0);
GnomeKeyringResult result = gnome_keyring_find_password_sync(GNOME_KEYRING_NETWORK_PASSWORD,
&password,
"user", account,
/* Can put other properties here that
* GNOME_KEYRING_NETWORK_PASSWORD schema supports.
*/
NULL
);
(*env)->ReleaseStringUTFChars(env, jaccount, account);

if (result == GNOME_KEYRING_RESULT_OK) {
jpass = (*env)->NewStringUTF(env, password);
}

gnome_keyring_free_password(password);
return jpass;
}

JNIEXPORT jboolean JNICALL Java_example_GnomeKeyring_deletePassword
(JNIEnv *env, jobject obj, jstring jaccount) {
const char *account = (*env)->GetStringUTFChars(env, jaccount, 0);
GnomeKeyringResult result = gnome_keyring_delete_password_sync(GNOME_KEYRING_NETWORK_PASSWORD,
"user", account,
/* Can put other properties here that
* GNOME_KEYRING_NETWORK_PASSWORD schema supports.
*/
NULL
);
(*env)->ReleaseStringUTFChars(env, jaccount, account);

return result == GNOME_KEYRING_RESULT_OK ? TRUE : FALSE;
}

JNIEXPORT jboolean JNICALL Java_example_GnomeKeyring_storePassword
(JNIEnv *env, jobject obj, jstring jaccount, jstring jpass) {
const char *account = (*env)->GetStringUTFChars(env, jaccount, 0);
const char *pass = (*env)->GetStringUTFChars(env, jpass, 0);
GnomeKeyringResult result = gnome_keyring_store_password_sync(GNOME_KEYRING_NETWORK_PASSWORD,
NULL,
"My Password",
pass,
"user", account,
/* Can put other properties here that
* GNOME_KEYRING_NETWORK_PASSWORD schema supports.
*/
NULL
);
(*env)->ReleaseStringUTFChars(env, jaccount, account);
(*env)->ReleaseStringUTFChars(env, jpass, pass);

return result == GNOME_KEYRING_RESULT_OK ? TRUE : FALSE;
}

JNIEXPORT void JNICALL Java_example_GnomeKeyring_setApplicationName
(JNIEnv *env, jobject obj, jstring name) {
const char *str = (*env)->GetStringUTFChars(env, name, 0);
g_set_application_name(str);
(*env)->ReleaseStringUTFChars(env, name, str);
}

JNIEXPORT jobjectArray JNICALL Java_example_GnomeKeyring_getKeyRingNames
(JNIEnv *env, jobject obj)
{
int i;
char *keyring;
GList *keyrings, *l;
jstring string = NULL;

gnome_keyring_list_keyring_names_sync (&keyrings);
guint len = g_list_length(keyrings);

jclass stringClass = (*env)->FindClass(env,"Ljava/lang/String;");
jobjectArray stringArray = (*env)->NewObjectArray(env, len, stringClass, NULL);
for (l = keyrings, i = 0; l != NULL; l = l->next, i++) {
keyring = l->data;
string = (*env)->NewStringUTF(env, keyring);
(*env)->SetObjectArrayElement(env, stringArray, i, string);
(*env)->DeleteLocalRef(env, string);
}
gnome_keyring_string_list_free(keyrings);

return stringArray;
}

JNIEXPORT jboolean JNICALL Java_example_GnomeKeyring_isKeyRingAvailable
(JNIEnv *env, jobject obj)
{
if(gnome_keyring_is_available()) {
return TRUE;
}
return FALSE;
}


Here I used only "user" property of the GNOME_KEYRING_NETWORK_PASSWORD schema, but other can be used as well, or even new schemas can be created.
Finally the makefile to put it all together:

BIN=bin
PAK=example
CSRC=src/$(PAK)/native

JFILE=GnomeKeyring
CFILE=$(JFILE).c
HFILE=$(JFILE).h
OBJ=$(JFILE).o

LIB=libgk-native.so

all : $(BIN)/$(LIB)

$(BIN)/$(LIB) : $(BIN)/$(OBJ)
gcc -shared -o $(BIN)/$(LIB) $(BIN)/$(OBJ) /usr/lib/libgnome-keyring.so

$(BIN)/$(OBJ) : $(CSRC)/$(CFILE)
gcc -I/usr/lib/jvm/java-6-sun/include -I/usr/lib/jvm/java-6-sun/include/linux -I/usr/include/gnome-keyring-1 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -c -fpic $(CSRC)/$(CFILE) -o $(BIN)/$(OBJ)

header : $(BIN)/$(PAK)/$(JFILE).class
javah -jni -classpath bin -o $(CSRC)/$(HFILE) $(PAK).$(JFILE)

run:
java -cp $(BIN) -Djava.library.path=$(BIN) $(PAK).$(JFILE)
clean :
rm $(BIN)/$(OBJ)
rm $(BIN)/$(LIB)



So now I can do everything that's required with GnomeKeyring, next I will try to think of a way to integrate it all into SC.

SIP Communicator GSoC 2010 Application Part 3

The JNI Way

First of all I started researching Seahorse and it's DBUS API. I was hoping that it's possible to use the java bindings for dbus to store and retrieve passwords but then I realized that in fact it was only possible to store keys with Seahorse dbus and not passwords, so the java dbus api was of no use. I wasted a lot of time on all of this.
My only option was to use libgnome-keyring. Because it has only C and python bindings, I had to use it via JNI. Not knowing anything about Java Native Interface, I started researching again and after a lot of googling and experimenting finally came up with a custom shared library (my C file with a function that lists all keyrings) linked together with libgnome-keyring, and a small java class that loads it and calls the function. It took time and patience but it works - java can talk to GnomeKeyring! Next I'll try password store and retrieve.

Friday 2 April 2010

SIP Communicator GSoC 2010 Application Part 2

The Problem
This part describes what the project idea is all about and what needs to be done.
The thing with security is that a system is secure only as much as it's weakest link. That weakest link happens to be the password most of the time. Not only can it be easy to guess, even worst, it can be SEEN by simply knowing a thing or two about how the system works. SIP Communicator (SC) stores it's passwords insecurely in a Base64-encoded string inside ~/.sip-communicator/sip-communicator.properties. Just grep for PASSWORD=, run base64 -d on that value and you're done, you have the password for the account. Sure, only the user can read files in his home directory. But insecure still and good software needs good security.
If we go deep into the code then here's what we have (mostly taken from my letter to SC dev list):

AccountManager loads the accounts on start-up in a separate thread. It's doLoadStoredAccounts() method is called for all supported
ProtocolProviderFactory implementations, and this method (besides other things) decodes the stored password and puts it in a map along with other properties; the map is then passed into the ProtocolProviderFactory.loadAccount() is done for all accounts for the given protocol. Now, inside ProtocolProviderFactory.loadAccount, a protocol specific AccountID is created from the passed-in properties map.
After that, things get interesting: in the same method ServiceRegistration object is created with the call bundleContext.registerService(...). This triggers inside a new thread a call chain from ProtocolProviderFactory*Impl.register() (which has our created AccountID with the password inside) to ProtocolProviderFactory.loadPassword(bundleContext, accountID) which does the same thing as doLoadStoredAccounts() - loads and decodes the password.
Actually, it seems that doLoadStoredAccounts() password decoding is some old code that should be deleted, I commented it out and it ran ok. So the things that needs to be refactored to support third party password storage utilities is ProtocolProviderFactory's loadPassword and storePassword methods.

Of course we still must preserve the current plaintext storage because not everyone runs GnomeKeyring/Kwallet/other utility, but we still must have a system that can identify what password storage utility is available and use it or fall back to the default plaintext base64 storage.

SIP Communicator GSoC 2010 Application Part 1

The Overview

This year I decided to apply for Google Summer of Code and the organization I chose is SIP Communicator. It's a really good project with a great development team that is basically an universal IM that supports everything from MSN to IRC and Facebook. It's written in Java and uses Apache Felix OSGi implementation.
The project idea I want to work on is GnomeKeyring (since I use Gnome) for password storage. I've always been interested in security and this semester I'm taking a really good course on applied cryptography using Java, so it's a perfect thing for me.
All of my application related things will be in this blog because I find it more convenient to just give a link that points here and keep everything in one place. If I get accepted, then I will continue to post on my progress here.
In the next posts, I'm going to present the technical details of my application, stay tuned.

Thursday 1 April 2010

Basic keytool commands

Keytool is a java utility for managing keys and certificates that comes with JDK. It can generate public/private key pairs, generate certificate requests, import trusted certificates and much more. Keytool keeps all of this stuff in a keystore file and every entry (key or certificate) has a unique name or alias.
I has to make a keystore that contains a certificate chain for testing purposes, so here's what i did:

Generate self-signed PrivateKeyEntry with an alias "store". This will ask for password and DN information and create a keystore file called keystore.store
keytool -genkey -keyalg "RSA" -alias store -keystore keystore.store

Generate a cert request that can be signed by the CA
keytool -certreq -v -alias store -file store.req -keystore keystore.store

Import root CA's cert (ca.pem) as a trusted cert into the keystore with an alias root-ca
keytool -import -v -trustcacerts -alias root-ca -file ca.pem -keystore keystore.store

Import subca's cert with an alias sub-ca. This is optional if you don't have one. Make sure subca.pem starts with -----BEGIN CERTIFICATE-----
keytool -import -v -trustcacerts -alias sub-ca -file subca.pem -keystore keystore.store

Import your signed cert (made from your cert request), notice that the alias is the same as the generated key's alias. Keytool understands that this cert is for the generated key and can construct the certificate chain.
keytool -import -v -alias store -file store.crt -keystore keystore.store

Finally list keystore's entries. You can add -v for more information about the entries.
keytool -list -keystore keystore.store

More information:
http://java.sun.com/javase/6/docs/technotes/tools/solaris/keytool.html
http://www.globalsign.com/support/code-signing/codesign_sunjava.html
http://www.informit.com/articles/article.aspx?p=407886