From 4b558a53f61005b0ca49665d2da92303f6e14872 Mon Sep 17 00:00:00 2001
From: Jonathan Beck <jonabeck@gmail.com>
Date: Mon, 4 Aug 2008 22:31:43 +0200
Subject: [PATCH] Store certificates and private keys as PEM files instead of
 storing them in config file. Added functions to generate proper pairing
 request.

Signed-off-by: Matt Colyer <matt@colyer.name>
---
 src/initconf.c |  12 +---
 src/lockdown.c |  35 +++++++-----
 src/plist.c    |  32 ++++++++++-
 src/plist.h    |   1 +
 src/userpref.c | 148 ++++++++++++++++++++++---------------------------
 src/userpref.h |  29 +++++-----
 6 files changed, 136 insertions(+), 121 deletions(-)

diff --git a/src/initconf.c b/src/initconf.c
index 7d6aa28..960fb6b 100644
--- a/src/initconf.c
+++ b/src/initconf.c
@@ -93,25 +93,15 @@ int main(int argc, char *argv[]) {
 	gnutls_x509_crt_export (root_cert, GNUTLS_X509_FMT_PEM,  root_cert_pem.data, &root_cert_pem.size);
 	gnutls_x509_crt_export (host_cert, GNUTLS_X509_FMT_PEM,  host_cert_pem.data, &host_cert_pem.size);
 
-	/* encode in base64 for storage */
-	char* root_key_b64 = g_base64_encode (root_key_pem.data,root_key_pem.size);
-	char* host_key_b64 = g_base64_encode (host_key_pem.data,host_key_pem.size);
-
-	char* root_cert_b64 = g_base64_encode (root_cert_pem.data,root_cert_pem.size);
-	char* host_cert_b64 = g_base64_encode (host_cert_pem.data,host_cert_pem.size);
 
 	/* store values in config file */
 	
-	init_config_file(host_id, root_key_b64, host_key_b64, root_cert_b64, host_cert_b64);
+	init_config_file(host_id, &root_key_pem, &host_key_pem, &root_cert_pem, &host_cert_pem);
 
 	gnutls_free(root_key_pem.data);
 	gnutls_free(host_key_pem.data);
 	gnutls_free(root_cert_pem.data);
 	gnutls_free(host_cert_pem.data);
-	g_free(root_key_b64);
-	g_free(host_key_b64);
-	g_free(root_cert_b64);
-	g_free(host_cert_b64);
 
 	return 0;
 }
diff --git a/src/lockdown.c b/src/lockdown.c
index d5149a9..095b2b4 100644
--- a/src/lockdown.c
+++ b/src/lockdown.c
@@ -263,8 +263,8 @@ int lockdownd_pair_device(lockdownd_client *control, char *public_key_b64, char
 
 	/* Setup Pair request plist */
 	dict = add_child_to_plist(plist, "dict", "\n", NULL, 0);
-	add_key_str_dict_element(plist, dict, "Key", "PairRecord", 1);
-	dictRecord = add_child_to_plist(plist, "dict", "\n", NULL, 1);
+	dictRecord = add_key_dict_node(plist, dict, "PairRecord", "\n", 1);
+	//dictRecord = add_child_to_plist(plist, "dict", "\n", NULL, 1);
 	add_key_data_dict_element(plist, dictRecord, "DeviceCertificate", device_cert_b64, 2);
 	add_key_data_dict_element(plist, dictRecord, "HostCertificate", host_cert_b64, 2);
 	add_key_str_dict_element(plist, dictRecord, "HostID", host_id, 2);
@@ -273,6 +273,8 @@ int lockdownd_pair_device(lockdownd_client *control, char *public_key_b64, char
 
 	xmlDocDumpMemory(plist, (xmlChar**)&XML_content, &length);
 
+	printf("XML Pairing request : %s\n",XML_content);
+
 	/* send to iPhone */
 	bytes = lockdownd_send(control, XML_content, length);
 	
@@ -366,34 +368,34 @@ int lockdownd_gen_pair_cert(char *public_key_b64, char **device_cert_b64, char *
 		gnutls_datum_t essentially_null = {strdup("abababababababab"), strlen("abababababababab")};
 	
 		gnutls_x509_privkey_t fake_privkey, root_privkey;
-		gnutls_x509_crt_t dev_cert, root_cert;
+		gnutls_x509_crt_t dev_cert, root_cert, host_cert;
 	
 		gnutls_x509_privkey_init(&fake_privkey);
 		gnutls_x509_crt_init(&dev_cert);
 		gnutls_x509_crt_init(&root_cert);
+		gnutls_x509_crt_init(&host_cert);
 
 		if ( GNUTLS_E_SUCCESS == gnutls_x509_privkey_import_rsa_raw(fake_privkey, &modulus, &exponent, &essentially_null, &essentially_null, &essentially_null, &essentially_null) ) {
 		
 			gnutls_x509_privkey_init(&root_privkey);
 			
-			/* get certificate stored in config */
-			*host_cert_b64 = get_host_certificate();
-			*root_cert_b64 = get_root_certificate();
-
+			/* get root cert */
 			gnutls_datum_t pem_root_cert = {NULL, 0};
-			pem_root_cert.data = g_base64_decode (*root_cert_b64, &pem_root_cert.size);
-
+			ret = get_root_certificate(&pem_root_cert);
 			ret = gnutls_x509_crt_import (root_cert, &pem_root_cert, GNUTLS_X509_FMT_PEM);
-			gnutls_free(pem_root_cert.data);
+			
 
+			/* get host cert */
+			gnutls_datum_t pem_host_cert = {NULL, 0};
+			ret = get_host_certificate(&pem_host_cert);
+			ret = gnutls_x509_crt_import (host_cert, &pem_host_cert, GNUTLS_X509_FMT_PEM);
+			
 
 			/* get root private key */
-			char *root_priv_b64 = get_root_private_key();
 			gnutls_datum_t pem_root_priv = {NULL, 0};
-			pem_root_priv.data = g_base64_decode (root_priv_b64, &pem_root_priv.size);
-
+			ret = get_root_private_key(&pem_root_priv);
 			ret = gnutls_x509_privkey_import (root_privkey, &pem_root_priv, GNUTLS_X509_FMT_PEM);
-			gnutls_free(pem_root_priv.data);
+			
 
 			/* generate device certificate */
 			
@@ -418,8 +420,13 @@ int lockdownd_gen_pair_cert(char *public_key_b64, char **device_cert_b64, char *
 
 				/* now encode certificates for output */
 				*device_cert_b64 = g_base64_encode(dev_pem.data, dev_pem.size);
+				*host_cert_b64 = g_base64_encode(pem_host_cert.data, pem_host_cert.size);
+				*root_cert_b64 = g_base64_encode(pem_root_cert.data, pem_root_cert.size);
 				ret = 1;
 			}
+			gnutls_free(pem_root_priv.data);
+			gnutls_free(pem_root_cert.data);
+			gnutls_free(pem_host_cert.data);
 		}
 	}
 
diff --git a/src/plist.c b/src/plist.c
index 2d2a832..73cdffc 100644
--- a/src/plist.c
+++ b/src/plist.c
@@ -29,6 +29,29 @@ const char *plist_base = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
 <plist version=\"1.0\">\n\
 </plist>\0";
 
+char* format_string(char* buf, int cols, int depth)
+{
+	int colw = depth + cols + 1; //new buf cols width
+	int len = strlen(buf);
+	//int nlines = ceil((float)len / (float)cols);
+	int nlines = len / cols + 1;
+ 	char* new_buf = (char*)malloc(nlines * colw + depth + 1);
+	int i = 0;
+	int j = 0;
+	for (i = 0; i < nlines; i++){
+		new_buf[i * colw] = '\n';
+		for (j = 0; j < depth; j++)
+			new_buf[i * colw + 1 + j] = '\t';
+		memcpy(new_buf + i * colw + 1 + depth, buf + i * cols, cols);
+	}
+	new_buf[len+(1+depth)*nlines] = '\n';
+	for (j = 0; j < depth; j++)
+		new_buf[len+(1+depth)*nlines + 1 + j] = '\t';
+	new_buf[len+(1+depth)*nlines+depth+1] = '\0';
+	free(buf);
+	return new_buf;
+}
+
 xmlDocPtr new_plist() {
 	char *plist = strdup(plist_base);
 	xmlDocPtr plist_xml = xmlReadMemory(plist, strlen(plist), NULL, NULL, 0);
@@ -62,10 +85,17 @@ xmlNode *add_key_str_dict_element(xmlDocPtr plist, xmlNode *dict, const char *ke
 	return keyPtr;
 }
 
+xmlNode *add_key_dict_node(xmlDocPtr plist, xmlNode *dict, const char *key, const char *value, int depth) {
+	xmlNode *child;
+	add_child_to_plist(plist, "key", key, dict, depth);
+	child = add_child_to_plist(plist, "dict", value, dict, depth);
+	return child;
+}
+
 xmlNode *add_key_data_dict_element(xmlDocPtr plist, xmlNode *dict, const char *key, const char *value, int depth) {
 	xmlNode *keyPtr;
 	keyPtr = add_child_to_plist(plist, "key", key, dict, depth);
-	add_child_to_plist(plist, "data", value, dict, depth);
+	add_child_to_plist(plist, "data", format_string(value, 60, depth), dict, depth);
 	return keyPtr;
 }
 
diff --git a/src/plist.h b/src/plist.h
index 64ff4d3..a2f558e 100644
--- a/src/plist.h
+++ b/src/plist.h
@@ -25,6 +25,7 @@
 #include <libxml/parser.h>
 #include <libxml/tree.h>
 
+xmlNode *add_key_dict_node(xmlDocPtr plist, xmlNode *dict, const char *key, const char *value, int depth);
 xmlNode *add_key_str_dict_element(xmlDocPtr plist, xmlNode *dict, const char *key, const char *value, int depth);
 xmlNode *add_key_data_dict_element(xmlDocPtr plist, xmlNode *dict, const char *key, const char *value, int depth);
 xmlNode *add_child_to_plist(xmlDocPtr plist, const char *name, const char *content, xmlNode *to_node, int depth);
diff --git a/src/userpref.c b/src/userpref.c
index f93cff4..12ff8f3 100644
--- a/src/userpref.c
+++ b/src/userpref.c
@@ -24,9 +24,16 @@
 #include <string.h>
 #include "userpref.h"
 
+
 #define LIBIPHONE_CONF_DIR  "libiphone"
 #define LIBIPHONE_CONF_FILE "libiphonerc"
 
+#define LIBIPHONE_ROOT_PRIVKEY  "RootPrivateKey.pem"
+#define LIBIPHONE_HOST_PRIVKEY  "HostPrivateKey.pem"
+#define LIBIPHONE_ROOT_CERTIF  "RootCertificate.pem"
+#define LIBIPHONE_HOST_CERTIF  "HostCertificate.pem"
+
+
 extern int debug;
 
 inline void create_config_dir() {
@@ -145,99 +152,59 @@ int store_device_public_key(char* public_key)
 	return 1;
 }
 
-
-char* get_root_private_key()
+int read_file_in_confdir(char* file, gnutls_datum_t* data)
 {
-	char* private_key = NULL;
-
-	/* first get config file */
-	gchar* config_file = g_build_path(G_DIR_SEPARATOR_S,  g_get_user_config_dir(), LIBIPHONE_CONF_DIR,  LIBIPHONE_CONF_FILE, NULL);
-	if (g_file_test(config_file, (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))) {
-
-		/* now parse file to get knwon devices list */
-		GKeyFile* key_file = g_key_file_new ();
-		if( g_key_file_load_from_file (key_file, config_file, G_KEY_FILE_KEEP_COMMENTS, NULL) ) {
+	if (NULL == file || NULL == data)
+		return 0;
 
-			gchar* loc_private_key = g_key_file_get_value(key_file, "Global", "RootPrivateKey", NULL);
-			if (loc_private_key)
-				private_key = strdup((char*)loc_private_key);
-			g_free(loc_private_key);
-		}
-		g_key_file_free(key_file);
+	gchar* filepath = g_build_path(G_DIR_SEPARATOR_S,  g_get_user_config_dir(), LIBIPHONE_CONF_DIR,  file, NULL);
+	if (g_file_test(filepath, (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))) {
+
+		FILE * pFile;
+		long lSize;
+		
+		pFile = fopen ( filepath , "rb" );
+		if (pFile==NULL)
+			return 0;
+
+		fseek (pFile , 0 , SEEK_END);
+		data->size = ftell (pFile);
+		rewind (pFile);
+		
+		data->data = (char*)gnutls_malloc(data->size);
+		if (data->data == NULL)
+			return 0;
+		
+		// copy the file into the buffer:
+		fread (data->data,1,data->size,pFile);	
+		fclose (pFile);
 	}
-	return private_key;
+	return 1;
 }
 
-char* get_host_private_key()
+int get_root_private_key(gnutls_datum_t* root_privkey)
 {
-	char* private_key = NULL;
-
-	/* first get config file */
-	gchar* config_file = g_build_path(G_DIR_SEPARATOR_S,  g_get_user_config_dir(), LIBIPHONE_CONF_DIR,  LIBIPHONE_CONF_FILE, NULL);
-	if (g_file_test(config_file, (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))) {
-
-		/* now parse file to get knwon devices list */
-		GKeyFile* key_file = g_key_file_new ();
-		if( g_key_file_load_from_file (key_file, config_file, G_KEY_FILE_KEEP_COMMENTS, NULL) ) {
-
-			gchar* loc_private_key = g_key_file_get_value(key_file, "Global", "HostPrivateKey", NULL);
-			if (loc_private_key)
-				private_key = strdup((char*)loc_private_key);
-			g_free(loc_private_key);
-		}
-		g_key_file_free(key_file);
-	}
-	return private_key;
+	return read_file_in_confdir(LIBIPHONE_ROOT_PRIVKEY, root_privkey);
 }
 
-
-char* get_root_certificate()
+int get_host_private_key(gnutls_datum_t* host_privkey)
 {
-	char* cert = NULL;
-
-	/* first get config file */
-	gchar* config_file = g_build_path(G_DIR_SEPARATOR_S,  g_get_user_config_dir(), LIBIPHONE_CONF_DIR,  LIBIPHONE_CONF_FILE, NULL);
-	if (g_file_test(config_file, (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))) {
-
-		/* now parse file to get knwon devices list */
-		GKeyFile* key_file = g_key_file_new ();
-		if( g_key_file_load_from_file (key_file, config_file, G_KEY_FILE_KEEP_COMMENTS, NULL) ) {
-
-			gchar* loc_cert = g_key_file_get_value(key_file, "Global", "RootCertificate", NULL);
-			if (loc_cert)
-				cert = strdup((char*)loc_cert);
-			g_free(loc_cert);
-		}
-		g_key_file_free(key_file);
-	}
-	return cert;
+	return read_file_in_confdir(LIBIPHONE_HOST_PRIVKEY, host_privkey);
 }
 
-char* get_host_certificate()
+int get_root_certificate(gnutls_datum_t* root_cert)
 {
-	char* cert = NULL;
-
-	/* first get config file */
-	gchar* config_file = g_build_path(G_DIR_SEPARATOR_S,  g_get_user_config_dir(), LIBIPHONE_CONF_DIR,  LIBIPHONE_CONF_FILE, NULL);
-	if (g_file_test(config_file, (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))) {
-
-		/* now parse file to get knwon devices list */
-		GKeyFile* key_file = g_key_file_new ();
-		if( g_key_file_load_from_file (key_file, config_file, G_KEY_FILE_KEEP_COMMENTS, NULL) ) {
+	return read_file_in_confdir(LIBIPHONE_ROOT_CERTIF, root_cert);
+}
 
-			gchar* loc_cert = g_key_file_get_value(key_file, "Global", "HostCertificate", NULL);
-			if (loc_cert)
-				cert = strdup((char*)loc_cert);
-			g_free(loc_cert);
-		}
-		g_key_file_free(key_file);
-	}
-	return cert;
+int get_host_certificate(gnutls_datum_t* host_cert)
+{
+	return read_file_in_confdir(LIBIPHONE_HOST_CERTIF, host_cert);
 }
 
-int init_config_file(char* host_id, char* root_private_key, char* host_private_key, char* root_cert, char* host_cert)
+int init_config_file(char* host_id, gnutls_datum_t* root_key, gnutls_datum_t* host_key, gnutls_datum_t* root_cert, gnutls_datum_t* host_cert)
 {
-	if (!host_id || !root_private_key || !host_private_key || !root_cert || !host_cert)
+	if (!host_id || !root_key || !host_key || !root_cert || !host_cert)
 		return 0;
 
 	gchar* config_file =  g_build_path(G_DIR_SEPARATOR_S,  g_get_user_config_dir(), LIBIPHONE_CONF_DIR,  LIBIPHONE_CONF_FILE, NULL);
@@ -249,10 +216,6 @@ int init_config_file(char* host_id, char* root_private_key, char* host_private_k
 
 	/* store in config file */
 	g_key_file_set_value (key_file, "Global", "HostID", host_id);
-	g_key_file_set_value (key_file, "Global", "RootPrivateKey", root_private_key);
-	g_key_file_set_value (key_file, "Global", "HostPrivateKey", host_private_key);
-	g_key_file_set_value (key_file, "Global", "RootCertificate", root_cert);
-	g_key_file_set_value (key_file, "Global", "HostCertificate", host_cert);
 
 	/* write config file on disk */
 	gsize length;
@@ -263,5 +226,28 @@ int init_config_file(char* host_id, char* root_private_key, char* host_private_k
 
 	g_key_file_free(key_file);
 
+	//now write keys and certifs to disk
+	FILE * pFile;
+	gchar* pem;
+	pem = g_build_path(G_DIR_SEPARATOR_S,  g_get_user_config_dir(), LIBIPHONE_CONF_DIR, LIBIPHONE_ROOT_PRIVKEY, NULL);
+	pFile = fopen ( pem , "wb" );
+	fwrite ( root_key->data, 1 , root_key->size , pFile );
+	fclose (pFile);
+
+	pem = g_build_path(G_DIR_SEPARATOR_S,  g_get_user_config_dir(), LIBIPHONE_CONF_DIR, LIBIPHONE_HOST_PRIVKEY, NULL);
+	pFile = fopen ( pem , "wb" );
+	fwrite ( host_key->data, 1 , host_key->size , pFile );
+	fclose (pFile);
+
+	pem = g_build_path(G_DIR_SEPARATOR_S,  g_get_user_config_dir(), LIBIPHONE_CONF_DIR, LIBIPHONE_ROOT_CERTIF, NULL);
+	pFile = fopen ( pem , "wb" );
+	fwrite ( root_cert->data, 1 , root_cert->size , pFile );
+	fclose (pFile);
+
+	pem = g_build_path(G_DIR_SEPARATOR_S,  g_get_user_config_dir(), LIBIPHONE_CONF_DIR, LIBIPHONE_HOST_CERTIF, NULL);
+	pFile = fopen ( pem , "wb" );
+	fwrite ( host_cert->data, 1 , host_cert->size , pFile );
+	fclose (pFile);
+
 	return 1;
 }
diff --git a/src/userpref.h b/src/userpref.h
index cef0bed..441c7be 100644
--- a/src/userpref.h
+++ b/src/userpref.h
@@ -22,6 +22,7 @@
 #ifndef USERPREF_H
 #define USERPREF_H
 
+#include <gnutls/gnutls.h>
 /**
 * \fn char* get_host_id() 
 *  method to get user's HostID. Caller must free returned buffer.
@@ -43,34 +44,34 @@ int is_device_known(char* public_key);
 int store_device_public_key(char* public_key);
 
 /**
-* \fn char* get_root_private_key()
-* \return RootPrivateKey if exists. Returns NULL otherwise.
+* \fn int get_root_private_key(gnutls_datum_t* root_privkey)
+* \return 1 if everything went well. Returns 0 otherwise.
 */
-char* get_root_private_key();
+int get_root_private_key(gnutls_datum_t* root_privkey);
 
 /**
-* \fn char* get_host_private_key()
-* \return HostPrivateKey if exists. Returns NULL otherwise.
+* \fn int get_host_private_key(gnutls_datum_t* host_privkey)
+* \return 1 if everything went well. Returns 0 otherwise.
 */
-char* get_host_private_key();
+int get_host_private_key(gnutls_datum_t* host_privkey);
 
 /**
-* \fn char* get_root_certificate()
-* \return RootCertificate if exists. Returns NULL otherwise.
+* \fn int get_root_certificate(gnutls_datum_t* root_cert)
+* \return 1 if everything went well. Returns 0 otherwise.
 */
-char* get_root_certificate();
+int get_root_certificate(gnutls_datum_t* root_cert);
 
 /**
-* \fn char* get_host_certificate()
-* \return HostCertificate if exists. Returns NULL otherwise.
+* \fn int get_host_certificate(gnutls_datum_t* host_cert)
+* \return 1 if everything went well. Returns 0 otherwise.
 */
-char* get_host_certificate();
+int get_host_certificate(gnutls_datum_t* host_cert);
 
 /**
-* \fn int init_config_file(char* host_id, char* root_private_key, char* host_private_key, char* root_cert, char* host_cert)
+* \fn int init_config_file(char* host_id, gnutls_datum_t* root_key, gnutls_datum_t* host_key, gnutls_datum_t* root_cert, gnutls_datum_t* host_cert)
 * setup a brand new config file.
 * \return 1 if everything went well. Returns 0 otherwise.
 */
-int init_config_file(char* host_id, char* root_private_key, char* host_private_key, char* root_cert, char* host_cert);
+int init_config_file(char* host_id, gnutls_datum_t* root_key, gnutls_datum_t* host_key, gnutls_datum_t* root_cert, gnutls_datum_t* host_cert);
 #endif
 
-- 
2.18.1