summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README22
-rw-r--r--configure.ac4
-rw-r--r--src/Makefile.am8
-rw-r--r--src/initconf.c213
-rw-r--r--src/lockdown.c160
-rw-r--r--src/lockdown.h8
-rw-r--r--src/userpref.c324
-rw-r--r--src/userpref.h50
8 files changed, 373 insertions, 416 deletions
diff --git a/README b/README
index 5bc5c5e..955da4e 100644
--- a/README
+++ b/README
@@ -7,10 +7,11 @@ For:
7 7
8You must have: 8You must have:
9 libgnutls-dev 9 libgnutls-dev
10 libgcrypt-dev
10 libusb-dev 11 libusb-dev
11 libfuse-dev (and the associated kernel modules) 12 libfuse-dev (and the associated kernel modules)
12 libglib2.0-dev 13 libglib2.0-dev
13 libxml2-dev 14 libplist-dev
14 make 15 make
15 autoheader 16 autoheader
16 automake 17 automake
@@ -22,31 +23,12 @@ To compile run:
22 ./configure 23 ./configure
23 make 24 make
24 sudo make install # (if you want to install it into your system directories) 25 sudo make install # (if you want to install it into your system directories)
25 libiphone-initconf # (as the user you intend to user the library)
26 26
27On Ubuntu/Debian, you can do: 27On Ubuntu/Debian, you can do:
28 sudo apt-get install build-essential automake autoconf \ 28 sudo apt-get install build-essential automake autoconf \
29 libgnutls-dev libusb-dev libfuse-dev libglib2.0-dev libxml2-dev \ 29 libgnutls-dev libusb-dev libfuse-dev libglib2.0-dev libxml2-dev \
30 libreadline5-dev 30 libreadline5-dev
31 31
32USAGE
33================================================================================
34
35Now comes the fun bit!
36
37== Generating keys ==
38
39IMPORTANT: Before using the library you must run "libiphone-initconf"
40as your own user (not root). It will generate keys and a host id for your
41system to be able to communicate with 'lockdownd' on the iPhone.
42
43It will probably take 5-10 minutes, but thankfully only needs to be
44run _once_. It MUST be run otherwise communication will not work:
45
46 libiphone-initconf
47
48The generated keys are saved in '~/.config/libiphone/' in your home directory.
49
50== Who/what/where? == 32== Who/what/where? ==
51 33
52wiki: 34wiki:
diff --git a/configure.ac b/configure.ac
index 29f9be3..e2f98c7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -25,11 +25,11 @@ PKG_CHECK_MODULES(libglib2, glib-2.0 >= 2.14.1)
25PKG_CHECK_MODULES(libgthread2, gthread-2.0 >= 2.14.1) 25PKG_CHECK_MODULES(libgthread2, gthread-2.0 >= 2.14.1)
26PKG_CHECK_MODULES(libgnutls, gnutls >= 1.6.3 gnutls <= 2.5.0 ) 26PKG_CHECK_MODULES(libgnutls, gnutls >= 1.6.3 gnutls <= 2.5.0 )
27PKG_CHECK_MODULES(libtasn1, libtasn1 >= 1.1) 27PKG_CHECK_MODULES(libtasn1, libtasn1 >= 1.1)
28PKG_CHECK_MODULES(libplist, libplist >= 0.1.0) 28PKG_CHECK_MODULES(libplist, libplist >= 0.10)
29 29
30# Checks for header files. 30# Checks for header files.
31AC_HEADER_STDC 31AC_HEADER_STDC
32AC_CHECK_HEADERS([arpa/inet.h stdint.h stdlib.h string.h]) 32AC_CHECK_HEADERS([arpa/inet.h stdint.h stdlib.h string.h gcrypt.h])
33 33
34# Checks for typedefs, structures, and compiler characteristics. 34# Checks for typedefs, structures, and compiler characteristics.
35AC_C_CONST 35AC_C_CONST
diff --git a/src/Makefile.am b/src/Makefile.am
index 71667ae..a10254c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -3,13 +3,5 @@ INCLUDES = -I$(top_srcdir)/include
3AM_CFLAGS = $(GLOBAL_CFLAGS) $(libusb_CFLAGS) $(libglib2_CFLAGS) $(libgnutls_CFLAGS) $(libtasn1_CFLAGS) $(libgthread2_CFLAGS) $(libplist_CFLAGS) $(LFS_CFLAGS) 3AM_CFLAGS = $(GLOBAL_CFLAGS) $(libusb_CFLAGS) $(libglib2_CFLAGS) $(libgnutls_CFLAGS) $(libtasn1_CFLAGS) $(libgthread2_CFLAGS) $(libplist_CFLAGS) $(LFS_CFLAGS)
4AM_LDFLAGS = $(libusb_LIBS) $(libglib2_LIBS) $(libgnutls_LIBS) $(libtasn1_LIBS) $(libgthread2_LIBS) $(libplist_LIBS) 4AM_LDFLAGS = $(libusb_LIBS) $(libglib2_LIBS) $(libgnutls_LIBS) $(libtasn1_LIBS) $(libgthread2_LIBS) $(libplist_LIBS)
5 5
6bin_PROGRAMS = libiphone-initconf
7
8
9libiphone_initconf_SOURCES = initconf.c userpref.c utils.c
10libiphone_initconf_CFLAGS = $(libgthread2_CFLAGS) $(AM_CFLAGS)
11libiphone_initconf_LDFLAGS = $(libgthread2_LIBS) $(AM_LDFLAGS)
12
13
14lib_LTLIBRARIES = libiphone.la 6lib_LTLIBRARIES = libiphone.la
15libiphone_la_SOURCES = usbmux.c iphone.c lockdown.c AFC.c NotificationProxy.c userpref.c utils.c MobileSync.c 7libiphone_la_SOURCES = usbmux.c iphone.c lockdown.c AFC.c NotificationProxy.c userpref.c utils.c MobileSync.c
diff --git a/src/initconf.c b/src/initconf.c
deleted file mode 100644
index 538f344..0000000
--- a/src/initconf.c
+++ /dev/null
@@ -1,213 +0,0 @@
1/*
2 * userpref.c
3 * contains methods to access user specific certificates IDs and more.
4 *
5 * Copyright (c) 2008 Jonathan Beck All Rights Reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <gnutls/gnutls.h>
26#include <gnutls/x509.h>
27#include <glib.h>
28
29#include "libiphone/libiphone.h"
30#include "userpref.h"
31#include "utils.h"
32
33/** Generates a 2048 byte key, split into a function so that it can be run in a
34 * thread.
35 *
36 * @param key The pointer to the desired location of the new key.
37 */
38static void generate_key(gpointer key)
39{
40 gnutls_x509_privkey_generate(*((gnutls_x509_privkey_t *) key), GNUTLS_PK_RSA, 2048, 0);
41 g_thread_exit(0);
42}
43
44/** Simple function that generates a spinner until the mutex is released.
45 */
46static void progress_bar(gpointer mutex)
47{
48 const char *spinner = "|/-\\|/-\\";
49 int i = 0;
50
51 while (!g_static_mutex_trylock((GStaticMutex *) mutex)) {
52 usleep(500000);
53 printf("Generating key... %c\r", spinner[i++]);
54 fflush(stdout);
55 if (i > 8)
56 i = 0;
57 }
58 printf("Generating key... done\n");
59 g_thread_exit(0);
60}
61
62int get_rand(int min, int max)
63{
64 int retval = (rand() % (max - min)) + min;
65 return retval;
66}
67
68/** Generates a valid HostID (which is actually a UUID).
69 *
70 * @param A null terminated string containing a valid HostID.
71 */
72char *lockdownd_generate_hostid()
73{
74 char *hostid = (char *) malloc(sizeof(char) * 37); // HostID's are just UUID's, and UUID's are 36 characters long
75 const char *chars = "ABCDEF0123456789";
76 srand(time(NULL));
77 int i = 0;
78
79 for (i = 0; i < 36; i++) {
80 if (i == 8 || i == 13 || i == 18 || i == 23) {
81 hostid[i] = '-';
82 continue;
83 } else {
84 hostid[i] = chars[get_rand(0, 16)];
85 }
86 }
87 hostid[36] = '\0'; // make it a real string
88 return hostid;
89}
90
91int main(int argc, char *argv[])
92{
93 GThread *progress_thread, *key_thread;
94 GError *err;
95 static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
96 char *host_id = NULL;
97 gnutls_x509_privkey_t root_privkey;
98 gnutls_x509_privkey_t host_privkey;
99 gnutls_x509_crt_t root_cert;
100 gnutls_x509_crt_t host_cert;
101
102 iphone_set_debug(1);
103
104 // Create the thread
105 if (!g_thread_supported()) {
106 g_thread_init(NULL);
107 }
108 gnutls_global_init();
109
110 printf("This program generates keys required to connect with the iPhone\n");
111 printf("It only needs to be run ONCE.\n\n");
112 printf("Additionally it may take several minutes to run, please be patient.\n\n");
113
114
115 gnutls_x509_privkey_init(&root_privkey);
116 gnutls_x509_privkey_init(&host_privkey);
117
118 gnutls_x509_crt_init(&root_cert);
119 gnutls_x509_crt_init(&host_cert);
120
121 /* generate HostID */
122 host_id = lockdownd_generate_hostid();
123
124 /* generate root key */
125 g_static_mutex_lock(&mutex);
126 if ((key_thread = g_thread_create((GThreadFunc) generate_key, &root_privkey, TRUE, &err)) == NULL) {
127 printf("Thread create failed: %s!!\n", err->message);
128 g_error_free(err);
129 }
130 if ((progress_thread = g_thread_create((GThreadFunc) progress_bar, &mutex, TRUE, &err)) == NULL) {
131 printf("Thread create failed: %s!!\n", err->message);
132 g_error_free(err);
133 }
134 g_thread_join(key_thread);
135 g_static_mutex_unlock(&mutex);
136 g_thread_join(progress_thread);
137
138 /* generate host key */
139 g_static_mutex_init(&mutex);
140 g_static_mutex_lock(&mutex);
141 if ((key_thread = g_thread_create((GThreadFunc) generate_key, &host_privkey, TRUE, &err)) == NULL) {
142 printf("Thread create failed: %s!!\n", err->message);
143 g_error_free(err);
144 }
145 if ((progress_thread = g_thread_create((GThreadFunc) progress_bar, &mutex, TRUE, &err)) == NULL) {
146 printf("Thread create failed: %s!!\n", err->message);
147 g_error_free(err);
148 }
149 g_thread_join(key_thread);
150 g_static_mutex_unlock(&mutex);
151 g_thread_join(progress_thread);
152
153 /* generate certificates */
154 gnutls_x509_crt_set_key(root_cert, root_privkey);
155 gnutls_x509_crt_set_serial(root_cert, "\x00", 1);
156 gnutls_x509_crt_set_version(root_cert, 3);
157 gnutls_x509_crt_set_ca_status(root_cert, 1);
158 gnutls_x509_crt_set_activation_time(root_cert, time(NULL));
159 gnutls_x509_crt_set_expiration_time(root_cert, time(NULL) + (60 * 60 * 24 * 365 * 10));
160 gnutls_x509_crt_sign(root_cert, root_cert, root_privkey);
161
162
163 gnutls_x509_crt_set_key(host_cert, host_privkey);
164 gnutls_x509_crt_set_serial(host_cert, "\x00", 1);
165 gnutls_x509_crt_set_version(host_cert, 3);
166 gnutls_x509_crt_set_ca_status(host_cert, 0);
167 gnutls_x509_crt_set_key_usage(host_cert, GNUTLS_KEY_KEY_ENCIPHERMENT | GNUTLS_KEY_DIGITAL_SIGNATURE);
168 gnutls_x509_crt_set_activation_time(host_cert, time(NULL));
169 gnutls_x509_crt_set_expiration_time(host_cert, time(NULL) + (60 * 60 * 24 * 365 * 10));
170 gnutls_x509_crt_sign(host_cert, root_cert, root_privkey);
171
172
173 /* export to PEM format */
174 gnutls_datum_t root_key_pem = { NULL, 0 };
175 gnutls_datum_t host_key_pem = { NULL, 0 };
176
177 gnutls_x509_privkey_export(root_privkey, GNUTLS_X509_FMT_PEM, NULL, &root_key_pem.size);
178 gnutls_x509_privkey_export(host_privkey, GNUTLS_X509_FMT_PEM, NULL, &host_key_pem.size);
179
180 root_key_pem.data = gnutls_malloc(root_key_pem.size);
181 host_key_pem.data = gnutls_malloc(host_key_pem.size);
182
183 gnutls_x509_privkey_export(root_privkey, GNUTLS_X509_FMT_PEM, root_key_pem.data, &root_key_pem.size);
184 gnutls_x509_privkey_export(host_privkey, GNUTLS_X509_FMT_PEM, host_key_pem.data, &host_key_pem.size);
185
186 gnutls_datum_t root_cert_pem = { NULL, 0 };
187 gnutls_datum_t host_cert_pem = { NULL, 0 };
188
189 gnutls_x509_crt_export(root_cert, GNUTLS_X509_FMT_PEM, NULL, &root_cert_pem.size);
190 gnutls_x509_crt_export(host_cert, GNUTLS_X509_FMT_PEM, NULL, &host_cert_pem.size);
191
192 root_cert_pem.data = gnutls_malloc(root_cert_pem.size);
193 host_cert_pem.data = gnutls_malloc(host_cert_pem.size);
194
195 printf("Generating root certificate...");
196 gnutls_x509_crt_export(root_cert, GNUTLS_X509_FMT_PEM, root_cert_pem.data, &root_cert_pem.size);
197 printf("done\n");
198
199 printf("Generating host certificate...");
200 gnutls_x509_crt_export(host_cert, GNUTLS_X509_FMT_PEM, host_cert_pem.data, &host_cert_pem.size);
201 printf("done\n");
202
203
204 /* store values in config file */
205 init_config_file(host_id, &root_key_pem, &host_key_pem, &root_cert_pem, &host_cert_pem);
206
207 gnutls_free(root_key_pem.data);
208 gnutls_free(host_key_pem.data);
209 gnutls_free(root_cert_pem.data);
210 gnutls_free(host_cert_pem.data);
211
212 return 0;
213}
diff --git a/src/lockdown.c b/src/lockdown.c
index 63f9090..e720b29 100644
--- a/src/lockdown.c
+++ b/src/lockdown.c
@@ -1,22 +1,22 @@
1/* 1/*
2 * lockdown.c 2 * lockdown.c
3 * libiphone built-in lockdownd client 3 * libiphone built-in lockdownd client
4 * 4 *
5 * Copyright (c) 2008 Zach C. All Rights Reserved. 5 * Copyright (c) 2008 Zach C. All Rights Reserved.
6 * 6 *
7 * This library is free software; you can redistribute it and/or 7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public 8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either 9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version. 10 * version 2.1 of the License, or (at your option) any later version.
11 * 11 *
12 * This library is distributed in the hope that it will be useful, 12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details. 15 * Lesser General Public License for more details.
16 * 16 *
17 * You should have received a copy of the GNU Lesser General Public 17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software 18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */ 20 */
21 21
22#include "usbmux.h" 22#include "usbmux.h"
@@ -67,7 +67,7 @@ iphone_lckd_client_t new_lockdownd_client(iphone_device_t phone)
67 67
68/** 68/**
69 * Closes the lockdownd communication session, by sending 69 * Closes the lockdownd communication session, by sending
70 * the StopSession Request to the device. 70 * the StopSession Request to the device.
71 * 71 *
72 * @param control The lockdown client 72 * @param control The lockdown client
73 */ 73 */
@@ -128,7 +128,7 @@ static void iphone_lckd_stop_session(iphone_lckd_client_t control)
128 128
129/** 129/**
130 * Shuts down the SSL session by first calling iphone_lckd_stop_session 130 * Shuts down the SSL session by first calling iphone_lckd_stop_session
131 * to cleanly close the lockdownd communication session, and then 131 * to cleanly close the lockdownd communication session, and then
132 * performing a close notify, which is done by "gnutls_bye". 132 * performing a close notify, which is done by "gnutls_bye".
133 * 133 *
134 * @param client The lockdown client 134 * @param client The lockdown client
@@ -219,6 +219,7 @@ iphone_error_t iphone_lckd_recv(iphone_lckd_client_t client, plist_t * plist)
219 return IPHONE_E_NOT_ENOUGH_DATA; 219 return IPHONE_E_NOT_ENOUGH_DATA;
220 } 220 }
221 221
222 log_dbg_msg(DBGMASK_LOCKDOWND, "Recv msg :\nsize : %i\nbuffer :\n%s\n", bytes, receive);
222 plist_from_xml(receive, bytes, plist); 223 plist_from_xml(receive, bytes, plist);
223 free(receive); 224 free(receive);
224 225
@@ -229,7 +230,7 @@ iphone_error_t iphone_lckd_recv(iphone_lckd_client_t client, plist_t * plist)
229} 230}
230 231
231/** Sends lockdownd data to the iPhone 232/** Sends lockdownd data to the iPhone
232 * 233 *
233 * @note This function is low-level and should only be used if you need to send 234 * @note This function is low-level and should only be used if you need to send
234 * a new type of message. 235 * a new type of message.
235 * 236 *
@@ -272,7 +273,7 @@ iphone_error_t iphone_lckd_send(iphone_lckd_client_t client, plist_t plist)
272} 273}
273 274
274/** Initiates the handshake for the lockdown session. Part of the lockdownd handshake. 275/** Initiates the handshake for the lockdown session. Part of the lockdownd handshake.
275 * 276 *
276 * @note You most likely want lockdownd_init unless you are doing something special. 277 * @note You most likely want lockdownd_init unless you are doing something special.
277 * 278 *
278 * @param control The lockdownd client 279 * @param control The lockdownd client
@@ -338,7 +339,7 @@ iphone_error_t lockdownd_hello(iphone_lckd_client_t control)
338 * 339 *
339 * @return IPHONE_E_SUCCESS on success. 340 * @return IPHONE_E_SUCCESS on success.
340 */ 341 */
341iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, const char *req_key, char *req_string, 342iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, const char *req_key, const char *req_string,
342 gnutls_datum_t * value) 343 gnutls_datum_t * value)
343{ 344{
344 if (!control || !req_key || !value || value->data) 345 if (!control || !req_key || !value || value->data)
@@ -396,7 +397,7 @@ iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, const c
396 return ret; 397 return ret;
397 } 398 }
398 399
399 plist_t value_key_node = plist_get_next_sibling(result_key_node); 400 plist_t value_key_node = plist_find_node_by_key(dict, "Value");//plist_get_next_sibling(result_value_node);
400 plist_t value_value_node = plist_get_next_sibling(value_key_node); 401 plist_t value_value_node = plist_get_next_sibling(value_key_node);
401 402
402 plist_type value_key_type = plist_get_node_type(value_key_node); 403 plist_type value_key_type = plist_get_node_type(value_key_node);
@@ -418,6 +419,16 @@ iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, const c
418 value->size = strlen(value_value); 419 value->size = strlen(value_value);
419 ret = IPHONE_E_SUCCESS; 420 ret = IPHONE_E_SUCCESS;
420 } 421 }
422
423 if (PLIST_DATA == value_value_type) {
424 char *value_value = NULL;
425 uint64_t size = 0;
426 plist_get_data_val(value_value_node, &value_value, &size);
427
428 value->data = value_value;
429 value->size = size;
430 ret = IPHONE_E_SUCCESS;
431 }
421 } 432 }
422 free(result_key); 433 free(result_key);
423 } 434 }
@@ -435,8 +446,9 @@ iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, const c
435iphone_error_t lockdownd_get_device_uid(iphone_lckd_client_t control, char **uid) 446iphone_error_t lockdownd_get_device_uid(iphone_lckd_client_t control, char **uid)
436{ 447{
437 gnutls_datum_t temp = { NULL, 0 }; 448 gnutls_datum_t temp = { NULL, 0 };
438 return lockdownd_generic_get_value(control, "Key", "UniqueDeviceID", &temp); 449 iphone_error_t ret = lockdownd_generic_get_value(control, "Key", "UniqueDeviceID", &temp);
439 *uid = temp.data; 450 *uid = temp.data;
451 return ret;
440} 452}
441 453
442/** Askes for the device's public key. Part of the lockdownd handshake. 454/** Askes for the device's public key. Part of the lockdownd handshake.
@@ -480,6 +492,7 @@ iphone_error_t iphone_lckd_new_client(iphone_device_t device, iphone_lckd_client
480 if (IPHONE_E_SUCCESS != ret) { 492 if (IPHONE_E_SUCCESS != ret) {
481 log_debug_msg("Device refused to send uid.\n"); 493 log_debug_msg("Device refused to send uid.\n");
482 } 494 }
495 log_debug_msg("Device uid: %s\n", uid);
483 496
484 host_id = get_host_id(); 497 host_id = get_host_id();
485 if (IPHONE_E_SUCCESS == ret && !host_id) { 498 if (IPHONE_E_SUCCESS == ret && !host_id) {
@@ -495,19 +508,22 @@ iphone_error_t iphone_lckd_new_client(iphone_device_t device, iphone_lckd_client
495 uid = NULL; 508 uid = NULL;
496 } 509 }
497 510
498 ret = lockdownd_start_SSL_session(client_loc, host_id); 511 if (IPHONE_E_SUCCESS == ret) {
499 if (IPHONE_E_SUCCESS != ret) { 512 ret = lockdownd_start_SSL_session(client_loc, host_id);
500 ret = IPHONE_E_SSL_ERROR; 513 if (IPHONE_E_SUCCESS != ret) {
501 log_debug_msg("SSL Session opening failed.\n"); 514 ret = IPHONE_E_SSL_ERROR;
502 } 515 log_debug_msg("SSL Session opening failed.\n");
516 }
503 517
504 if (host_id) { 518 if (host_id) {
505 free(host_id); 519 free(host_id);
506 host_id = NULL; 520 host_id = NULL;
521 }
522
523 if (IPHONE_E_SUCCESS == ret)
524 *client = client_loc;
507 } 525 }
508 526
509 if (IPHONE_E_SUCCESS == ret)
510 *client = client_loc;
511 return ret; 527 return ret;
512} 528}
513 529
@@ -534,6 +550,7 @@ iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *uid, ch
534 log_debug_msg("Device refused to send public key.\n"); 550 log_debug_msg("Device refused to send public key.\n");
535 return ret; 551 return ret;
536 } 552 }
553 log_debug_msg("device public key :\n %s.\n", public_key.data);
537 554
538 ret = lockdownd_gen_pair_cert(public_key, &device_cert, &host_cert, &root_cert); 555 ret = lockdownd_gen_pair_cert(public_key, &device_cert, &host_cert, &root_cert);
539 if (ret != IPHONE_E_SUCCESS) { 556 if (ret != IPHONE_E_SUCCESS) {
@@ -547,15 +564,15 @@ iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *uid, ch
547 dict_record = plist_new_dict(); 564 dict_record = plist_new_dict();
548 plist_add_sub_node(dict, dict_record); 565 plist_add_sub_node(dict, dict_record);
549 plist_add_sub_key_el(dict_record, "DeviceCertificate"); 566 plist_add_sub_key_el(dict_record, "DeviceCertificate");
550 plist_add_sub_data_el(dict_record, device_cert.data, device_cert.size); 567 plist_add_sub_data_el(dict_record, (const char*)device_cert.data, device_cert.size);
551 plist_add_sub_key_el(dict_record, "HostCertificate"); 568 plist_add_sub_key_el(dict_record, "HostCertificate");
552 plist_add_sub_data_el(dict_record, host_cert.data, host_cert.size); 569 plist_add_sub_data_el(dict_record, (const char*)host_cert.data, host_cert.size);
553 plist_add_sub_key_el(dict_record, "HostID"); 570 plist_add_sub_key_el(dict_record, "HostID");
554 plist_add_sub_string_el(dict_record, host_id); 571 plist_add_sub_string_el(dict_record, host_id);
555 plist_add_sub_key_el(dict_record, "RootCertificate"); 572 plist_add_sub_key_el(dict_record, "RootCertificate");
556 plist_add_sub_data_el(dict_record, root_cert.data, root_cert.size); 573 plist_add_sub_data_el(dict_record, (const char*)root_cert.data, root_cert.size);
557 plist_add_sub_key_el(dict_record, "Request"); 574 plist_add_sub_key_el(dict, "Request");
558 plist_add_sub_string_el(dict_record, "Pair"); 575 plist_add_sub_string_el(dict, "Pair");
559 576
560 /* send to iPhone */ 577 /* send to iPhone */
561 ret = iphone_lckd_send(control, dict); 578 ret = iphone_lckd_send(control, dict);
@@ -667,7 +684,7 @@ void lockdownd_close(iphone_lckd_client_t control)
667 684
668/** Generates the device certificate from the public key as well as the host 685/** Generates the device certificate from the public key as well as the host
669 * and root certificates. 686 * and root certificates.
670 * 687 *
671 * @return IPHONE_E_SUCCESS on success. 688 * @return IPHONE_E_SUCCESS on success.
672 */ 689 */
673iphone_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datum_t * odevice_cert, 690iphone_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datum_t * odevice_cert,
@@ -718,7 +735,7 @@ iphone_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datum_t
718 gnutls_global_init(); 735 gnutls_global_init();
719 gnutls_datum_t essentially_null = { strdup("abababababababab"), strlen("abababababababab") }; 736 gnutls_datum_t essentially_null = { strdup("abababababababab"), strlen("abababababababab") };
720 737
721 gnutls_x509_privkey_t fake_privkey, root_privkey; 738 gnutls_x509_privkey_t fake_privkey, root_privkey, host_privkey;
722 gnutls_x509_crt_t dev_cert, root_cert, host_cert; 739 gnutls_x509_crt_t dev_cert, root_cert, host_cert;
723 740
724 gnutls_x509_privkey_init(&fake_privkey); 741 gnutls_x509_privkey_init(&fake_privkey);
@@ -731,57 +748,50 @@ iphone_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datum_t
731 &essentially_null, &essentially_null)) { 748 &essentially_null, &essentially_null)) {
732 749
733 gnutls_x509_privkey_init(&root_privkey); 750 gnutls_x509_privkey_init(&root_privkey);
751 gnutls_x509_privkey_init(&host_privkey);
734 752
735 /* get root cert */ 753 ret = get_keys_and_certs( root_privkey, root_cert, host_privkey, host_cert);
736 gnutls_datum_t pem_root_cert = { NULL, 0 };
737 get_root_certificate(&pem_root_cert);
738 if (GNUTLS_E_SUCCESS != gnutls_x509_crt_import(root_cert, &pem_root_cert, GNUTLS_X509_FMT_PEM))
739 ret = IPHONE_E_SSL_ERROR;
740
741 /* get host cert */
742 gnutls_datum_t pem_host_cert = { NULL, 0 };
743 get_host_certificate(&pem_host_cert);
744 if (GNUTLS_E_SUCCESS != gnutls_x509_crt_import(host_cert, &pem_host_cert, GNUTLS_X509_FMT_PEM))
745 ret = IPHONE_E_SSL_ERROR;
746
747 /* get root private key */
748 gnutls_datum_t pem_root_priv = { NULL, 0 };
749 get_root_private_key(&pem_root_priv);
750 if (GNUTLS_E_SUCCESS != gnutls_x509_privkey_import(root_privkey, &pem_root_priv, GNUTLS_X509_FMT_PEM))
751 ret = IPHONE_E_SSL_ERROR;
752
753 /* generate device certificate */
754 gnutls_x509_crt_set_key(dev_cert, fake_privkey);
755 gnutls_x509_crt_set_serial(dev_cert, "\x00", 1);
756 gnutls_x509_crt_set_version(dev_cert, 3);
757 gnutls_x509_crt_set_ca_status(dev_cert, 0);
758 gnutls_x509_crt_set_activation_time(dev_cert, time(NULL));
759 gnutls_x509_crt_set_expiration_time(dev_cert, time(NULL) + (60 * 60 * 24 * 365 * 10));
760 gnutls_x509_crt_sign(dev_cert, root_cert, root_privkey);
761 754
762 if (IPHONE_E_SUCCESS == ret) { 755 if (IPHONE_E_SUCCESS == ret) {
763 /* if everything went well, export in PEM format */ 756
764 gnutls_datum_t dev_pem = { NULL, 0 }; 757 /* generate device certificate */
765 gnutls_x509_crt_export(dev_cert, GNUTLS_X509_FMT_PEM, NULL, &dev_pem.size); 758 gnutls_x509_crt_set_key(dev_cert, fake_privkey);
766 dev_pem.data = gnutls_malloc(dev_pem.size); 759 gnutls_x509_crt_set_serial(dev_cert, "\x00", 1);
767 gnutls_x509_crt_export(dev_cert, GNUTLS_X509_FMT_PEM, dev_pem.data, &dev_pem.size); 760 gnutls_x509_crt_set_version(dev_cert, 3);
768 761 gnutls_x509_crt_set_ca_status(dev_cert, 0);
769 /* copy buffer for output */ 762 gnutls_x509_crt_set_activation_time(dev_cert, time(NULL));
770 odevice_cert->data = malloc(dev_pem.size); 763 gnutls_x509_crt_set_expiration_time(dev_cert, time(NULL) + (60 * 60 * 24 * 365 * 10));
771 memcpy(odevice_cert->data, dev_pem.data, dev_pem.size); 764 gnutls_x509_crt_sign(dev_cert, root_cert, root_privkey);
772 odevice_cert->size = dev_pem.size; 765
773 766 if (IPHONE_E_SUCCESS == ret) {
774 ohost_cert->data = malloc(pem_host_cert.size); 767 /* if everything went well, export in PEM format */
775 memcpy(ohost_cert->data, pem_host_cert.data, pem_host_cert.size); 768 gnutls_datum_t dev_pem = { NULL, 0 };
776 ohost_cert->size = pem_host_cert.size; 769 gnutls_x509_crt_export(dev_cert, GNUTLS_X509_FMT_PEM, NULL, &dev_pem.size);
777 770 dev_pem.data = gnutls_malloc(dev_pem.size);
778 oroot_cert->data = malloc(pem_root_cert.size); 771 gnutls_x509_crt_export(dev_cert, GNUTLS_X509_FMT_PEM, dev_pem.data, &dev_pem.size);
779 memcpy(oroot_cert->data, pem_root_cert.data, pem_root_cert.size); 772
780 oroot_cert->size = pem_root_cert.size; 773 gnutls_datum_t pem_root_cert = { NULL, 0 };
774 gnutls_datum_t pem_host_cert = { NULL, 0 };
775
776 if ( IPHONE_E_SUCCESS == get_certs_as_pem(&pem_root_cert, &pem_host_cert) ) {
777 /* copy buffer for output */
778 odevice_cert->data = malloc(dev_pem.size);
779 memcpy(odevice_cert->data, dev_pem.data, dev_pem.size);
780 odevice_cert->size = dev_pem.size;
781
782 ohost_cert->data = malloc(pem_host_cert.size);
783 memcpy(ohost_cert->data, pem_host_cert.data, pem_host_cert.size);
784 ohost_cert->size = pem_host_cert.size;
785
786 oroot_cert->data = malloc(pem_root_cert.size);
787 memcpy(oroot_cert->data, pem_root_cert.data, pem_root_cert.size);
788 oroot_cert->size = pem_root_cert.size;
789
790 g_free(pem_root_cert.data);
791 g_free(pem_host_cert.data);
792 }
793 }
781 } 794 }
782 gnutls_free(pem_root_priv.data);
783 gnutls_free(pem_root_cert.data);
784 gnutls_free(pem_host_cert.data);
785 } 795 }
786 } 796 }
787 797
diff --git a/src/lockdown.h b/src/lockdown.h
index cad06a3..7485006 100644
--- a/src/lockdown.h
+++ b/src/lockdown.h
@@ -8,15 +8,15 @@
8 * modify it under the terms of the GNU Lesser General Public 8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either 9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version. 10 * version 2.1 of the License, or (at your option) any later version.
11 * 11 *
12 * This library is distributed in the hope that it will be useful, 12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details. 15 * Lesser General Public License for more details.
16 * 16 *
17 * You should have received a copy of the GNU Lesser General Public 17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software 18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */ 20 */
21 21
22#ifndef LOCKDOWND_H 22#ifndef LOCKDOWND_H
@@ -41,7 +41,7 @@ struct iphone_lckd_client_int {
41iphone_lckd_client_t new_lockdownd_client(iphone_device_t phone); 41iphone_lckd_client_t new_lockdownd_client(iphone_device_t phone);
42iphone_error_t lockdownd_hello(iphone_lckd_client_t control); 42iphone_error_t lockdownd_hello(iphone_lckd_client_t control);
43 43
44iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, const char *req_key, char *req_string, 44iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, const char *req_key, const char *req_string,
45 gnutls_datum_t * value); 45 gnutls_datum_t * value);
46 46
47iphone_error_t lockdownd_get_device_public_key(iphone_lckd_client_t control, gnutls_datum_t * public_key); 47iphone_error_t lockdownd_get_device_public_key(iphone_lckd_client_t control, gnutls_datum_t * public_key);
diff --git a/src/userpref.c b/src/userpref.c
index 3e5eb06..0e83133 100644
--- a/src/userpref.c
+++ b/src/userpref.c
@@ -8,25 +8,28 @@
8 * modify it under the terms of the GNU Lesser General Public 8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either 9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version. 10 * version 2.1 of the License, or (at your option) any later version.
11 * 11 *
12 * This library is distributed in the hope that it will be useful, 12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details. 15 * Lesser General Public License for more details.
16 * 16 *
17 * You should have received a copy of the GNU Lesser General Public 17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software 18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */ 20 */
21 21
22#include <glib.h> 22#include <glib.h>
23#include <glib/gprintf.h> 23#include <glib/gprintf.h>
24#include <stdio.h> 24#include <stdio.h>
25#include <stdlib.h>
25#include <string.h> 26#include <string.h>
27#include <gnutls/gnutls.h>
28#include <gnutls/x509.h>
29#include <gcrypt.h>
30
26#include "userpref.h" 31#include "userpref.h"
27#include "utils.h" 32#include "utils.h"
28#include <string.h>
29#include <stdlib.h>
30 33
31#define LIBIPHONE_CONF_DIR "libiphone" 34#define LIBIPHONE_CONF_DIR "libiphone"
32#define LIBIPHONE_CONF_FILE "libiphonerc" 35#define LIBIPHONE_CONF_FILE "libiphonerc"
@@ -49,9 +52,75 @@ static void create_config_dir(void)
49 g_free(config_dir); 52 g_free(config_dir);
50} 53}
51 54
55static int get_rand(int min, int max)
56{
57 int retval = (rand() % (max - min)) + min;
58 return retval;
59}
60
61/** Generates a valid HostID (which is actually a UUID).
62 *
63 * @return A null terminated string containing a valid HostID.
64 */
65static char *lockdownd_generate_hostid()
66{
67 char *hostid = (char *) malloc(sizeof(char) * 37); // HostID's are just UUID's, and UUID's are 36 characters long
68 const char *chars = "ABCDEF0123456789";
69 srand(time(NULL));
70 int i = 0;
71
72 for (i = 0; i < 36; i++) {
73 if (i == 8 || i == 13 || i == 18 || i == 23) {
74 hostid[i] = '-';
75 continue;
76 } else {
77 hostid[i] = chars[get_rand(0, 16)];
78 }
79 }
80 hostid[36] = '\0'; // make it a real string
81 return hostid;
82}
83
84/** Store HostID in config file.
85 *
86 * @param host_id A null terminated string containing a valid HostID.
87 */
88static int write_host_id(char *host_id)
89{
90 GKeyFile *key_file;
91 gsize length;
92 gchar *buf, *config_file;
93 GIOChannel *file;
94
95 if (!host_id)
96 return 0;
97
98 /* Make sure config directory exists */
99 create_config_dir();
100
101 /* Now parse file to get the HostID */
102 key_file = g_key_file_new();
52 103
53/** Reads the HostID from a previously generated configuration file. 104 /* Store in config file */
54 * 105 log_debug_msg("init_config_file(): setting hostID to %s\n", host_id);
106 g_key_file_set_value(key_file, "Global", "HostID", host_id);
107
108 /* Write config file on disk */
109 buf = g_key_file_to_data(key_file, &length, NULL);
110 config_file =
111 g_build_path(G_DIR_SEPARATOR_S, g_get_user_config_dir(), LIBIPHONE_CONF_DIR, LIBIPHONE_CONF_FILE, NULL);
112 file = g_io_channel_new_file(config_file, "w", NULL);
113 g_free(config_file);
114 g_io_channel_write_chars(file, buf, length, NULL, NULL);
115 g_io_channel_shutdown(file, TRUE, NULL);
116 g_io_channel_unref(file);
117
118 g_key_file_free(key_file);
119 return 1;
120}
121
122/** Reads the HostID from a previously generated configuration file.
123 *
55 * @note It is the responsibility of the calling function to free the returned host_id 124 * @note It is the responsibility of the calling function to free the returned host_id
56 * 125 *
57 * @return The string containing the HostID or NULL 126 * @return The string containing the HostID or NULL
@@ -77,6 +146,12 @@ char *get_host_id(void)
77 g_key_file_free(key_file); 146 g_key_file_free(key_file);
78 g_free(config_file); 147 g_free(config_file);
79 148
149 if (!host_id) {
150 //no config, generate host_id
151 host_id = lockdownd_generate_hostid();
152 write_host_id(host_id);
153 }
154
80 log_debug_msg("get_host_id(): Using %s as HostID\n", host_id); 155 log_debug_msg("get_host_id(): Using %s as HostID\n", host_id);
81 return host_id; 156 return host_id;
82} 157}
@@ -156,56 +231,220 @@ static int read_file_in_confdir(const char *file, gnutls_datum_t * data)
156 g_free(filepath); 231 g_free(filepath);
157 232
158 /* Add it to the gnutls_datnum_t structure */ 233 /* Add it to the gnutls_datnum_t structure */
159 data->data = content; 234 data->data = (uint8_t*) content;
160 data->size = size; 235 data->size = size;
161 236
162 return success; 237 return success;
163} 238}
164 239
165/** Read the root private key 240
166 * 241/** Private function which generate private keys and certificates.
167 * @param root_privkey A pointer to the appropriate gnutls structure
168 * 242 *
169 * @return 1 if the file was successfully read and 0 otherwise. 243 * @return IPHONE_E_SUCCESS if keys were successfully generated.
170 */ 244 */
171int get_root_private_key(gnutls_datum_t * root_privkey) 245static iphone_error_t gen_keys_and_cert(void)
172{ 246{
173 return read_file_in_confdir(LIBIPHONE_ROOT_PRIVKEY, root_privkey); 247 iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR;
248 gnutls_x509_privkey_t root_privkey;
249 gnutls_x509_privkey_t host_privkey;
250 gnutls_x509_crt_t root_cert;
251 gnutls_x509_crt_t host_cert;
252
253 gnutls_global_deinit();
254 gnutls_global_init();
255
256 //use less secure random to speed up key generation
257 gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM);
258
259 gnutls_x509_privkey_init(&root_privkey);
260 gnutls_x509_privkey_init(&host_privkey);
261
262 gnutls_x509_crt_init(&root_cert);
263 gnutls_x509_crt_init(&host_cert);
264
265 /* generate root key */
266 gnutls_x509_privkey_generate(root_privkey, GNUTLS_PK_RSA, 2048, 0);
267 gnutls_x509_privkey_generate(host_privkey, GNUTLS_PK_RSA, 2048, 0);
268
269 /* generate certificates */
270 gnutls_x509_crt_set_key(root_cert, root_privkey);
271 gnutls_x509_crt_set_serial(root_cert, "\x00", 1);
272 gnutls_x509_crt_set_version(root_cert, 3);
273 gnutls_x509_crt_set_ca_status(root_cert, 1);
274 gnutls_x509_crt_set_activation_time(root_cert, time(NULL));
275 gnutls_x509_crt_set_expiration_time(root_cert, time(NULL) + (60 * 60 * 24 * 365 * 10));
276 gnutls_x509_crt_sign(root_cert, root_cert, root_privkey);
277
278
279 gnutls_x509_crt_set_key(host_cert, host_privkey);
280 gnutls_x509_crt_set_serial(host_cert, "\x00", 1);
281 gnutls_x509_crt_set_version(host_cert, 3);
282 gnutls_x509_crt_set_ca_status(host_cert, 0);
283 gnutls_x509_crt_set_key_usage(host_cert, GNUTLS_KEY_KEY_ENCIPHERMENT | GNUTLS_KEY_DIGITAL_SIGNATURE);
284 gnutls_x509_crt_set_activation_time(host_cert, time(NULL));
285 gnutls_x509_crt_set_expiration_time(host_cert, time(NULL) + (60 * 60 * 24 * 365 * 10));
286 gnutls_x509_crt_sign(host_cert, root_cert, root_privkey);
287
288 /* export to PEM format */
289 gnutls_datum_t root_key_pem = { NULL, 0 };
290 gnutls_datum_t host_key_pem = { NULL, 0 };
291
292 gnutls_x509_privkey_export(root_privkey, GNUTLS_X509_FMT_PEM, NULL, &root_key_pem.size);
293 gnutls_x509_privkey_export(host_privkey, GNUTLS_X509_FMT_PEM, NULL, &host_key_pem.size);
294
295 root_key_pem.data = gnutls_malloc(root_key_pem.size);
296 host_key_pem.data = gnutls_malloc(host_key_pem.size);
297
298 gnutls_x509_privkey_export(root_privkey, GNUTLS_X509_FMT_PEM, root_key_pem.data, &root_key_pem.size);
299 gnutls_x509_privkey_export(host_privkey, GNUTLS_X509_FMT_PEM, host_key_pem.data, &host_key_pem.size);
300
301 gnutls_datum_t root_cert_pem = { NULL, 0 };
302 gnutls_datum_t host_cert_pem = { NULL, 0 };
303
304 gnutls_x509_crt_export(root_cert, GNUTLS_X509_FMT_PEM, NULL, &root_cert_pem.size);
305 gnutls_x509_crt_export(host_cert, GNUTLS_X509_FMT_PEM, NULL, &host_cert_pem.size);
306
307 root_cert_pem.data = gnutls_malloc(root_cert_pem.size);
308 host_cert_pem.data = gnutls_malloc(host_cert_pem.size);
309
310 gnutls_x509_crt_export(root_cert, GNUTLS_X509_FMT_PEM, root_cert_pem.data, &root_cert_pem.size);
311 gnutls_x509_crt_export(host_cert, GNUTLS_X509_FMT_PEM, host_cert_pem.data, &host_cert_pem.size);
312
313 if (NULL != root_cert_pem.data && 0 != root_cert_pem.size &&
314 NULL != host_cert_pem.data && 0 != host_cert_pem.size)
315 ret = IPHONE_E_SUCCESS;
316
317 /* store values in config file */
318 init_config_file( &root_key_pem, &host_key_pem, &root_cert_pem, &host_cert_pem);
319
320 gnutls_free(root_key_pem.data);
321 gnutls_free(host_key_pem.data);
322 gnutls_free(root_cert_pem.data);
323 gnutls_free(host_cert_pem.data);
324
325 //restore gnutls env
326 gnutls_global_deinit();
327 gnutls_global_init();
328
329 return ret;
174} 330}
175 331
176/** Read the host private key 332/** Private function which import the given key into a gnutls structure.
177 * 333 *
178 * @param host_privkey A pointer to the appropriate gnutls structure 334 * @param key_name The filename of the private key to import.
335 * @param key the gnutls key structure.
179 * 336 *
180 * @return 1 if the file was successfully read and 0 otherwise. 337 * @return IPHONE_E_SUCCESS if the key was successfully imported.
181 */ 338 */
182int get_host_private_key(gnutls_datum_t * host_privkey) 339static iphone_error_t import_key(const char* key_name, gnutls_x509_privkey_t key)
183{ 340{
184 return read_file_in_confdir(LIBIPHONE_HOST_PRIVKEY, host_privkey); 341 iphone_error_t ret = IPHONE_E_INVALID_CONF;
342 gnutls_datum_t pem_key = { NULL, 0 };
343
344 if ( read_file_in_confdir(key_name, &pem_key) ) {
345 if (GNUTLS_E_SUCCESS == gnutls_x509_privkey_import(key, &pem_key, GNUTLS_X509_FMT_PEM))
346 ret = IPHONE_E_SUCCESS;
347 else
348 ret = IPHONE_E_SSL_ERROR;
349 }
350 gnutls_free(pem_key.data);
351 return ret;
185} 352}
186 353
187/** Read the root certificate 354/** Private function which import the given certificate into a gnutls structure.
188 * 355 *
189 * @param root_privkey A pointer to the appropriate gnutls structure 356 * @param crt_name The filename of the certificate to import.
357 * @param cert the gnutls certificate structure.
190 * 358 *
191 * @return 1 if the file was successfully read and 0 otherwise. 359 * @return IPHONE_E_SUCCESS if the certificate was successfully imported.
192 */ 360 */
193int get_root_certificate(gnutls_datum_t * root_cert) 361static iphone_error_t import_crt(const char* crt_name, gnutls_x509_crt_t cert)
194{ 362{
195 return read_file_in_confdir(LIBIPHONE_ROOT_CERTIF, root_cert); 363 iphone_error_t ret = IPHONE_E_INVALID_CONF;
364 gnutls_datum_t pem_cert = { NULL, 0 };
365
366 if ( read_file_in_confdir(crt_name, &pem_cert) ) {
367 if (GNUTLS_E_SUCCESS == gnutls_x509_crt_import(cert, &pem_cert, GNUTLS_X509_FMT_PEM))
368 ret = IPHONE_E_SUCCESS;
369 else
370 ret = IPHONE_E_SSL_ERROR;
371 }
372 gnutls_free(pem_cert.data);
373 return ret;
196} 374}
197 375
198/** Read the host certificate 376/** Function to retrieve host keys and certificates.
377 * This function trigger key generation if they do not exists yet or are invalid.
199 * 378 *
200 * @param root_privkey A pointer to the appropriate gnutls structure 379 * @note This function can take few seconds to complete (typically 5 seconds)
201 * 380 *
202 * @return 1 if the file was successfully read and 0 otherwise. 381 * @param root_privkey The root private key.
382 * @param root_crt The root certificate.
383 * @param host_privkey The host private key.
384 * @param host_crt The host certificate.
385 *
386 * @return IPHONE_E_SUCCESS if the keys and certificates were successfully retrieved.
203 */ 387 */
204int get_host_certificate(gnutls_datum_t * host_cert) 388iphone_error_t get_keys_and_certs(gnutls_x509_privkey_t root_privkey, gnutls_x509_crt_t root_crt, gnutls_x509_privkey_t host_privkey, gnutls_x509_crt_t host_crt)
205{ 389{
206 return read_file_in_confdir(LIBIPHONE_HOST_CERTIF, host_cert); 390 iphone_error_t ret = IPHONE_E_SUCCESS;
391
392 if (ret == IPHONE_E_SUCCESS)
393 ret = import_key(LIBIPHONE_ROOT_PRIVKEY, root_privkey);
394
395 if (ret == IPHONE_E_SUCCESS)
396 ret = import_key(LIBIPHONE_HOST_PRIVKEY, host_privkey);
397
398 if (ret == IPHONE_E_SUCCESS)
399 ret = import_crt(LIBIPHONE_ROOT_CERTIF, root_crt);
400
401 if (ret == IPHONE_E_SUCCESS)
402 ret = import_crt(LIBIPHONE_HOST_CERTIF, host_crt);
403
404
405 if (IPHONE_E_SUCCESS != ret) {
406 //we had problem reading or importing root cert
407 //try with a new ones.
408 ret = gen_keys_and_cert();
409
410 if (ret == IPHONE_E_SUCCESS)
411 ret = import_key(LIBIPHONE_ROOT_PRIVKEY, root_privkey);
412
413 if (ret == IPHONE_E_SUCCESS)
414 ret = import_key(LIBIPHONE_HOST_PRIVKEY, host_privkey);
415
416 if (ret == IPHONE_E_SUCCESS)
417 ret = import_crt(LIBIPHONE_ROOT_CERTIF, root_crt);
418
419 if (ret == IPHONE_E_SUCCESS)
420 ret = import_crt(LIBIPHONE_HOST_CERTIF, host_crt);
421 }
422
423 return ret;
207} 424}
208 425
426/** Function to retrieve certificates encoded in PEM format.
427 *
428 * @param pem_root_cert The root certificate.
429 * @param pem_host_cert The host certificate.
430 *
431 * @return IPHONE_E_SUCCESS if the certificates were successfully retrieved.
432 */
433iphone_error_t get_certs_as_pem(gnutls_datum_t *pem_root_cert, gnutls_datum_t *pem_host_cert)
434{
435 iphone_error_t ret = IPHONE_E_INVALID_CONF;
436
437 if ( !pem_root_cert || !pem_host_cert)
438 return IPHONE_E_INVALID_ARG;
439
440 if ( read_file_in_confdir(LIBIPHONE_ROOT_CERTIF, pem_root_cert) && read_file_in_confdir(LIBIPHONE_HOST_CERTIF, pem_host_cert))
441 ret = IPHONE_E_SUCCESS;
442 else {
443 g_free(pem_root_cert->data);
444 g_free(pem_host_cert->data);
445 }
446 return ret;
447}
209/** Create and save a configuration file containing the given data. 448/** Create and save a configuration file containing the given data.
210 * 449 *
211 * @note: All fields must specified and be non-null 450 * @note: All fields must specified and be non-null
@@ -218,41 +457,18 @@ int get_host_certificate(gnutls_datum_t * host_cert)
218 * 457 *
219 * @return 1 on success and 0 otherwise. 458 * @return 1 on success and 0 otherwise.
220 */ 459 */
221int init_config_file(char *host_id, gnutls_datum_t * root_key, gnutls_datum_t * host_key, gnutls_datum_t * root_cert, 460int init_config_file( gnutls_datum_t * root_key, gnutls_datum_t * host_key, gnutls_datum_t * root_cert,
222 gnutls_datum_t * host_cert) 461 gnutls_datum_t * host_cert)
223{ 462{
224 FILE *pFile; 463 FILE *pFile;
225 gchar *pem; 464 gchar *pem;
226 GKeyFile *key_file;
227 gsize length;
228 gchar *buf, *config_file;
229 GIOChannel *file;
230 465
231 if (!host_id || !root_key || !host_key || !root_cert || !host_cert) 466 if (!root_key || !host_key || !root_cert || !host_cert)
232 return 0; 467 return 0;
233 468
234 /* Make sure config directory exists */ 469 /* Make sure config directory exists */
235 create_config_dir(); 470 create_config_dir();
236 471
237 /* Now parse file to get the HostID */
238 key_file = g_key_file_new();
239
240 /* Store in config file */
241 log_debug_msg("init_config_file(): setting hostID to %s\n", host_id);
242 g_key_file_set_value(key_file, "Global", "HostID", host_id);
243
244 /* Write config file on disk */
245 buf = g_key_file_to_data(key_file, &length, NULL);
246 config_file =
247 g_build_path(G_DIR_SEPARATOR_S, g_get_user_config_dir(), LIBIPHONE_CONF_DIR, LIBIPHONE_CONF_FILE, NULL);
248 file = g_io_channel_new_file(config_file, "w", NULL);
249 g_free(config_file);
250 g_io_channel_write_chars(file, buf, length, NULL, NULL);
251 g_io_channel_shutdown(file, TRUE, NULL);
252 g_io_channel_unref(file);
253
254 g_key_file_free(key_file);
255
256 /* Now write keys and certificates to disk */ 472 /* Now write keys and certificates to disk */
257 pem = g_build_path(G_DIR_SEPARATOR_S, g_get_user_config_dir(), LIBIPHONE_CONF_DIR, LIBIPHONE_ROOT_PRIVKEY, NULL); 473 pem = g_build_path(G_DIR_SEPARATOR_S, g_get_user_config_dir(), LIBIPHONE_CONF_DIR, LIBIPHONE_ROOT_PRIVKEY, NULL);
258 pFile = fopen(pem, "wb"); 474 pFile = fopen(pem, "wb");
diff --git a/src/userpref.h b/src/userpref.h
index 7e606eb..deced04 100644
--- a/src/userpref.h
+++ b/src/userpref.h
@@ -8,64 +8,34 @@
8 * modify it under the terms of the GNU Lesser General Public 8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either 9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version. 10 * version 2.1 of the License, or (at your option) any later version.
11 * 11 *
12 * This library is distributed in the hope that it will be useful, 12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details. 15 * Lesser General Public License for more details.
16 * 16 *
17 * You should have received a copy of the GNU Lesser General Public 17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software 18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */ 20 */
21 21
22#ifndef USERPREF_H 22#ifndef USERPREF_H
23#define USERPREF_H 23#define USERPREF_H
24 24
25#include <gnutls/gnutls.h> 25#include <gnutls/gnutls.h>
26/** 26#include "libiphone/libiphone.h"
27 * Method to get user's HostID. Caller must free returned buffer.
28 *
29 * @return the HostID if exist in config file. Returns NULL otherwise.
30 */
31char *get_host_id(void);
32 27
33/**
34 * Determine if we already paired this device.
35 *
36 * @return 1 if device is already paired. Returns 0 otherwise.
37 */
38int is_device_known(char *uid);
39 28
40/** 29iphone_error_t get_keys_and_certs(gnutls_x509_privkey_t root_privkey, gnutls_x509_crt_t root_crt, gnutls_x509_privkey_t host_privkey, gnutls_x509_crt_t host_crt);
41 * @return 1 if everything went well. Returns 0 otherwise.
42 */
43int store_device_public_key(char *uid, gnutls_datum_t public_key);
44 30
45/** 31iphone_error_t get_certs_as_pem(gnutls_datum_t *pem_root_cert, gnutls_datum_t *pem_host_cert);
46 * @return 1 if everything went well. Returns 0 otherwise.
47 */
48int get_root_private_key(gnutls_datum_t * root_privkey);
49 32
50/** 33char *get_host_id(void);
51 * @return 1 if everything went well. Returns 0 otherwise.
52 */
53int get_host_private_key(gnutls_datum_t * host_privkey);
54 34
55/** 35int is_device_known(char *uid);
56 * @return 1 if everything went well. Returns 0 otherwise.
57 */
58int get_root_certificate(gnutls_datum_t * root_cert);
59 36
60/** 37int store_device_public_key(char *uid, gnutls_datum_t public_key);
61 * @return 1 if everything went well. Returns 0 otherwise.
62 */
63int get_host_certificate(gnutls_datum_t * host_cert);
64 38
65/** 39int init_config_file( gnutls_datum_t * root_key, gnutls_datum_t * host_key, gnutls_datum_t * root_cert,
66 * Setup a brand new config file.
67 * @return 1 if everything went well. Returns 0 otherwise.
68 */
69int init_config_file(char *host_id, gnutls_datum_t * root_key, gnutls_datum_t * host_key, gnutls_datum_t * root_cert,
70 gnutls_datum_t * host_cert); 40 gnutls_datum_t * host_cert);
71#endif 41#endif