summaryrefslogtreecommitdiffstats
path: root/src/lockdown.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lockdown.c')
-rw-r--r--src/lockdown.c969
1 files changed, 0 insertions, 969 deletions
diff --git a/src/lockdown.c b/src/lockdown.c
deleted file mode 100644
index e882128..0000000
--- a/src/lockdown.c
+++ /dev/null
@@ -1,969 +0,0 @@
1/*
2 * lockdown.c
3 * libiphone built-in lockdownd client
4 *
5 * Copyright (c) 2008 Zach C. 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 "usbmux.h"
23#include "iphone.h"
24#include "lockdown.h"
25#include "userpref.h"
26#include <arpa/inet.h>
27#include <errno.h>
28#include <string.h>
29#include <glib.h>
30#include <libtasn1.h>
31#include <gnutls/x509.h>
32
33const ASN1_ARRAY_TYPE pkcs1_asn1_tab[] = {
34 {"PKCS1", 536872976, 0},
35 {0, 1073741836, 0},
36 {"RSAPublicKey", 536870917, 0},
37 {"modulus", 1073741827, 0},
38 {"publicExponent", 3, 0},
39 {0, 0, 0}
40};
41
42
43
44/** Creates a lockdownd client for the give iPhone.
45 *
46 * @param phone The iPhone to create a lockdownd client for
47 *
48 * @return The lockdownd client.
49 */
50iphone_lckd_client_t new_lockdownd_client(iphone_device_t phone)
51{
52 if (!phone)
53 return NULL;
54 iphone_lckd_client_t control = (iphone_lckd_client_t) malloc(sizeof(struct iphone_lckd_client_int));
55
56 if (IPHONE_E_SUCCESS != iphone_mux_new_client(phone, 0x0a00, 0xf27e, &control->connection)) {
57 free(control);
58 return NULL;
59 }
60
61 control->ssl_session = (gnutls_session_t *) malloc(sizeof(gnutls_session_t));
62 control->in_SSL = 0;
63 control->gtls_buffer_hack_len = 0;
64 return control;
65}
66
67/** Closes the lockdownd client and does the necessary housekeeping.
68 *
69 * @param control The lockdown client
70 */
71iphone_error_t iphone_lckd_free_client(iphone_lckd_client_t client)
72{
73 if (!client)
74 return IPHONE_E_INVALID_ARG;
75 iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR;
76
77 if (client->connection) {
78 ret = iphone_mux_free_client(client->connection);
79 }
80
81 if (client->ssl_session)
82 gnutls_deinit(*client->ssl_session);
83 free(client->ssl_session);
84 free(client);
85 return ret;
86}
87
88/** Polls the iPhone for lockdownd data.
89 *
90 * @param control The lockdownd client
91 * @param dump_data The pointer to the location of the buffer in which to store
92 * the received data
93 *
94 * @return The number of bytes received
95 */
96iphone_error_t iphone_lckd_recv(iphone_lckd_client_t client, char **dump_data, uint32_t * recv_bytes)
97{
98 if (!client || !dump_data || !recv_bytes)
99 return IPHONE_E_INVALID_ARG;
100 iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR;
101 char *receive;
102 uint32_t datalen = 0, bytes = 0;
103
104 if (!client->in_SSL)
105 ret = iphone_mux_recv(client->connection, (char *) &datalen, sizeof(datalen), &bytes);
106 else {
107 bytes = gnutls_record_recv(*client->ssl_session, &datalen, sizeof(datalen));
108 if (bytes > 0)
109 ret = IPHONE_E_SUCCESS;
110 }
111 datalen = ntohl(datalen);
112
113 receive = (char *) malloc(sizeof(char) * datalen);
114 if (!client->in_SSL)
115 ret = iphone_mux_recv(client->connection, receive, datalen, &bytes);
116 else {
117 bytes = gnutls_record_recv(*client->ssl_session, receive, datalen);
118 if (bytes > 0)
119 ret = IPHONE_E_SUCCESS;
120 }
121 *dump_data = receive;
122 *recv_bytes = bytes;
123 return ret;
124}
125
126/** Sends lockdownd data to the iPhone
127 *
128 * @note This function is low-level and should only be used if you need to send
129 * a new type of message.
130 *
131 * @param control The lockdownd client
132 * @param raw_data The null terminated string buffer to send
133 * @param length The length of data to send
134 *
135 * @return The number of bytes sent
136 */
137iphone_error_t iphone_lckd_send(iphone_lckd_client_t client, char *raw_data, uint32_t length, uint32_t * sent_bytes)
138{
139 if (!client || !raw_data || length == 0 || !sent_bytes)
140 return IPHONE_E_INVALID_ARG;
141 char *real_query;
142 int bytes;
143 iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR;
144
145 real_query = (char *) malloc(sizeof(char) * (length + 4));
146 length = htonl(length);
147 memcpy(real_query, &length, sizeof(length));
148 memcpy(real_query + 4, raw_data, ntohl(length));
149 log_debug_msg("lockdownd_send(): made the query, sending it along\n");
150 dump_debug_buffer("grpkt", real_query, ntohl(length) + 4);
151
152 if (!client->in_SSL)
153 ret = iphone_mux_send(client->connection, real_query, ntohl(length) + sizeof(length), &bytes);
154 else {
155 gnutls_record_send(*client->ssl_session, real_query, ntohl(length) + sizeof(length));
156 ret = IPHONE_E_SUCCESS;
157 }
158 log_debug_msg("lockdownd_send(): sent it!\n");
159 free(real_query);
160 *sent_bytes = bytes;
161 return ret;
162}
163
164/** Initiates the handshake for the lockdown session. Part of the lockdownd handshake.
165 *
166 * @note You most likely want lockdownd_init unless you are doing something special.
167 *
168 * @param control The lockdownd client
169 *
170 * @return 1 on success and 0 on failure.
171 */
172iphone_error_t lockdownd_hello(iphone_lckd_client_t control)
173{
174 if (!control)
175 return IPHONE_E_INVALID_ARG;
176
177 int bytes = 0, i = 0;
178 iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR;
179
180 plist_t dict = NULL;
181 plist_new_dict(&dict);
182
183 plist_add_dict_element(dict, "Request", PLIST_STRING, (void *) "QueryType", strlen("QueryType"));
184
185 log_debug_msg("lockdownd_hello() called\n");
186 char *XML_content = NULL;
187 uint32_t length = 0;
188
189 plist_to_xml(dict, &XML_content, &length);
190 log_debug_msg("Send msg :\nsize : %i\nxml : %s", length, XML_content);
191 ret = iphone_lckd_send(control, XML_content, length, &bytes);
192
193 free(XML_content);
194 XML_content = NULL;
195 plist_free(dict);
196 dict = NULL;
197
198 ret = iphone_lckd_recv(control, &XML_content, &bytes);
199 log_debug_msg("Receive msg :\nsize : %i\nxml : %s", bytes, XML_content);
200 xml_to_plist(XML_content, bytes, &dict);
201
202 if (!dict)
203 return IPHONE_E_PLIST_ERROR;
204
205 plist_t query_node = find_query_node(dict, "Request", "QueryType");
206 plist_t result_node = g_node_next_sibling(query_node);
207 plist_t value_node = g_node_next_sibling(result_node);
208
209 plist_type result_type;
210 plist_type value_type;
211
212 char *result_value = NULL;
213 char *value_value = NULL;
214 uint64_t result_length = 0;
215 uint64_t value_length = 0;
216
217 get_type_and_value(result_node, &result_type, (void *) (&result_value), &result_length);
218 get_type_and_value(value_node, &value_type, (void *) (&value_value), &value_length);
219
220 if (result_type == PLIST_KEY &&
221 value_type == PLIST_STRING && !strcmp(result_value, "Result") && !strcmp(value_value, "Success")) {
222 log_debug_msg("lockdownd_hello(): success\n");
223 ret = IPHONE_E_SUCCESS;
224 }
225
226 return ret;
227}
228
229/** Generic function to handle simple (key, value) requests.
230 *
231 * @param control an initialized lockdownd client.
232 * @param key the key to request
233 * @param value a pointer to the requested value
234 *
235 * @return IPHONE_E_SUCCESS on success.
236 */
237iphone_error_t lockdownd_generic_get_value(iphone_lckd_client_t control, char *req_key, char *req_string,
238 gnutls_datum_t * value)
239{
240 if (!control || !req_key || !value || value->data)
241 return IPHONE_E_INVALID_ARG;
242
243 plist_t dict = NULL;
244 int bytes = 0, i = 0;
245 char *XML_content = NULL;
246 uint32_t length = 0;
247 iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR;
248
249 /* Setup DevicePublicKey request plist */
250 plist_new_dict(&dict);
251 plist_add_dict_element(dict, req_key, PLIST_STRING, (void *) req_string, strlen(req_string));
252 plist_add_dict_element(dict, "Request", PLIST_STRING, (void *) "GetValue", strlen("GetValue"));
253 plist_to_xml(dict, &XML_content, &length);
254
255 /* send to iPhone */
256 log_debug_msg("Send msg :\nsize : %i\nxml : %s", length, XML_content);
257 ret = iphone_lckd_send(control, XML_content, length, &bytes);
258
259 free(XML_content);
260 XML_content = NULL;
261 plist_free(dict);
262 dict = NULL;
263
264 if (ret != IPHONE_E_SUCCESS)
265 return ret;
266
267 /* Now get iPhone's answer */
268 ret = iphone_lckd_recv(control, &XML_content, &bytes);
269 log_debug_msg("Receive msg :\nsize : %i\nxml : %s", bytes, XML_content);
270
271 if (ret != IPHONE_E_SUCCESS)
272 return ret;
273
274 xml_to_plist(XML_content, bytes, &dict);
275 if (!dict)
276 return IPHONE_E_PLIST_ERROR;
277
278 plist_t query_node = find_query_node(dict, "Request", "GetValue");
279 plist_t result_key_node = g_node_next_sibling(query_node);
280 plist_t result_value_node = g_node_next_sibling(result_key_node);
281
282 plist_type result_key_type;
283 plist_type result_value_type;
284 char *result_key = NULL;
285 char *result_value = NULL;
286 uint64_t result_length = 0;
287 uint64_t value_length = 0;
288
289 get_type_and_value(result_key_node, &result_key_type, (void *) (&result_key), &result_length);
290 get_type_and_value(result_value_node, &result_value_type, (void *) (&result_value), &value_length);
291
292 if (result_key_type == PLIST_KEY &&
293 result_value_type == PLIST_STRING && !strcmp(result_key, "Result") && !strcmp(result_value, "Success")) {
294 log_debug_msg("lockdownd_generic_get_value(): success\n");
295 ret = IPHONE_E_SUCCESS;
296 }
297
298 if (ret != IPHONE_E_SUCCESS) {
299 return IPHONE_E_DICT_ERROR;
300 }
301
302 plist_t value_key_node = g_node_next_sibling(result_key_node);
303 plist_t value_value_node = g_node_next_sibling(value_key_node);
304 plist_type value_key_type;
305 plist_type value_value_type;
306 char *value_key = NULL;
307 char *value_value = NULL;
308 uint64_t key_length = 0;
309 uint64_t valval_length = 0;
310
311 get_type_and_value(value_key_node, &value_key_type, (void *) (&value_key), &key_length);
312 get_type_and_value(value_value_node, &value_value_type, (void *) (&value_value), &valval_length);
313
314 if (value_key_type == PLIST_KEY && !strcmp(result_key, "Value")) {
315 log_debug_msg("lockdownd_generic_get_value(): success\n");
316 value->data = value_value;
317 value->size = valval_length;
318 ret = IPHONE_E_SUCCESS;
319 }
320
321 plist_free(dict);
322 free(XML_content);
323 return ret;
324}
325
326/** Askes for the device's unique id. Part of the lockdownd handshake.
327 *
328 * @note You most likely want lockdownd_init unless you are doing something special.
329 *
330 * @return 1 on success and 0 on failure.
331 */
332iphone_error_t lockdownd_get_device_uid(iphone_lckd_client_t control, char **uid)
333{
334 gnutls_datum_t temp = { NULL, 0 };
335 return lockdownd_generic_get_value(control, "Key", "UniqueDeviceID", &temp);
336 *uid = temp.data;
337}
338
339/** Askes for the device's public key. Part of the lockdownd handshake.
340 *
341 * @note You most likely want lockdownd_init unless you are doing something special.
342 *
343 * @return 1 on success and 0 on failure.
344 */
345iphone_error_t lockdownd_get_device_public_key(iphone_lckd_client_t control, gnutls_datum_t * public_key)
346{
347 return lockdownd_generic_get_value(control, "Key", "DevicePublicKey", public_key);
348}
349
350/** Completes the entire lockdownd handshake.
351 *
352 * @param phone The iPhone
353 * @param lockdownd_client The pointer to the location of the lockdownd_client
354 *
355 * @return 1 on success and 0 on failure
356 */
357iphone_error_t iphone_lckd_new_client(iphone_device_t device, iphone_lckd_client_t * client)
358{
359 if (!device || !client || (client && *client))
360 return IPHONE_E_INVALID_ARG;
361 iphone_error_t ret = IPHONE_E_SUCCESS;
362 char *host_id = NULL;
363
364 iphone_lckd_client_t client_loc = new_lockdownd_client(device);
365 if (IPHONE_E_SUCCESS != lockdownd_hello(client_loc)) {
366 fprintf(stderr, "Hello failed in the lockdownd client.\n");
367 ret = IPHONE_E_NOT_ENOUGH_DATA;
368 }
369
370
371 char *uid = NULL;
372 ret = lockdownd_get_device_uid(client_loc, &uid);
373 if (IPHONE_E_SUCCESS != ret) {
374 fprintf(stderr, "Device refused to send uid.\n");
375 }
376
377 host_id = get_host_id();
378 if (IPHONE_E_SUCCESS == ret && !host_id) {
379 fprintf(stderr, "No HostID found, run libiphone-initconf.\n");
380 ret = IPHONE_E_INVALID_CONF;
381 }
382
383 if (IPHONE_E_SUCCESS == ret && !is_device_known(uid))
384 ret = lockdownd_pair_device(client_loc, uid, host_id);
385
386 if (uid) {
387 free(uid);
388 uid = NULL;
389 }
390
391 ret = lockdownd_start_SSL_session(client_loc, host_id);
392 if (IPHONE_E_SUCCESS != ret) {
393 ret = IPHONE_E_SSL_ERROR;
394 fprintf(stderr, "SSL Session opening failed.\n");
395 }
396
397 if (host_id) {
398 free(host_id);
399 host_id = NULL;
400 }
401
402 if (IPHONE_E_SUCCESS == ret)
403 *client = client_loc;
404 return ret;
405}
406
407/** Generates the appropriate keys and pairs the device. It's part of the
408 * lockdownd handshake.
409 *
410 * @note You most likely want lockdownd_init unless you are doing something special.
411 *
412 * @return 1 on success and 0 on failure
413 */
414iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *uid, char *host_id)
415{
416 iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR;
417 plist_t dict = NULL;
418 plist_t dict_record = NULL;
419 int bytes = 0, i = 0;
420 char *XML_content = NULL;
421 uint32_t length = 0;
422
423 gnutls_datum_t device_cert = { NULL, 0 };
424 gnutls_datum_t host_cert = { NULL, 0 };
425 gnutls_datum_t root_cert = { NULL, 0 };
426 gnutls_datum_t public_key = { NULL, 0 };
427
428 ret = lockdownd_get_device_public_key(control, &public_key);
429 if (ret != IPHONE_E_SUCCESS) {
430 fprintf(stderr, "Device refused to send public key.\n");
431 return ret;
432 }
433
434 ret = lockdownd_gen_pair_cert(public_key, &device_cert, &host_cert, &root_cert);
435 if (ret != IPHONE_E_SUCCESS) {
436 free(public_key.data);
437 return ret;
438 }
439
440 /* Setup Pair request plist */
441 plist_new_dict(&dict);
442 plist_add_dict_element(dict, "PairRecord", PLIST_DICT, NULL, 0);
443 dict_record = g_node_last_child(dict);
444 plist_add_dict_element(dict_record, "DeviceCertificate", PLIST_DATA, (void *) device_cert.data, device_cert.size);
445 plist_add_dict_element(dict_record, "HostCertificate", PLIST_DATA, (void *) host_cert.data, host_cert.size);
446 plist_add_dict_element(dict_record, "HostID", PLIST_STRING, (void *) host_id, strlen(host_id));
447 plist_add_dict_element(dict_record, "RootCertificate", PLIST_DATA, (void *) root_cert.data, root_cert.size);
448 plist_add_dict_element(dict, "Request", PLIST_STRING, (void *) "Pair", strlen("Pair"));
449 plist_to_xml(dict, &XML_content, &length);
450 log_debug_msg("XML Pairing request :\nsize : %i\nxml :\n %s", length, XML_content);
451
452 /* send to iPhone */
453 ret = iphone_lckd_send(control, XML_content, length, &bytes);
454
455 free(XML_content);
456 plist_free(dict);
457 dict = NULL;
458
459 if (ret != IPHONE_E_SUCCESS)
460 return ret;
461
462 /* Now get iPhone's answer */
463 ret = iphone_lckd_recv(control, &XML_content, &bytes);
464
465 if (ret != IPHONE_E_SUCCESS)
466 return ret;
467
468 log_debug_msg("lockdown_pair_device: iPhone's response to our pair request:\n");
469 log_debug_msg(XML_content);
470 log_debug_msg("\n\n");
471
472 xml_to_plist(XML_content, bytes, &dict);
473 if (!dict)
474 return IPHONE_E_PLIST_ERROR;
475
476 plist_t query_node = find_query_node(dict, "Request", "Pair");
477 plist_t result_key_node = g_node_next_sibling(query_node);
478 plist_t result_value_node = g_node_next_sibling(result_key_node);
479
480 plist_type result_key_type;
481 plist_type result_value_type;
482 char *result_key = NULL;
483 char *result_value = NULL;
484 uint64_t key_length = 0;
485 uint64_t val_length = 0;
486
487 get_type_and_value(result_key_node, &result_key_type, (void *) (&result_key), &key_length);
488 get_type_and_value(result_value_node, &result_value_type, (void *) (&result_value), &val_length);
489
490 if (result_key_type == PLIST_KEY &&
491 result_value_type == PLIST_STRING && !strcmp(result_key, "Result") && !strcmp(result_value, "Success")) {
492 ret = IPHONE_E_SUCCESS;
493 }
494
495 /* store public key in config if pairing succeeded */
496 if (ret == IPHONE_E_SUCCESS) {
497 log_debug_msg("lockdownd_pair_device: pair success\n");
498 store_device_public_key(uid, public_key);
499 ret = IPHONE_E_SUCCESS;
500 } else {
501 log_debug_msg("lockdownd_pair_device: pair failure\n");
502 ret = IPHONE_E_PAIRING_FAILED;
503 }
504 free(public_key.data);
505 return ret;
506}
507
508/** Generates the device certificate from the public key as well as the host
509 * and root certificates.
510 *
511 * @return IPHONE_E_SUCCESS on success.
512 */
513iphone_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datum_t * odevice_cert,
514 gnutls_datum_t * ohost_cert, gnutls_datum_t * oroot_cert)
515{
516 if (!public_key.data || !odevice_cert || !ohost_cert || !oroot_cert)
517 return IPHONE_E_INVALID_ARG;
518 iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR;
519
520 gnutls_datum_t modulus = { NULL, 0 };
521 gnutls_datum_t exponent = { NULL, 0 };
522
523 /* now decode the PEM encoded key */
524 gnutls_datum_t der_pub_key;
525 if (GNUTLS_E_SUCCESS == gnutls_pem_base64_decode_alloc("RSA PUBLIC KEY", &public_key, &der_pub_key)) {
526
527 /* initalize asn.1 parser */
528 ASN1_TYPE pkcs1 = ASN1_TYPE_EMPTY;
529 if (ASN1_SUCCESS == asn1_array2tree(pkcs1_asn1_tab, &pkcs1, NULL)) {
530
531 ASN1_TYPE asn1_pub_key = ASN1_TYPE_EMPTY;
532 asn1_create_element(pkcs1, "PKCS1.RSAPublicKey", &asn1_pub_key);
533
534 if (ASN1_SUCCESS == asn1_der_decoding(&asn1_pub_key, der_pub_key.data, der_pub_key.size, NULL)) {
535
536 /* get size to read */
537 int ret1 = asn1_read_value(asn1_pub_key, "modulus", NULL, &modulus.size);
538 int ret2 = asn1_read_value(asn1_pub_key, "publicExponent", NULL, &exponent.size);
539
540 modulus.data = gnutls_malloc(modulus.size);
541 exponent.data = gnutls_malloc(exponent.size);
542
543 ret1 = asn1_read_value(asn1_pub_key, "modulus", modulus.data, &modulus.size);
544 ret2 = asn1_read_value(asn1_pub_key, "publicExponent", exponent.data, &exponent.size);
545 if (ASN1_SUCCESS == ret1 && ASN1_SUCCESS == ret2)
546 ret = IPHONE_E_SUCCESS;
547 }
548 if (asn1_pub_key)
549 asn1_delete_structure(&asn1_pub_key);
550 }
551 if (pkcs1)
552 asn1_delete_structure(&pkcs1);
553 }
554
555 /* now generate certifcates */
556 if (IPHONE_E_SUCCESS == ret && 0 != modulus.size && 0 != exponent.size) {
557
558 gnutls_global_init();
559 gnutls_datum_t essentially_null = { strdup("abababababababab"), strlen("abababababababab") };
560
561 gnutls_x509_privkey_t fake_privkey, root_privkey;
562 gnutls_x509_crt_t dev_cert, root_cert, host_cert;
563
564 gnutls_x509_privkey_init(&fake_privkey);
565 gnutls_x509_crt_init(&dev_cert);
566 gnutls_x509_crt_init(&root_cert);
567 gnutls_x509_crt_init(&host_cert);
568
569 if (GNUTLS_E_SUCCESS ==
570 gnutls_x509_privkey_import_rsa_raw(fake_privkey, &modulus, &exponent, &essentially_null, &essentially_null,
571 &essentially_null, &essentially_null)) {
572
573 gnutls_x509_privkey_init(&root_privkey);
574
575 /* get root cert */
576 gnutls_datum_t pem_root_cert = { NULL, 0 };
577 get_root_certificate(&pem_root_cert);
578 if (GNUTLS_E_SUCCESS != gnutls_x509_crt_import(root_cert, &pem_root_cert, GNUTLS_X509_FMT_PEM))
579 ret = IPHONE_E_SSL_ERROR;
580
581 /* get host cert */
582 gnutls_datum_t pem_host_cert = { NULL, 0 };
583 get_host_certificate(&pem_host_cert);
584 if (GNUTLS_E_SUCCESS != gnutls_x509_crt_import(host_cert, &pem_host_cert, GNUTLS_X509_FMT_PEM))
585 ret = IPHONE_E_SSL_ERROR;
586
587 /* get root private key */
588 gnutls_datum_t pem_root_priv = { NULL, 0 };
589 get_root_private_key(&pem_root_priv);
590 if (GNUTLS_E_SUCCESS != gnutls_x509_privkey_import(root_privkey, &pem_root_priv, GNUTLS_X509_FMT_PEM))
591 ret = IPHONE_E_SSL_ERROR;
592
593 /* generate device certificate */
594 gnutls_x509_crt_set_key(dev_cert, fake_privkey);
595 gnutls_x509_crt_set_serial(dev_cert, "\x00", 1);
596 gnutls_x509_crt_set_version(dev_cert, 3);
597 gnutls_x509_crt_set_ca_status(dev_cert, 0);
598 gnutls_x509_crt_set_activation_time(dev_cert, time(NULL));
599 gnutls_x509_crt_set_expiration_time(dev_cert, time(NULL) + (60 * 60 * 24 * 365 * 10));
600 gnutls_x509_crt_sign(dev_cert, root_cert, root_privkey);
601
602 if (IPHONE_E_SUCCESS == ret) {
603 /* if everything went well, export in PEM format */
604 gnutls_datum_t dev_pem = { NULL, 0 };
605 gnutls_x509_crt_export(dev_cert, GNUTLS_X509_FMT_PEM, NULL, &dev_pem.size);
606 dev_pem.data = gnutls_malloc(dev_pem.size);
607 gnutls_x509_crt_export(dev_cert, GNUTLS_X509_FMT_PEM, dev_pem.data, &dev_pem.size);
608
609 /* copy buffer for output */
610 odevice_cert->data = malloc(dev_pem.size);
611 memcpy(odevice_cert->data, dev_pem.data, dev_pem.size);
612 odevice_cert->size = dev_pem.size;
613
614 ohost_cert->data = malloc(pem_host_cert.size);
615 memcpy(ohost_cert->data, pem_host_cert.data, pem_host_cert.size);
616 ohost_cert->size = pem_host_cert.size;
617
618 oroot_cert->data = malloc(pem_root_cert.size);
619 memcpy(oroot_cert->data, pem_root_cert.data, pem_root_cert.size);
620 oroot_cert->size = pem_root_cert.size;
621 }
622 gnutls_free(pem_root_priv.data);
623 gnutls_free(pem_root_cert.data);
624 gnutls_free(pem_host_cert.data);
625 }
626 }
627
628 gnutls_free(modulus.data);
629 gnutls_free(exponent.data);
630
631 gnutls_free(der_pub_key.data);
632
633 return ret;
634}
635
636/** Starts SSL communication with lockdownd after the iPhone has been paired.
637 *
638 * @param control The lockdownd client
639 * @param HostID The HostID used with this phone
640 *
641 * @return 1 on success and 0 on failure
642 */
643iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const char *HostID)
644{
645 plist_t dict = NULL;
646 char *XML_content = NULL;
647 uint32_t length = 0, bytes = 0, return_me = 0;
648
649 iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR;
650
651 /* Setup DevicePublicKey request plist */
652 plist_new_dict(&dict);
653 plist_add_dict_element(dict, "HostID", PLIST_STRING, (void *) HostID, strlen(HostID));
654 plist_add_dict_element(dict, "Request", PLIST_STRING, (void *) "StartSession", strlen("StartSession"));
655 plist_to_xml(dict, &XML_content, &length);
656 log_debug_msg("Send msg :\nsize : %i\nxml : %s", length, XML_content);
657
658 ret = iphone_lckd_send(control, XML_content, length, &bytes);
659
660 free(XML_content);
661 XML_content = NULL;
662 plist_free(dict);
663 dict = NULL;
664
665 if (ret != IPHONE_E_SUCCESS)
666 return ret;
667
668 if (bytes > 0) {
669 ret = iphone_lckd_recv(control, &XML_content, &bytes);
670 log_debug_msg("Receive msg :\nsize : %i\nxml : %s", bytes, XML_content);
671 xml_to_plist(XML_content, bytes, &dict);
672 if (!dict)
673 return IPHONE_E_PLIST_ERROR;
674
675 plist_t query_node = find_query_node(dict, "Request", "StartSession");
676 plist_t result_key_node = g_node_next_sibling(query_node);
677 plist_t result_value_node = g_node_next_sibling(result_key_node);
678
679 plist_type result_key_type;
680 plist_type result_value_type;
681 char *result_key = NULL;
682 char *result_value = NULL;
683 uint64_t key_length = 0;
684 uint64_t val_length = 0;
685
686 get_type_and_value(result_key_node, &result_key_type, (void *) (&result_key), &key_length);
687 get_type_and_value(result_value_node, &result_value_type, (void *) (&result_value), &val_length);
688
689 free(XML_content);
690 XML_content = NULL;
691 plist_free(dict);
692 dict = NULL;
693
694 if (result_key_type == PLIST_KEY &&
695 result_value_type == PLIST_STRING && !strcmp(result_key, "Result") && !strcmp(result_value, "Success")) {
696 // Set up GnuTLS...
697 //gnutls_anon_client_credentials_t anoncred;
698 gnutls_certificate_credentials_t xcred;
699
700 log_debug_msg("We started the session OK, now trying GnuTLS\n");
701 errno = 0;
702 gnutls_global_init();
703 //gnutls_anon_allocate_client_credentials(&anoncred);
704 gnutls_certificate_allocate_credentials(&xcred);
705 gnutls_certificate_set_x509_trust_file(xcred, "hostcert.pem", GNUTLS_X509_FMT_PEM);
706 gnutls_init(control->ssl_session, GNUTLS_CLIENT);
707 {
708 int protocol_priority[16] = { GNUTLS_SSL3, 0 };
709 int kx_priority[16] = { GNUTLS_KX_ANON_DH, GNUTLS_KX_RSA, 0 };
710 int cipher_priority[16] = { GNUTLS_CIPHER_AES_128_CBC, GNUTLS_CIPHER_AES_256_CBC, 0 };
711 int mac_priority[16] = { GNUTLS_MAC_SHA1, GNUTLS_MAC_MD5, 0 };
712 int comp_priority[16] = { GNUTLS_COMP_NULL, 0 };
713
714 gnutls_cipher_set_priority(*control->ssl_session, cipher_priority);
715 gnutls_compression_set_priority(*control->ssl_session, comp_priority);
716 gnutls_kx_set_priority(*control->ssl_session, kx_priority);
717 gnutls_protocol_set_priority(*control->ssl_session, protocol_priority);
718 gnutls_mac_set_priority(*control->ssl_session, mac_priority);
719
720 }
721 gnutls_credentials_set(*control->ssl_session, GNUTLS_CRD_CERTIFICATE, xcred); // this part is killing me.
722
723 log_debug_msg("GnuTLS step 1...\n");
724 gnutls_transport_set_ptr(*control->ssl_session, (gnutls_transport_ptr_t) control);
725 log_debug_msg("GnuTLS step 2...\n");
726 gnutls_transport_set_push_function(*control->ssl_session, (gnutls_push_func) & lockdownd_secuwrite);
727 log_debug_msg("GnuTLS step 3...\n");
728 gnutls_transport_set_pull_function(*control->ssl_session, (gnutls_pull_func) & lockdownd_securead);
729 log_debug_msg("GnuTLS step 4 -- now handshaking...\n");
730
731 if (errno)
732 log_debug_msg("WARN: errno says %s before handshake!\n", strerror(errno));
733 return_me = gnutls_handshake(*control->ssl_session);
734 log_debug_msg("GnuTLS handshake done...\n");
735
736 if (return_me != GNUTLS_E_SUCCESS) {
737 log_debug_msg("GnuTLS reported something wrong.\n");
738 gnutls_perror(return_me);
739 log_debug_msg("oh.. errno says %s\n", strerror(errno));
740 return IPHONE_E_SSL_ERROR;
741 } else {
742 control->in_SSL = 1;
743 return IPHONE_E_SUCCESS;
744 }
745 }
746
747 log_debug_msg("Apparently failed negotiating with lockdownd.\n");
748 log_debug_msg("Responding dictionary: \n");
749 return IPHONE_E_SSL_ERROR;
750 } else {
751 log_debug_msg("Didn't get enough bytes.\n");
752 return IPHONE_E_NOT_ENOUGH_DATA;
753 }
754}
755
756/** gnutls callback for writing data to the iPhone.
757 *
758 * @param transport It's really the lockdownd client, but the method signature has to match
759 * @param buffer The data to send
760 * @param length The length of data to send in bytes
761 *
762 * @return The number of bytes sent
763 */
764ssize_t lockdownd_secuwrite(gnutls_transport_ptr_t transport, char *buffer, size_t length)
765{
766 int bytes = 0;
767 iphone_lckd_client_t control;
768 control = (iphone_lckd_client_t) transport;
769 log_debug_msg("lockdownd_secuwrite() called\n");
770 log_debug_msg("pre-send\nlength = %zi\n", length);
771 iphone_mux_send(control->connection, buffer, length, &bytes);
772 log_debug_msg("post-send\nsent %i bytes\n", bytes);
773
774 dump_debug_buffer("sslpacketwrite.out", buffer, length);
775 return bytes;
776}
777
778/** gnutls callback for reading data from the iPhone
779 *
780 * @param transport It's really the lockdownd client, but the method signature has to match
781 * @param buffer The buffer to store data in
782 * @param length The length of data to read in bytes
783 *
784 * @return The number of bytes read
785 */
786ssize_t lockdownd_securead(gnutls_transport_ptr_t transport, char *buffer, size_t length)
787{
788 int bytes = 0, pos_start_fill = 0;
789 char *hackhackhack = NULL;
790 iphone_lckd_client_t control;
791 control = (iphone_lckd_client_t) transport;
792 log_debug_msg("lockdownd_securead() called\nlength = %zi\n", length);
793 // Buffering hack! Throw what we've got in our "buffer" into the stream first, then get more.
794 if (control->gtls_buffer_hack_len > 0) {
795 if (length > control->gtls_buffer_hack_len) { // If it's asking for more than we got
796 length -= control->gtls_buffer_hack_len; // Subtract what we have from their requested length
797 pos_start_fill = control->gtls_buffer_hack_len; // set the pos to start filling at
798 memcpy(buffer, control->gtls_buffer_hack, control->gtls_buffer_hack_len); // Fill their buffer partially
799 free(control->gtls_buffer_hack); // free our memory, it's not chained anymore
800 control->gtls_buffer_hack_len = 0; // we don't have a hack buffer anymore
801 log_debug_msg("Did a partial fill to help quench thirst for data\n");
802 } else if (length < control->gtls_buffer_hack_len) { // If it's asking for less...
803 control->gtls_buffer_hack_len -= length; // subtract what they're asking for
804 memcpy(buffer, control->gtls_buffer_hack, length); // fill their buffer
805 hackhackhack = (char *) malloc(sizeof(char) * control->gtls_buffer_hack_len); // strndup is NOT a good solution -- concatenates \0!!!! Anyway, make a new "hack" buffer.
806 memcpy(hackhackhack, control->gtls_buffer_hack + length, control->gtls_buffer_hack_len); // Move what's left into the new one
807 free(control->gtls_buffer_hack); // Free the old one
808 control->gtls_buffer_hack = hackhackhack; // And make it the new one.
809 hackhackhack = NULL;
810 log_debug_msg("Quenched the thirst for data; new hack length is %i\n", control->gtls_buffer_hack_len);
811 return length; // hand it over.
812 } else { // length == hack length
813 memcpy(buffer, control->gtls_buffer_hack, length); // copy our buffer into theirs
814 free(control->gtls_buffer_hack); // free our "obligation"
815 control->gtls_buffer_hack_len = 0; // free our "obligation"
816 log_debug_msg("Satiated the thirst for data; now we have to eventually receive again.\n");
817 return length; // hand it over
818 }
819 }
820 // End buffering hack!
821 char *recv_buffer = (char *) malloc(sizeof(char) * (length * 1000)); // ensuring nothing stupid happens
822
823 log_debug_msg("pre-read\nclient wants %zi bytes\n", length);
824 iphone_mux_recv(control->connection, recv_buffer, (length * 1000), &bytes);
825 log_debug_msg("post-read\nwe got %i bytes\n", bytes);
826 if (bytes < 0) {
827 log_debug_msg("lockdownd_securead(): uh oh\n");
828 log_debug_msg
829 ("I believe what we have here is a failure to communicate... libusb says %s but strerror says %s\n",
830 usb_strerror(), strerror(errno));
831 return bytes + 28; // an errno
832 }
833 if (bytes >= length) {
834 if (bytes > length) {
835 log_debug_msg
836 ("lockdownd_securead: Client deliberately read less data than was there; resorting to GnuTLS buffering hack.\n");
837 if (!control->gtls_buffer_hack_len) { // if there's no hack buffer yet
838 //control->gtls_buffer_hack = strndup(recv_buffer+length, bytes-length); // strndup is NOT a good solution!
839 control->gtls_buffer_hack_len += bytes - length;
840 control->gtls_buffer_hack = (char *) malloc(sizeof(char) * control->gtls_buffer_hack_len);
841 memcpy(control->gtls_buffer_hack, recv_buffer + length, control->gtls_buffer_hack_len);
842 } else { // if there is.
843 control->gtls_buffer_hack =
844 realloc(control->gtls_buffer_hack, control->gtls_buffer_hack_len + (bytes - length));
845 memcpy(control->gtls_buffer_hack + control->gtls_buffer_hack_len, recv_buffer + length, bytes - length);
846 control->gtls_buffer_hack_len += bytes - length;
847 }
848 }
849 memcpy(buffer + pos_start_fill, recv_buffer, length);
850 free(recv_buffer);
851 if (bytes == length) {
852 log_debug_msg("Returning how much we received.\n");
853 return bytes;
854 } else {
855 log_debug_msg("Returning what they want to hear.\nHack length: %i\n", control->gtls_buffer_hack_len);
856 return length;
857 }
858 }
859 return bytes;
860}
861
862/** Command to start the desired service
863 *
864 * @param control The lockdownd client
865 * @param service The name of the service to start
866 *
867 * @return The port number the service was started on or 0 on failure.
868 */
869iphone_error_t iphone_lckd_start_service(iphone_lckd_client_t client, const char *service, int *port)
870{
871 if (!client || !service || !port)
872 return IPHONE_E_INVALID_ARG;
873
874 char *host_id = get_host_id();
875 if (!host_id)
876 return IPHONE_E_INVALID_CONF;
877 if (!client->in_SSL && !lockdownd_start_SSL_session(client, host_id))
878 return IPHONE_E_SSL_ERROR;
879
880
881 plist_t dict = NULL;
882 char *XML_content = NULL;
883 uint32_t length, i = 0, port_loc = 0, bytes = 0;
884 iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR;
885
886 free(host_id);
887 host_id = NULL;
888
889 plist_new_dict(&dict);
890 plist_add_dict_element(dict, "Request", PLIST_STRING, (void *) "StartService", strlen("StartService"));
891 plist_add_dict_element(dict, "Service", PLIST_STRING, (void *) service, strlen(service));
892 plist_to_xml(dict, &XML_content, &length);
893
894 /* send to iPhone */
895 log_debug_msg("Send msg :\nsize : %i\nxml : %s", length, XML_content);
896 ret = iphone_lckd_send(client, XML_content, length, &bytes);
897
898 free(XML_content);
899 XML_content = NULL;
900 plist_free(dict);
901 dict = NULL;
902
903 if (IPHONE_E_SUCCESS != ret)
904 return ret;
905
906 ret = iphone_lckd_recv(client, &XML_content, &bytes);
907
908 if (IPHONE_E_SUCCESS != ret)
909 return ret;
910
911 xml_to_plist(XML_content, bytes, &dict);
912 if (!dict)
913 return IPHONE_E_PLIST_ERROR;
914
915
916 if (bytes <= 0)
917 return IPHONE_E_NOT_ENOUGH_DATA;
918 else {
919
920 plist_t query_node = find_query_node(dict, "Request", "StartService");
921 plist_t result_key_node = g_node_next_sibling(query_node);
922 plist_t result_value_node = g_node_next_sibling(result_key_node);
923
924 plist_t port_key_node = find_node(dict, PLIST_KEY, "Port");
925 plist_t port_value_node = g_node_next_sibling(port_key_node);
926
927 plist_type result_key_type;
928 plist_type result_value_type;
929 plist_type port_key_type;
930 plist_type port_value_type;
931 char *result_key = NULL;
932 char *result_value = NULL;
933 char *port_key = NULL;
934 uint64_t res_key_length = 0;
935 uint64_t res_val_length = 0;
936 uint64_t port_key_length = 0;
937 uint64_t port_val_length = 0;
938 uint64_t port_value = 0;
939
940 get_type_and_value(result_key_node, &result_key_type, (void *) (&result_key), &res_key_length);
941 get_type_and_value(result_value_node, &result_value_type, (void *) (&result_value), &res_val_length);
942 get_type_and_value(port_key_node, &port_key_type, (void *) (&port_key), &port_key_length);
943 get_type_and_value(port_value_node, &port_value_type, (void *) (&port_value), &port_val_length);
944
945 if (result_key_type == PLIST_KEY &&
946 result_value_type == PLIST_STRING &&
947 port_key_type == PLIST_KEY &&
948 port_value_type == PLIST_UINT &&
949 !strcmp(result_key, "Result") && !strcmp(result_value, "Success") && !strcmp(port_key, "Port")) {
950 port_loc = port_value;
951 ret = IPHONE_E_SUCCESS;
952 }
953
954 log_debug_msg("lockdownd_start_service(): DATA RECEIVED:\n\n");
955 log_debug_msg(XML_content);
956 log_debug_msg("end data received by lockdownd_start_service()\n");
957
958 free(XML_content);
959 plist_free(dict);
960 dict = NULL;
961 if (port && ret == IPHONE_E_SUCCESS) {
962 *port = port_loc;
963 return IPHONE_E_SUCCESS;
964 } else
965 return IPHONE_E_UNKNOWN_ERROR;
966 }
967
968 return IPHONE_E_UNKNOWN_ERROR;
969}