summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Martin Szulecki2014-03-21 00:16:29 +0100
committerGravatar Martin Szulecki2014-03-21 00:16:29 +0100
commitd1ccd4eeebc94dac11140ae77b73392d0763d3a4 (patch)
treefb5fa6cab2bdaf55b28004921960d331db59bf7b
parent88ce6113593158944630435678e689bf155d9a03 (diff)
downloadlibimobiledevice-d1ccd4eeebc94dac11140ae77b73392d0763d3a4.tar.gz
libimobiledevice-d1ccd4eeebc94dac11140ae77b73392d0763d3a4.tar.bz2
Refactor pair record handling to use new usbmuxd pair record interface
This refactoring is mandatory as libimobiledevice should not interact with the pair record configuration directory which is owned by the usbmuxd user. This change also adds compatibility for the native usbmuxd and thus pair records saved by iTunes.
-rw-r--r--common/userpref.c989
-rw-r--r--common/userpref.h34
-rw-r--r--common/utils.c30
-rw-r--r--common/utils.h1
-rw-r--r--src/idevice.c31
-rw-r--r--src/lockdown.c530
-rw-r--r--src/lockdown.h5
-rw-r--r--tools/idevicepair.c12
8 files changed, 608 insertions, 1024 deletions
diff --git a/common/userpref.c b/common/userpref.c
index c192c1d..d9641cb 100644
--- a/common/userpref.c
+++ b/common/userpref.c
@@ -35,6 +35,7 @@
35#include <pwd.h> 35#include <pwd.h>
36#endif 36#endif
37#include <unistd.h> 37#include <unistd.h>
38#include <usbmuxd.h>
38#ifdef HAVE_OPENSSL 39#ifdef HAVE_OPENSSL
39#include <openssl/pem.h> 40#include <openssl/pem.h>
40#include <openssl/rsa.h> 41#include <openssl/rsa.h>
@@ -59,6 +60,17 @@
59#include "debug.h" 60#include "debug.h"
60#include "utils.h" 61#include "utils.h"
61 62
63#ifndef HAVE_OPENSSL
64const ASN1_ARRAY_TYPE pkcs1_asn1_tab[] = {
65 {"PKCS1", 536872976, 0},
66 {0, 1073741836, 0},
67 {"RSAPublicKey", 536870917, 0},
68 {"modulus", 1073741827, 0},
69 {"publicExponent", 3, 0},
70 {0, 0, 0}
71};
72#endif
73
62#ifdef WIN32 74#ifdef WIN32
63#define DIR_SEP '\\' 75#define DIR_SEP '\\'
64#define DIR_SEP_S "\\" 76#define DIR_SEP_S "\\"
@@ -158,274 +170,20 @@ const char *userpref_get_config_dir()
158 return __config_dir; 170 return __config_dir;
159} 171}
160 172
161static int __mkdir(const char *dir, int mode)
162{
163#ifdef WIN32
164 return mkdir(dir);
165#else
166 return mkdir(dir, mode);
167#endif
168}
169
170static int mkdir_with_parents(const char *dir, int mode)
171{
172 if (!dir) return -1;
173 if (__mkdir(dir, mode) == 0) {
174 return 0;
175 } else {
176 if (errno == EEXIST) return 0;
177 }
178 int res;
179 char *parent = strdup(dir);
180 char* parentdir = dirname(parent);
181 if (parentdir) {
182 res = mkdir_with_parents(parentdir, mode);
183 } else {
184 res = -1;
185 }
186 free(parent);
187 return res;
188}
189
190/**
191 * Creates a freedesktop compatible configuration directory.
192 */
193static void userpref_create_config_dir(void)
194{
195 const char *config_path = userpref_get_config_dir();
196 struct stat st;
197 if (stat(config_path, &st) != 0) {
198 mkdir_with_parents(config_path, 0755);
199 }
200}
201
202static int get_rand(int min, int max)
203{
204 int retval = (rand() % (max - min)) + min;
205 return retval;
206}
207
208/**
209 * Generates a valid HostID (which is actually a UUID).
210 *
211 * @return A null terminated string containing a valid HostID.
212 */
213static char *userpref_generate_host_id(int idx)
214{
215 /* HostID's are just UUID's, and UUID's are 36 characters long */
216 char *hostid = (char *) malloc(sizeof(char) * 37);
217 const char *chars = "ABCDEF0123456789";
218 srand(time(NULL) - idx);
219 int i = 0;
220
221 for (i = 0; i < 36; i++) {
222 if (i == 8 || i == 13 || i == 18 || i == 23) {
223 hostid[i] = '-';
224 continue;
225 } else {
226 hostid[i] = chars[get_rand(0, 16)];
227 }
228 }
229 /* make it a real string */
230 hostid[36] = '\0';
231 return hostid;
232}
233
234/**
235 * Generates a valid BUID for this system (which is actually a UUID).
236 *
237 * @return A null terminated string containing a valid BUID.
238 */
239static char *userpref_generate_system_buid()
240{
241 return userpref_generate_host_id(1);
242}
243
244static int internal_set_value(const char *config_file, const char *key, plist_t value)
245{
246 if (!config_file)
247 return 0;
248
249 /* read file into plist */
250 plist_t config = NULL;
251
252 plist_read_from_filename(&config, config_file);
253 if (!config) {
254 config = plist_new_dict();
255 plist_dict_set_item(config, key, value);
256 } else {
257 plist_t n = plist_dict_get_item(config, key);
258 if (n) {
259 plist_dict_remove_item(config, key);
260 }
261 plist_dict_set_item(config, key, value);
262 remove(config_file);
263 }
264
265 /* store in config file */
266 char *value_string = NULL;
267 if (plist_get_node_type(value) == PLIST_STRING) {
268 plist_get_string_val(value, &value_string);
269 debug_info("setting key %s to %s in config_file %s", key, value_string, config_file);
270 if (value_string)
271 free(value_string);
272 } else {
273 debug_info("setting key %s in config_file %s", key, config_file);
274 }
275
276 plist_write_to_filename(config, config_file, PLIST_FORMAT_XML);
277
278 plist_free(config);
279
280 return 1;
281}
282
283int userpref_set_value(const char *key, plist_t value)
284{
285 const char *config_path = NULL;
286 char *config_file = NULL;
287
288 /* Make sure config directory exists */
289 userpref_create_config_dir();
290
291 config_path = userpref_get_config_dir();
292 config_file = string_concat(config_path, DIR_SEP_S, USERPREF_CONFIG_FILE, NULL);
293
294 int result = internal_set_value(config_file, key, value);
295
296 free(config_file);
297
298 return result;
299}
300
301int userpref_device_record_set_value(const char *udid, const char *key, plist_t value)
302{
303 const char *config_path = NULL;
304 char *config_file = NULL;
305
306 /* Make sure config directory exists */
307 userpref_create_config_dir();
308
309 config_path = userpref_get_config_dir();
310 config_file = string_concat(config_path, DIR_SEP_S, udid, USERPREF_CONFIG_EXTENSION, NULL);
311
312 int result = internal_set_value(config_file, key, value);
313
314 free(config_file);
315
316 return result;
317}
318
319static int internal_get_value(const char* config_file, const char *key, plist_t *value)
320{
321 *value = NULL;
322
323 /* now parse file to get the SystemBUID */
324 plist_t config = NULL;
325 if (plist_read_from_filename(&config, config_file)) {
326 debug_info("reading key %s from config_file %s", key, config_file);
327 plist_t n = plist_dict_get_item(config, key);
328 if (n) {
329 *value = plist_copy(n);
330 n = NULL;
331 }
332 }
333 plist_free(config);
334
335 return 1;
336}
337
338int userpref_get_value(const char *key, plist_t *value)
339{
340 const char *config_path = NULL;
341 char *config_file = NULL;
342
343 config_path = userpref_get_config_dir();
344 config_file = string_concat(config_path, DIR_SEP_S, USERPREF_CONFIG_FILE, NULL);
345
346 int result = internal_get_value(config_file, key, value);
347
348 free(config_file);
349
350 return result;
351}
352
353int userpref_device_record_get_value(const char *udid, const char *key, plist_t *value)
354{
355 const char *config_path = NULL;
356 char *config_file = NULL;
357
358 config_path = userpref_get_config_dir();
359 config_file = string_concat(config_path, DIR_SEP_S, udid, USERPREF_CONFIG_EXTENSION, NULL);
360
361 int result = internal_get_value(config_file, key, value);
362
363 free(config_file);
364
365 return result;
366}
367
368/**
369 * Store SystemBUID in config file.
370 *
371 * @param host_id A null terminated string containing a valid SystemBUID.
372 */
373static int userpref_set_system_buid(const char *system_buid)
374{
375 return userpref_set_value(USERPREF_SYSTEM_BUID_KEY, plist_new_string(system_buid));
376}
377
378/** 173/**
379 * Reads the BUID from a previously generated configuration file. 174 * Reads the BUID from a previously generated configuration file.
380 * 175 *
381 * @note It is the responsibility of the calling function to free the returned system_buid 176 * @note It is the responsibility of the calling function to free the returned system_buid
382 * 177 * @param system_buid A null terminated string containing a valid SystemBUID.
383 * @return The string containing the BUID or NULL 178 * @return 1 if the system buid could be retrieved or 0 otherwise.
384 */ 179 */
385void userpref_get_system_buid(char **system_buid) 180int userpref_read_system_buid(char **system_buid)
386{ 181{
387 plist_t value = NULL; 182 int res = usbmuxd_read_buid(system_buid);
388
389 userpref_get_value(USERPREF_SYSTEM_BUID_KEY, &value);
390
391 if (value && (plist_get_node_type(value) == PLIST_STRING)) {
392 plist_get_string_val(value, system_buid);
393 debug_info("got %s %s", USERPREF_SYSTEM_BUID_KEY, *system_buid);
394 }
395
396 if (value)
397 plist_free(value);
398
399 if (!*system_buid) {
400 /* no config, generate system_buid */
401 debug_info("no previous %s found", USERPREF_SYSTEM_BUID_KEY);
402 *system_buid = userpref_generate_system_buid();
403 userpref_set_system_buid(*system_buid);
404 }
405 183
406 debug_info("using %s as %s", *system_buid, USERPREF_SYSTEM_BUID_KEY); 184 debug_info("using %s as %s", *system_buid, USERPREF_SYSTEM_BUID_KEY);
407}
408
409void userpref_device_record_get_host_id(const char *udid, char **host_id)
410{
411 plist_t value = NULL;
412
413 userpref_device_record_get_value(udid, USERPREF_HOST_ID_KEY, &value);
414
415 if (value && (plist_get_node_type(value) == PLIST_STRING)) {
416 plist_get_string_val(value, host_id);
417 }
418
419 if (value)
420 plist_free(value);
421 185
422 if (!*host_id) { 186 return res;
423 /* no config, generate host_id */
424 *host_id = userpref_generate_host_id(0);
425 userpref_device_record_set_value(udid, USERPREF_HOST_ID_KEY, plist_new_string(*host_id));
426 }
427
428 debug_info("using %s as %s", *host_id, USERPREF_HOST_ID_KEY);
429} 187}
430 188
431/** 189/**
@@ -436,7 +194,7 @@ void userpref_device_record_get_host_id(const char *udid, char **host_id)
436 * @return 1 if the device has been connected previously to this configuration 194 * @return 1 if the device has been connected previously to this configuration
437 * or 0 otherwise. 195 * or 0 otherwise.
438 */ 196 */
439int userpref_has_device_record(const char *udid) 197int userpref_has_pair_record(const char *udid)
440{ 198{
441 int ret = 0; 199 int ret = 0;
442 const char *config_path = NULL; 200 const char *config_path = NULL;
@@ -536,50 +294,61 @@ userpref_error_t userpref_get_paired_udids(char ***list, unsigned int *count)
536} 294}
537 295
538/** 296/**
539 * Mark the device as having connected to this configuration. 297 * Save a pair record for a device.
540 * 298 *
541 * @param udid The device UDID as given by the device 299 * @param udid The device UDID as given by the device
542 * @param device_record The device record with full configuration 300 * @param pair_record The pair record to save
543 * 301 *
544 * @return 1 on success and 0 if no device record is given or if it has already 302 * @return 1 on success and 0 if no device record is given or if it has already
545 * been marked as connected previously. 303 * been saved previously.
546 */ 304 */
547userpref_error_t userpref_set_device_record(const char *udid, plist_t device_record) 305userpref_error_t userpref_save_pair_record(const char *udid, plist_t pair_record)
548{ 306{
549 /* ensure config directory exists */ 307 char* record_data = NULL;
550 userpref_create_config_dir(); 308 uint32_t record_size = 0;
551 309
552 /* build file path */ 310 plist_to_bin(pair_record, &record_data, &record_size);
553 const char *config_path = userpref_get_config_dir();
554 char *device_record_file = string_concat(config_path, DIR_SEP_S, udid, USERPREF_CONFIG_EXTENSION, NULL);
555 311
556 remove(device_record_file); 312 int res = usbmuxd_save_pair_record(udid, record_data, record_size);
557 313
558 /* store file */ 314 free(record_data);
559 if (!plist_write_to_filename(device_record, device_record_file, PLIST_FORMAT_XML)) {
560 debug_info("could not open '%s' for writing: %s", device_record_file, strerror(errno));
561 }
562 free(device_record_file);
563 315
564 return USERPREF_E_SUCCESS; 316 return res == 0 ? USERPREF_E_SUCCESS: USERPREF_E_UNKNOWN_ERROR;
565} 317}
566 318
567userpref_error_t userpref_get_device_record(const char *udid, plist_t *device_record) 319/**
320 * Read a pair record for a device.
321 *
322 * @param udid The device UDID as given by the device
323 * @param pair_record The pair record to read
324 *
325 * @return 1 on success and 0 if no device record is given or if it has already
326 * been saved previously.
327 */
328userpref_error_t userpref_read_pair_record(const char *udid, plist_t *pair_record)
568{ 329{
569 /* ensure config directory exists */ 330 char* record_data = NULL;
570 userpref_create_config_dir(); 331 uint32_t record_size = 0;
332
333 int res = usbmuxd_read_pair_record(udid, &record_data, &record_size);
571 334
572 /* build file path */ 335 if (res < 0) {
573 const char *config_path = userpref_get_config_dir(); 336 if (record_data)
574 char *device_record_file = string_concat(config_path, DIR_SEP_S, udid, USERPREF_CONFIG_EXTENSION, NULL); 337 free(record_data);
575 338
576 /* read file */ 339 return USERPREF_E_INVALID_CONF;
577 if (!plist_read_from_filename(device_record, device_record_file)) {
578 debug_info("could not open '%s' for reading: %s", device_record_file, strerror(errno));
579 } 340 }
580 free(device_record_file);
581 341
582 return USERPREF_E_SUCCESS; 342 *pair_record = NULL;
343 if (memcmp(record_data, "bplist00", 8) == 0) {
344 plist_from_bin(record_data, record_size, pair_record);
345 } else {
346 plist_from_xml(record_data, record_size, pair_record);
347 }
348
349 free(record_data);
350
351 return res == 0 ? USERPREF_E_SUCCESS: USERPREF_E_UNKNOWN_ERROR;
583} 352}
584 353
585/** 354/**
@@ -589,87 +358,33 @@ userpref_error_t userpref_get_device_record(const char *udid, plist_t *device_re
589 * 358 *
590 * @return USERPREF_E_SUCCESS on success. 359 * @return USERPREF_E_SUCCESS on success.
591 */ 360 */
592userpref_error_t userpref_remove_device_record(const char *udid) 361userpref_error_t userpref_delete_pair_record(const char *udid)
593{ 362{
594 userpref_error_t res = USERPREF_E_SUCCESS; 363 int res = usbmuxd_delete_pair_record(udid);
595 if (!userpref_has_device_record(udid))
596 return res;
597
598 /* build file path */
599 const char *config_path = userpref_get_config_dir();
600 char *device_record_file = string_concat(config_path, DIR_SEP_S, udid, USERPREF_CONFIG_EXTENSION, NULL);
601
602 /* remove file */
603 if (remove(device_record_file) != 0) {
604 debug_info("could not remove %s: %s", device_record_file, strerror(errno));
605 res = USERPREF_E_UNKNOWN_ERROR;
606 }
607 364
608 free(device_record_file); 365 return res == 0 ? USERPREF_E_SUCCESS: USERPREF_E_UNKNOWN_ERROR;
609
610 return res;
611} 366}
612 367
613#if 0 368#ifdef HAVE_OPENSSL
614/** 369static int X509_add_ext_helper(X509 *cert, int nid, char *value)
615 * Private function which reads the given file into a key_data_t structure.
616 *
617 * @param file The filename of the file to read
618 * @param data The pointer at which to store the data.
619 *
620 * @return 1 if the file contents where read successfully and 0 otherwise.
621 */
622static int userpref_get_file_contents(const char *file, key_data_t * data)
623{ 370{
624 int success = 0; 371 X509_EXTENSION *ex;
625 unsigned long int size = 0; 372 X509V3_CTX ctx;
626 unsigned char *content = NULL;
627 const char *config_path = NULL;
628 char *filepath;
629 FILE *fd;
630
631 if (NULL == file || NULL == data)
632 return 0;
633
634 /* Read file */
635 config_path = userpref_get_config_dir();
636 filepath = string_concat(config_path, DIR_SEP_S, file, NULL);
637 373
638 fd = fopen(filepath, "rb"); 374 /* No configuration database */
639 if (fd) { 375 X509V3_set_ctx_nodb(&ctx);
640 fseek(fd, 0, SEEK_END);
641 size = ftell(fd);
642 fseek(fd, 0, SEEK_SET);
643 376
644 // prevent huge files 377 X509V3_set_ctx(&ctx, NULL, cert, NULL, NULL, 0);
645 if (size > 0xFFFFFF) { 378 ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
646 fprintf(stderr, "%s: file is too big (> 16MB). Refusing to read the contents to memory!", __func__); 379 if (!ex) {
647 } else { 380 debug_info("ERROR: X509V3_EXT_conf_nid(%d, %s) failed", nid, value);
648 size_t p = 0; 381 return 0;
649 content = (unsigned char*)malloc(size);
650 while (!feof(fd)) {
651 p += fread(content+p, 1, size-p, fd);
652 if (ferror(fd) != 0) {
653 break;
654 }
655 if (p >= size) {
656 success = 1;
657 break;
658 }
659 }
660 }
661 fclose(fd);
662 } 382 }
663 383
664 free(filepath); 384 X509_add_ext(cert, ex, -1);
385 X509_EXTENSION_free(ex);
665 386
666 /* Add it to the key_data_t structure */ 387 return 1;
667 if (success) {
668 data->data = (uint8_t*) content;
669 data->size = size;
670 }
671
672 return success;
673} 388}
674#endif 389#endif
675 390
@@ -678,7 +393,7 @@ static int userpref_get_file_contents(const char *file, key_data_t * data)
678 * 393 *
679 * @return 1 if keys were successfully generated, 0 otherwise 394 * @return 1 if keys were successfully generated, 0 otherwise
680 */ 395 */
681static userpref_error_t userpref_device_record_gen_keys_and_cert(const char* udid) 396userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record)
682{ 397{
683 userpref_error_t ret = USERPREF_E_SSL_ERROR; 398 userpref_error_t ret = USERPREF_E_SSL_ERROR;
684 399
@@ -687,7 +402,8 @@ static userpref_error_t userpref_device_record_gen_keys_and_cert(const char* udi
687 key_data_t host_key_pem = { NULL, 0 }; 402 key_data_t host_key_pem = { NULL, 0 };
688 key_data_t host_cert_pem = { NULL, 0 }; 403 key_data_t host_cert_pem = { NULL, 0 };
689 404
690 debug_info("generating keys and certificates"); 405 debug_info("Generating keys and certificates...");
406
691#ifdef HAVE_OPENSSL 407#ifdef HAVE_OPENSSL
692 BIGNUM *e = BN_new(); 408 BIGNUM *e = BN_new();
693 RSA* root_keypair = RSA_new(); 409 RSA* root_keypair = RSA_new();
@@ -719,11 +435,7 @@ static userpref_error_t userpref_device_record_gen_keys_and_cert(const char* udi
719 X509_set_version(root_cert, 2); 435 X509_set_version(root_cert, 2);
720 436
721 /* set x509v3 basic constraints */ 437 /* set x509v3 basic constraints */
722 X509_EXTENSION* ext; 438 X509_add_ext_helper(root_cert, NID_basic_constraints, (char*)"critical,CA:TRUE");
723 if (!(ext = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints, (char*)"critical,CA:TRUE"))) {
724 debug_info("ERROR: X509V3_EXT_conf_nid failed");
725 }
726 X509_add_ext(root_cert, ext, -1);
727 439
728 /* set key validity */ 440 /* set key validity */
729 ASN1_TIME* asn1time = ASN1_TIME_new(); 441 ASN1_TIME* asn1time = ASN1_TIME_new();
@@ -735,6 +447,7 @@ static userpref_error_t userpref_device_record_gen_keys_and_cert(const char* udi
735 447
736 /* use root public key for root cert */ 448 /* use root public key for root cert */
737 X509_set_pubkey(root_cert, root_pkey); 449 X509_set_pubkey(root_cert, root_pkey);
450
738 /* sign root cert with root private key */ 451 /* sign root cert with root private key */
739 X509_sign(root_cert, root_pkey, EVP_sha1()); 452 X509_sign(root_cert, root_pkey, EVP_sha1());
740 } 453 }
@@ -752,17 +465,10 @@ static userpref_error_t userpref_device_record_gen_keys_and_cert(const char* udi
752 X509_set_version(host_cert, 2); 465 X509_set_version(host_cert, 2);
753 466
754 /* set x509v3 basic constraints */ 467 /* set x509v3 basic constraints */
755 X509_EXTENSION* ext; 468 X509_add_ext_helper(host_cert, NID_basic_constraints, (char*)"critical,CA:FALSE");
756 if (!(ext = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints, (char*)"critical,CA:FALSE"))) {
757 debug_info("ERROR: X509V3_EXT_conf_nid failed");
758 }
759 X509_add_ext(host_cert, ext, -1);
760 469
761 /* set x509v3 key usage */ 470 /* set x509v3 key usage */
762 if (!(ext = X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage, (char*)"digitalSignature,keyEncipherment"))) { 471 X509_add_ext_helper(host_cert, NID_key_usage, (char*)"critical,digitalSignature,keyEncipherment");
763 debug_info("ERROR: X509V3_EXT_conf_nid failed");
764 }
765 X509_add_ext(host_cert, ext, -1);
766 472
767 /* set key validity */ 473 /* set key validity */
768 ASN1_TIME* asn1time = ASN1_TIME_new(); 474 ASN1_TIME* asn1time = ASN1_TIME_new();
@@ -907,8 +613,11 @@ static userpref_error_t userpref_device_record_gen_keys_and_cert(const char* udi
907 NULL != host_cert_pem.data && 0 != host_cert_pem.size) 613 NULL != host_cert_pem.data && 0 != host_cert_pem.size)
908 ret = USERPREF_E_SUCCESS; 614 ret = USERPREF_E_SUCCESS;
909 615
910 /* store values in config file */ 616 /* now set keys and certificates */
911 userpref_device_record_set_keys_and_certs(udid, &root_key_pem, &root_cert_pem, &host_key_pem, &host_cert_pem); 617 pair_record_set_item_from_key_data(pair_record, USERPREF_HOST_PRIVATE_KEY_KEY, &host_key_pem);
618 pair_record_set_item_from_key_data(pair_record, USERPREF_HOST_CERTIFICATE_KEY, &root_cert_pem);
619 pair_record_set_item_from_key_data(pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY, &root_key_pem);
620 pair_record_set_item_from_key_data(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, &host_cert_pem);
912 621
913 if (root_key_pem.data) 622 if (root_key_pem.data)
914 free(root_key_pem.data); 623 free(root_key_pem.data);
@@ -923,6 +632,284 @@ static userpref_error_t userpref_device_record_gen_keys_and_cert(const char* udi
923} 632}
924 633
925/** 634/**
635 * Generates the device certificate from the public key as well as the host
636 * and root certificates.
637 *
638 * @param pair_record The pair record to use for lookup of key pairs
639 * @param public_key The public key of the device to use for generation.
640 *
641 * @return USERPREF_E_SUCCESS on success, USERPREF_E_INVALID_ARG when a
642 * parameter is NULL, USERPREF_E_INVALID_CONF if the internal configuration
643 * system failed, USERPREF_E_SSL_ERROR if the certificates could not be
644 * generated
645 */
646userpref_error_t pair_record_generate_from_device_public_key(plist_t pair_record, key_data_t public_key)
647{
648 if (!pair_record || !public_key.data)
649 return USERPREF_E_INVALID_ARG;
650
651 userpref_error_t uret = USERPREF_E_UNKNOWN_ERROR;
652
653#ifdef HAVE_OPENSSL
654 BIO *membio = BIO_new_mem_buf(public_key.data, public_key.size);
655 RSA *pubkey = NULL;
656 if (!PEM_read_bio_RSAPublicKey(membio, &pubkey, NULL, NULL)) {
657 debug_info("Could not read public key");
658 }
659 BIO_free(membio);
660
661 /* now generate certificates */
662 key_data_t root_privkey, host_privkey;
663 key_data_t root_cert, host_cert;
664
665 X509* dev_cert = X509_new();
666
667 root_cert.data = NULL;
668 root_cert.size = 0;
669 host_cert.data = NULL;
670 host_cert.size = 0;
671
672 root_privkey.data = NULL;
673 root_privkey.size = 0;
674 host_privkey.data = NULL;
675 host_privkey.size = 0;
676
677 uret = pair_record_import_key_with_name(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, &root_cert);
678 uret = pair_record_import_key_with_name(pair_record, USERPREF_HOST_CERTIFICATE_KEY, &host_cert);
679 uret = pair_record_import_key_with_name(pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY, &root_privkey);
680 uret = pair_record_import_key_with_name(pair_record, USERPREF_HOST_PRIVATE_KEY_KEY, &host_privkey);
681
682 if (USERPREF_E_SUCCESS == uret) {
683 /* generate device certificate */
684 ASN1_INTEGER* sn = ASN1_INTEGER_new();
685 ASN1_INTEGER_set(sn, 0);
686 X509_set_serialNumber(dev_cert, sn);
687 ASN1_INTEGER_free(sn);
688 X509_set_version(dev_cert, 2);
689
690 X509_add_ext_helper(dev_cert, NID_basic_constraints, (char*)"critical,CA:FALSE");
691
692 ASN1_TIME* asn1time = ASN1_TIME_new();
693 ASN1_TIME_set(asn1time, time(NULL));
694 X509_set_notBefore(dev_cert, asn1time);
695 ASN1_TIME_set(asn1time, time(NULL) + (60 * 60 * 24 * 365 * 10));
696 X509_set_notAfter(dev_cert, asn1time);
697 ASN1_TIME_free(asn1time);
698
699 /* read root certificate */
700 BIO* membp;
701 X509* rootCert = NULL;
702 membp = BIO_new_mem_buf(root_cert.data, root_cert.size);
703 PEM_read_bio_X509(membp, &rootCert, NULL, NULL);
704 BIO_free(membp);
705 if (!rootCert) {
706 debug_info("Could not read RootCertificate");
707 } else {
708 debug_info("RootCertificate loaded");
709 EVP_PKEY* pkey = EVP_PKEY_new();
710 EVP_PKEY_assign_RSA(pkey, pubkey);
711 X509_set_pubkey(dev_cert, pkey);
712 EVP_PKEY_free(pkey);
713 X509_free(rootCert);
714 }
715
716 X509_add_ext_helper(dev_cert, NID_subject_key_identifier, (char*)"hash");
717 X509_add_ext_helper(dev_cert, NID_key_usage, (char*)"critical,digitalSignature,keyEncipherment");
718
719 /* read root private key */
720 EVP_PKEY* rootPriv = NULL;
721 membp = BIO_new_mem_buf(root_privkey.data, root_privkey.size);
722 PEM_read_bio_PrivateKey(membp, &rootPriv, NULL, NULL);
723 BIO_free(membp);
724 if (!rootPriv) {
725 debug_info("Could not read RootPrivateKey");
726 } else {
727 debug_info("RootPrivateKey loaded");
728 if (X509_sign(dev_cert, rootPriv, EVP_sha1())) {
729 uret = USERPREF_E_SUCCESS;
730 } else {
731 debug_info("signing failed");
732 }
733 EVP_PKEY_free(rootPriv);
734 }
735
736 if (USERPREF_E_SUCCESS == uret) {
737 /* if everything went well, export in PEM format */
738 key_data_t pem_root_cert = { NULL, 0 };
739 key_data_t pem_host_cert = { NULL, 0 };
740
741 uret = pair_record_import_key_with_name(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, &pem_root_cert);
742 uret = pair_record_import_key_with_name(pair_record, USERPREF_HOST_CERTIFICATE_KEY, &pem_host_cert);
743
744 if (USERPREF_E_SUCCESS == uret) {
745 /* set new keys and certs in pair record */
746 membp = BIO_new(BIO_s_mem());
747 if (membp && PEM_write_bio_X509(membp, dev_cert) > 0) {
748 void *datap;
749 int size = BIO_get_mem_data(membp, &datap);
750 plist_dict_set_item(pair_record, USERPREF_DEVICE_CERTIFICATE_KEY, plist_new_data(datap, size));
751 }
752 if (membp)
753 BIO_free(membp);
754
755 plist_dict_set_item(pair_record, USERPREF_HOST_CERTIFICATE_KEY, plist_new_data((char*)pem_host_cert.data, pem_host_cert.size));
756 plist_dict_set_item(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, plist_new_data((char*)pem_root_cert.data, pem_root_cert.size));
757 plist_dict_set_item(pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY, plist_new_data((char*)root_privkey.data, root_privkey.size));
758 plist_dict_set_item(pair_record, USERPREF_HOST_PRIVATE_KEY_KEY, plist_new_data((char*)host_privkey.data, host_privkey.size));
759
760 free(pem_root_cert.data);
761 free(pem_host_cert.data);
762 }
763 }
764 }
765 X509V3_EXT_cleanup();
766 X509_free(dev_cert);
767
768 if (root_cert.data)
769 free(root_cert.data);
770 if (host_cert.data)
771 free(host_cert.data);
772 if (root_privkey.data)
773 free(root_privkey.data);
774 if (host_privkey.data)
775 free(host_privkey.data);
776#else
777 gnutls_datum_t modulus = { NULL, 0 };
778 gnutls_datum_t exponent = { NULL, 0 };
779
780 /* now decode the PEM encoded key */
781 gnutls_datum_t der_pub_key;
782 if (GNUTLS_E_SUCCESS == gnutls_pem_base64_decode_alloc("RSA PUBLIC KEY", &public_key, &der_pub_key)) {
783
784 /* initalize asn.1 parser */
785 ASN1_TYPE pkcs1 = ASN1_TYPE_EMPTY;
786 if (ASN1_SUCCESS == asn1_array2tree(pkcs1_asn1_tab, &pkcs1, NULL)) {
787
788 ASN1_TYPE asn1_pub_key = ASN1_TYPE_EMPTY;
789 asn1_create_element(pkcs1, "PKCS1.RSAPublicKey", &asn1_pub_key);
790
791 if (ASN1_SUCCESS == asn1_der_decoding(&asn1_pub_key, der_pub_key.data, der_pub_key.size, NULL)) {
792
793 /* get size to read */
794 int ret1 = asn1_read_value(asn1_pub_key, "modulus", NULL, (int*)&modulus.size);
795 int ret2 = asn1_read_value(asn1_pub_key, "publicExponent", NULL, (int*)&exponent.size);
796
797 modulus.data = gnutls_malloc(modulus.size);
798 exponent.data = gnutls_malloc(exponent.size);
799
800 ret1 = asn1_read_value(asn1_pub_key, "modulus", modulus.data, (int*)&modulus.size);
801 ret2 = asn1_read_value(asn1_pub_key, "publicExponent", exponent.data, (int*)&exponent.size);
802 if (ASN1_SUCCESS == ret1 && ASN1_SUCCESS == ret2)
803 uret = USERPREF_E_SUCCESS;
804 }
805 if (asn1_pub_key)
806 asn1_delete_structure(&asn1_pub_key);
807 }
808 if (pkcs1)
809 asn1_delete_structure(&pkcs1);
810 }
811
812 /* now generate certificates */
813 if (USERPREF_E_SUCCESS == uret && 0 != modulus.size && 0 != exponent.size) {
814
815 gnutls_global_init();
816 gnutls_datum_t essentially_null = { (unsigned char*)strdup("abababababababab"), strlen("abababababababab") };
817
818 gnutls_x509_privkey_t fake_privkey, root_privkey, host_privkey;
819 gnutls_x509_crt_t dev_cert, root_cert, host_cert;
820
821 gnutls_x509_privkey_init(&fake_privkey);
822 gnutls_x509_privkey_init(&root_privkey);
823 gnutls_x509_privkey_init(&host_privkey);
824
825 gnutls_x509_crt_init(&dev_cert);
826 gnutls_x509_crt_init(&root_cert);
827 gnutls_x509_crt_init(&host_cert);
828
829 if (GNUTLS_E_SUCCESS ==
830 gnutls_x509_privkey_import_rsa_raw(fake_privkey, &modulus, &exponent, &essentially_null, &essentially_null,
831 &essentially_null, &essentially_null)) {
832
833 uret = pair_record_import_key_with_name(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, root_cert);
834 uret = pair_record_import_key_with_name(pair_record, USERPREF_HOST_CERTIFICATE_KEY, host_cert);
835 uret = pair_record_import_key_with_name(pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY, root_privkey);
836 uret = pair_record_import_key_with_name(pair_record, USERPREF_HOST_PRIVATE_KEY_KEY, host_privkey);
837
838 if (USERPREF_E_SUCCESS == uret) {
839 /* generate device certificate */
840 gnutls_x509_crt_set_key(dev_cert, fake_privkey);
841 gnutls_x509_crt_set_serial(dev_cert, "\x00", 1);
842 gnutls_x509_crt_set_version(dev_cert, 3);
843 gnutls_x509_crt_set_ca_status(dev_cert, 0);
844 gnutls_x509_crt_set_activation_time(dev_cert, time(NULL));
845 gnutls_x509_crt_set_expiration_time(dev_cert, time(NULL) + (60 * 60 * 24 * 365 * 10));
846
847 /* use custom hash generation for compatibility with the "Apple ecosystem" */
848 const gnutls_digest_algorithm_t dig_sha1 = GNUTLS_DIG_SHA1;
849 size_t hash_size = gnutls_hash_get_len(dig_sha1);
850 unsigned char hash[hash_size];
851 if (gnutls_hash_fast(dig_sha1, der_pub_key.data, der_pub_key.size, (unsigned char*)&hash) < 0) {
852 debug_info("ERROR: Failed to generate SHA1 for public key");
853 } else {
854 gnutls_x509_crt_set_subject_key_id(dev_cert, hash, hash_size);
855 }
856
857 gnutls_x509_crt_set_key_usage(dev_cert, GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT);
858 gnutls_x509_crt_sign(dev_cert, root_cert, root_privkey);
859
860 if (LOCKDOWN_E_SUCCESS == ret) {
861 /* if everything went well, export in PEM format */
862 size_t export_size = 0;
863 gnutls_datum_t dev_pem = { NULL, 0 };
864 gnutls_x509_crt_export(dev_cert, GNUTLS_X509_FMT_PEM, NULL, &export_size);
865 dev_pem.data = gnutls_malloc(export_size);
866 gnutls_x509_crt_export(dev_cert, GNUTLS_X509_FMT_PEM, dev_pem.data, &export_size);
867 dev_pem.size = export_size;
868
869 gnutls_datum_t pem_root_cert = { NULL, 0 };
870 gnutls_datum_t pem_host_cert = { NULL, 0 };
871
872 uret = pair_record_import_key_with_name(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, &pem_root_cert);
873 uret = pair_record_import_key_with_name(pair_record, USERPREF_HOST_CERTIFICATE_KEY, &pem_host_cert);
874
875 if (USERPREF_E_SUCCESS == uret) {
876 /* set new keys and certs in pair record */
877 plist_dict_set_item(pair_record, USERPREF_DEVICE_CERTIFICATE_KEY, plist_new_data(dev_pem.data, dev_pem.size));
878 plist_dict_set_item(pair_record, USERPREF_HOST_CERTIFICATE_KEY, plist_new_data(pem_host_cert.data, pem_host_cert.size));
879 plist_dict_set_item(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, plist_new_data(pem_root_cert.data, pem_root_cert.size));
880 plist_dict_set_item(pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY, plist_new_data(root_privkey.data, root_privkey.size));
881 plist_dict_set_item(pair_record, USERPREF_HOST_PRIVATE_KEY_KEY, plist_new_data(host_privkey.data, host_privkey.size));
882
883 gnutls_free(pem_root_cert.data);
884 gnutls_free(pem_host_cert.data);
885
886 if (dev_pem.data)
887 gnutls_free(dev_pem.data);
888 }
889 }
890 }
891 }
892
893 if (essentially_null.data)
894 free(essentially_null.data);
895
896 gnutls_x509_crt_deinit(dev_cert);
897 gnutls_x509_crt_deinit(root_cert);
898 gnutls_x509_crt_deinit(host_cert);
899 gnutls_x509_privkey_deinit(fake_privkey);
900 gnutls_x509_privkey_deinit(root_privkey);
901 gnutls_x509_privkey_deinit(host_privkey);
902 }
903
904 gnutls_free(modulus.data);
905 gnutls_free(exponent.data);
906
907 gnutls_free(der_pub_key.data);
908#endif
909 return uret;
910}
911
912/**
926 * Private function which import the given key into a gnutls structure. 913 * Private function which import the given key into a gnutls structure.
927 * 914 *
928 * @param name The name of the private key to import. 915 * @param name The name of the private key to import.
@@ -931,9 +918,9 @@ static userpref_error_t userpref_device_record_gen_keys_and_cert(const char* udi
931 * @return 1 if the key was successfully imported. 918 * @return 1 if the key was successfully imported.
932 */ 919 */
933#ifdef HAVE_OPENSSL 920#ifdef HAVE_OPENSSL
934static userpref_error_t userpref_device_record_import_key(const char* udid, const char* name, key_data_t* key) 921userpref_error_t pair_record_import_key_with_name(plist_t pair_record, const char* name, key_data_t* key)
935#else 922#else
936static userpref_error_t userpref_device_record_import_key(const char* udid, const char* name, gnutls_x509_privkey_t key) 923userpref_error_t pair_record_import_key_with_name(plist_t pair_record, const char* name, gnutls_x509_privkey_t key)
937#endif 924#endif
938{ 925{
939#ifdef HAVE_OPENSSL 926#ifdef HAVE_OPENSSL
@@ -941,33 +928,20 @@ static userpref_error_t userpref_device_record_import_key(const char* udid, cons
941 return USERPREF_E_SUCCESS; 928 return USERPREF_E_SUCCESS;
942#endif 929#endif
943 userpref_error_t ret = USERPREF_E_INVALID_CONF; 930 userpref_error_t ret = USERPREF_E_INVALID_CONF;
944 char* buffer = NULL;
945 uint64_t length = 0;
946 931
947 plist_t crt = NULL;
948 if (userpref_device_record_get_value(udid, name, &crt)) {
949 if (crt && plist_get_node_type(crt) == PLIST_DATA) {
950 plist_get_data_val(crt, &buffer, &length);
951#ifdef HAVE_OPENSSL 932#ifdef HAVE_OPENSSL
952 key->data = (unsigned char*)malloc(length); 933 ret = pair_record_get_item_as_key_data(pair_record, name, key);
953 memcpy(key->data, buffer, length);
954 key->size = length;
955 ret = USERPREF_E_SUCCESS;
956#else 934#else
957 key_data_t pem = { (unsigned char*)buffer, length }; 935 key_data_t pem = { NULL, 0 };
958 if (GNUTLS_E_SUCCESS == gnutls_x509_privkey_import(key, &pem, GNUTLS_X509_FMT_PEM)) 936 ret = pair_record_get_item_as_key_data(pair_record, name, pem);
959 ret = USERPREF_E_SUCCESS; 937 if (ret == USERPREF_E_SUCCESS && GNUTLS_E_SUCCESS == gnutls_x509_privkey_import(cert, &pem, GNUTLS_X509_FMT_PEM))
960 else 938 ret = USERPREF_E_SUCCESS;
961 ret = USERPREF_E_SSL_ERROR; 939 else
962#endif 940 ret = USERPREF_E_SSL_ERROR;
963 }
964 }
965
966 if (crt)
967 plist_free(crt);
968 941
969 if (buffer) 942 if (pem.data)
970 free(buffer); 943 free(pem.data);
944#endif
971 945
972 return ret; 946 return ret;
973} 947}
@@ -981,9 +955,9 @@ static userpref_error_t userpref_device_record_import_key(const char* udid, cons
981 * @return IDEVICE_E_SUCCESS if the certificate was successfully imported. 955 * @return IDEVICE_E_SUCCESS if the certificate was successfully imported.
982 */ 956 */
983#ifdef HAVE_OPENSSL 957#ifdef HAVE_OPENSSL
984static userpref_error_t userpref_device_record_import_crt(const char* udid, const char* name, key_data_t* cert) 958userpref_error_t pair_record_import_crt_with_name(plist_t pair_record, const char* name, key_data_t* cert)
985#else 959#else
986static userpref_error_t userpref_device_record_import_crt(const char* udid, const char* name, gnutls_x509_crt_t cert) 960userpref_error_t pair_record_import_crt_with_name(plist_t pair_record, const char* name, gnutls_x509_crt_t cert)
987#endif 961#endif
988{ 962{
989#ifdef HAVE_OPENSSL 963#ifdef HAVE_OPENSSL
@@ -991,206 +965,83 @@ static userpref_error_t userpref_device_record_import_crt(const char* udid, cons
991 return USERPREF_E_SUCCESS; 965 return USERPREF_E_SUCCESS;
992#endif 966#endif
993 userpref_error_t ret = USERPREF_E_INVALID_CONF; 967 userpref_error_t ret = USERPREF_E_INVALID_CONF;
994 char* buffer = NULL;
995 uint64_t length = 0;
996 968
997 plist_t crt = NULL;
998 if (userpref_device_record_get_value(udid, name, &crt)) {
999 if (crt && plist_get_node_type(crt) == PLIST_DATA) {
1000 plist_get_data_val(crt, &buffer, &length);
1001#ifdef HAVE_OPENSSL 969#ifdef HAVE_OPENSSL
1002 cert->data = (unsigned char*)malloc(length); 970 ret = pair_record_get_item_as_key_data(pair_record, name, cert);
1003 memcpy(cert->data, buffer, length);
1004 cert->size = length;
1005 ret = USERPREF_E_SUCCESS;
1006#else 971#else
1007 key_data_t pem = { (unsigned char*)buffer, length }; 972 key_data_t pem = { NULL, 0 };
1008 if (GNUTLS_E_SUCCESS == gnutls_x509_crt_import(cert, &pem, GNUTLS_X509_FMT_PEM)) 973 ret = pair_record_get_item_as_key_data(pair_record, name, pem);
1009 ret = USERPREF_E_SUCCESS; 974 if (ret == USERPREF_E_SUCCESS && GNUTLS_E_SUCCESS == gnutls_x509_crt_import(cert, &pem, GNUTLS_X509_FMT_PEM))
1010 else 975 ret = USERPREF_E_SUCCESS;
1011 ret = USERPREF_E_SSL_ERROR; 976 else
1012#endif 977 ret = USERPREF_E_SSL_ERROR;
1013 }
1014 }
1015
1016 if (crt)
1017 plist_free(crt);
1018 978
1019 if (buffer) 979 if (pem.data)
1020 free(buffer); 980 free(pem.data);
981#endif
1021 982
1022 return ret; 983 return ret;
1023} 984}
1024 985
1025/** 986userpref_error_t pair_record_get_host_id(plist_t pair_record, char** host_id)
1026 * Function to retrieve host keys and certificates.
1027 * This function trigger key generation if they do not exists yet or are invalid.
1028 *
1029 * @note This function can take few seconds to complete (typically 5 seconds)
1030 *
1031 * @param root_privkey The root private key.
1032 * @param root_crt The root certificate.
1033 * @param host_privkey The host private key.
1034 * @param host_crt The host certificate.
1035 *
1036 * @return 1 if the keys and certificates were successfully retrieved, 0 otherwise
1037 */
1038#ifdef HAVE_OPENSSL
1039userpref_error_t userpref_device_record_get_keys_and_certs(const char *udid, key_data_t* root_privkey, key_data_t* root_crt, key_data_t* host_privkey, key_data_t* host_crt)
1040#else
1041userpref_error_t userpref_device_record_get_keys_and_certs(const char *udid, gnutls_x509_privkey_t root_privkey, gnutls_x509_crt_t root_crt, gnutls_x509_privkey_t host_privkey, gnutls_x509_crt_t host_crt)
1042#endif
1043{ 987{
1044 userpref_error_t ret = USERPREF_E_SUCCESS; 988 plist_t node = plist_dict_get_item(pair_record, USERPREF_HOST_ID_KEY);
1045
1046 if (ret == USERPREF_E_SUCCESS)
1047 ret = userpref_device_record_import_key(udid, USERPREF_ROOT_PRIVATE_KEY_KEY, root_privkey);
1048
1049 if (ret == USERPREF_E_SUCCESS)
1050 ret = userpref_device_record_import_key(udid, USERPREF_HOST_PRIVATE_KEY_KEY, host_privkey);
1051
1052 if (ret == USERPREF_E_SUCCESS)
1053 ret = userpref_device_record_import_crt(udid, USERPREF_ROOT_CERTIFICATE_KEY, root_crt);
1054 989
1055 if (ret == USERPREF_E_SUCCESS) 990 if (node && plist_get_node_type(node) == PLIST_STRING) {
1056 ret = userpref_device_record_import_crt(udid, USERPREF_HOST_CERTIFICATE_KEY, host_crt); 991 plist_get_string_val(node, host_id);
1057 992 }
1058 if (USERPREF_E_SUCCESS != ret) {
1059 /* we had problem reading or importing root cert, try with new ones */
1060 ret = userpref_device_record_gen_keys_and_cert(udid);
1061
1062 if (ret == USERPREF_E_SUCCESS)
1063 ret = userpref_device_record_import_key(udid, USERPREF_ROOT_PRIVATE_KEY_KEY, root_privkey);
1064
1065 if (ret == USERPREF_E_SUCCESS)
1066 ret = userpref_device_record_import_key(udid, USERPREF_HOST_PRIVATE_KEY_KEY, host_privkey);
1067 993
1068 if (ret == USERPREF_E_SUCCESS) 994 return USERPREF_E_SUCCESS;
1069 ret = userpref_device_record_import_crt(udid, USERPREF_ROOT_CERTIFICATE_KEY, root_crt); 995}
1070 996
1071 if (ret == USERPREF_E_SUCCESS) 997userpref_error_t pair_record_set_host_id(plist_t pair_record, const char* host_id)
1072 ret = userpref_device_record_import_crt(udid, USERPREF_ROOT_CERTIFICATE_KEY, host_crt); 998{
1073 } 999 plist_dict_set_item(pair_record, USERPREF_HOST_ID_KEY, plist_new_string(host_id));
1074 1000
1075 return ret; 1001 return USERPREF_E_SUCCESS;
1076} 1002}
1077 1003
1078/** 1004userpref_error_t pair_record_get_item_as_key_data(plist_t pair_record, const char* name, key_data_t *value)
1079 * Function to retrieve certificates encoded in PEM format.
1080 *
1081 * @param pem_root_cert The root certificate.
1082 * @param pem_host_cert The host certificate.
1083 * @param pem_device_cert The device certificate (optional).
1084 *
1085 * @return 1 if the certificates were successfully retrieved, 0 otherwise
1086 */
1087userpref_error_t userpref_device_record_get_certs_as_pem(const char *udid, key_data_t *pem_root_cert, key_data_t *pem_host_cert, key_data_t *pem_device_cert)
1088{ 1005{
1089 if (!udid || !pem_root_cert || !pem_host_cert) 1006 if (!pair_record || !value)
1090 return USERPREF_E_INVALID_ARG; 1007 return USERPREF_E_INVALID_ARG;
1091 1008
1092 char* buffer = NULL; 1009 char* buffer = NULL;
1093 uint64_t length = 0; 1010 uint64_t length = 0;
1094 1011
1095 plist_t root_cert = NULL; 1012 plist_t node = plist_dict_get_item(pair_record, name);
1096 plist_t host_cert = NULL;
1097 plist_t dev_cert = NULL;
1098
1099 if (userpref_device_record_get_value(udid, USERPREF_HOST_CERTIFICATE_KEY, &host_cert) &&
1100 userpref_device_record_get_value(udid, USERPREF_ROOT_CERTIFICATE_KEY, &root_cert)) {
1101 if (host_cert && plist_get_node_type(host_cert) == PLIST_DATA) {
1102 plist_get_data_val(host_cert, &buffer, &length);
1103 pem_host_cert->data = (unsigned char*)malloc(length);
1104 memcpy(pem_host_cert->data, buffer, length);
1105 pem_host_cert->size = length;
1106 free(buffer);
1107 buffer = NULL;
1108 }
1109 if (root_cert && plist_get_node_type(root_cert) == PLIST_DATA) {
1110 plist_get_data_val(root_cert, &buffer, &length);
1111 pem_root_cert->data = (unsigned char*)malloc(length);
1112 memcpy(pem_root_cert->data, buffer, length);
1113 pem_root_cert->size = length;
1114 free(buffer);
1115 buffer = NULL;
1116 }
1117
1118 if (pem_device_cert) {
1119 userpref_device_record_get_value(udid, USERPREF_DEVICE_CERTIFICATE_KEY, &dev_cert);
1120 if (dev_cert && plist_get_node_type(dev_cert) == PLIST_DATA) {
1121 plist_get_data_val(dev_cert, &buffer, &length);
1122 pem_device_cert->data = (unsigned char*)malloc(length);
1123 memcpy(pem_device_cert->data, buffer, length);
1124 pem_device_cert->size = length;
1125 free(buffer);
1126 buffer = NULL;
1127 }
1128 }
1129
1130 if (root_cert)
1131 plist_free(root_cert);
1132 if (host_cert)
1133 plist_free(host_cert);
1134 if (dev_cert)
1135 plist_free(dev_cert);
1136 1013
1137 return USERPREF_E_SUCCESS; 1014 if (node && plist_get_node_type(node) == PLIST_DATA) {
1138 } else { 1015 plist_get_data_val(node, &buffer, &length);
1139 if (pem_root_cert->data) { 1016 value->data = (unsigned char*)malloc(length);
1140 free(pem_root_cert->data); 1017 memcpy(value->data, buffer, length);
1141 pem_root_cert->size = 0; 1018 value->size = length;
1142 } 1019 free(buffer);
1143 if (pem_host_cert->data) { 1020 buffer = NULL;
1144 free(pem_host_cert->data);
1145 pem_host_cert->size = 0;
1146 }
1147 } 1021 }
1148 1022
1149 if (root_cert) 1023 if (node)
1150 plist_free(root_cert); 1024 plist_free(node);
1151 if (host_cert)
1152 plist_free(host_cert);
1153 if (dev_cert)
1154 plist_free(dev_cert);
1155 1025
1156 debug_info("configuration invalid"); 1026 return USERPREF_E_SUCCESS;
1157
1158 return USERPREF_E_INVALID_CONF;
1159} 1027}
1160 1028
1161/** 1029userpref_error_t pair_record_set_item_from_key_data(plist_t pair_record, const char* name, key_data_t *value)
1162 * Create and save a configuration file containing the given data.
1163 *
1164 * @note: All fields must specified and be non-null
1165 *
1166 * @param root_key The root key
1167 * @param root_cert The root certificate
1168 * @param host_key The host key
1169 * @param host_cert The host certificate
1170 *
1171 * @return 1 on success and 0 otherwise.
1172 */
1173userpref_error_t userpref_device_record_set_keys_and_certs(const char* udid, key_data_t * root_key, key_data_t * root_cert, key_data_t * host_key, key_data_t * host_cert)
1174{ 1030{
1175 userpref_error_t ret = USERPREF_E_SUCCESS; 1031 userpref_error_t ret = USERPREF_E_SUCCESS;
1176 1032
1177 debug_info("saving keys and certs for udid %s", udid); 1033 if (!pair_record || !value) {
1178
1179 if (!root_key || !host_key || !root_cert || !host_cert) {
1180 debug_info("missing key or cert (root_key=%p, host_key=%p, root=cert=%p, host_cert=%p", root_key, host_key, root_cert, host_cert);
1181 return USERPREF_E_INVALID_ARG; 1034 return USERPREF_E_INVALID_ARG;
1182 } 1035 }
1183 1036
1184 /* now write keys and certificates to disk */ 1037 /* remove any existing item */
1185 if (userpref_device_record_set_value(udid, USERPREF_HOST_PRIVATE_KEY_KEY, plist_new_data((char*)host_key->data, host_key->size)) && 1038 if (plist_dict_get_item(pair_record, name)) {
1186 userpref_device_record_set_value(udid, USERPREF_HOST_CERTIFICATE_KEY, plist_new_data((char*)host_cert->data, host_cert->size)) && 1039 plist_dict_remove_item(pair_record, name);
1187 userpref_device_record_set_value(udid, USERPREF_ROOT_PRIVATE_KEY_KEY, plist_new_data((char*)root_key->data, root_key->size)) &&
1188 userpref_device_record_set_value(udid, USERPREF_ROOT_CERTIFICATE_KEY, plist_new_data((char*)root_cert->data, root_cert->size)))
1189 {
1190 ret = USERPREF_E_SUCCESS;
1191 } else {
1192 ret = 1;
1193 } 1040 }
1194 1041
1042 /* set new item */
1043 plist_dict_set_item(pair_record, name, plist_new_data((char*)value->data, value->size));
1044
1195 return ret; 1045 return ret;
1196} 1046}
1047
diff --git a/common/userpref.h b/common/userpref.h
index 07fed8d..a39417a 100644
--- a/common/userpref.h
+++ b/common/userpref.h
@@ -69,27 +69,29 @@ typedef gnutls_datum_t key_data_t;
69 69
70typedef int16_t userpref_error_t; 70typedef int16_t userpref_error_t;
71 71
72const char *userpref_get_config_dir();
73int userpref_read_system_buid(char **system_buid);
74userpref_error_t userpref_read_pair_record(const char *udid, plist_t *pair_record);
75userpref_error_t userpref_save_pair_record(const char *udid, plist_t pair_record);
76userpref_error_t userpref_delete_pair_record(const char *udid);
77
78LIBIMOBILEDEVICE_INTERNAL userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record);
79LIBIMOBILEDEVICE_INTERNAL userpref_error_t pair_record_generate_from_device_public_key(plist_t pair_record, key_data_t public_key);
72#ifdef HAVE_OPENSSL 80#ifdef HAVE_OPENSSL
73LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_device_record_get_keys_and_certs(const char *udid, key_data_t* root_privkey, key_data_t* root_crt, key_data_t* host_privkey, key_data_t* host_crt); 81LIBIMOBILEDEVICE_INTERNAL userpref_error_t pair_record_import_key_with_name(plist_t pair_record, const char* name, key_data_t* key);
82LIBIMOBILEDEVICE_INTERNAL userpref_error_t pair_record_import_crt_with_name(plist_t pair_record, const char* name, key_data_t* cert);
74#else 83#else
75LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_device_record_get_keys_and_certs(const char *udid, gnutls_x509_privkey_t root_privkey, gnutls_x509_crt_t root_crt, gnutls_x509_privkey_t host_privkey, gnutls_x509_crt_t host_crt); 84LIBIMOBILEDEVICE_INTERNAL userpref_error_t pair_record_import_key_with_name(plist_t pair_record, const char* name, gnutls_x509_privkey_t key);
85LIBIMOBILEDEVICE_INTERNAL userpref_error_t pair_record_import_crt_with_name(plist_t pair_record, const char* name, gnutls_x509_crt_t cert);
76#endif 86#endif
77LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_device_record_set_keys_and_certs(const char *udid, key_data_t * root_key, key_data_t * root_cert, key_data_t * host_key, key_data_t * host_cert);
78LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_device_record_get_certs_as_pem(const char *udid, key_data_t *pem_root_cert, key_data_t *pem_host_cert, key_data_t *pem_device_cert);
79 87
80LIBIMOBILEDEVICE_INTERNAL userpref_error_t userpref_set_device_record(const char *udid, plist_t device_record); 88userpref_error_t pair_record_get_host_id(plist_t pair_record, char** host_id);
81userpref_error_t userpref_remove_device_record(const char *udid); 89userpref_error_t pair_record_set_host_id(plist_t pair_record, const char* host_id);
82LIBIMOBILEDEVICE_INTERNAL int userpref_has_device_record(const char *udid); 90userpref_error_t pair_record_get_item_as_key_data(plist_t pair_record, const char* name, key_data_t *value);
91userpref_error_t pair_record_set_item_from_key_data(plist_t pair_record, const char* name, key_data_t *value);
83 92
93/* deprecated */
84userpref_error_t userpref_get_paired_udids(char ***list, unsigned int *count); 94userpref_error_t userpref_get_paired_udids(char ***list, unsigned int *count);
85void userpref_device_record_get_host_id(const char *udid, char **host_id); 95LIBIMOBILEDEVICE_INTERNAL int userpref_has_pair_record(const char *udid);
86void userpref_get_system_buid(char **system_buid);
87const char *userpref_get_config_dir();
88
89userpref_error_t userpref_get_device_record(const char *udid, plist_t *device_record);
90int userpref_get_value(const char *key, plist_t *value);
91int userpref_set_value(const char *key, plist_t value);
92int userpref_device_record_get_value(const char *udid, const char *key, plist_t *value);
93int userpref_device_record_set_value(const char *udid, const char *key, plist_t value);
94 96
95#endif 97#endif
diff --git a/common/utils.c b/common/utils.c
index 1b207ea..68b23b9 100644
--- a/common/utils.c
+++ b/common/utils.c
@@ -26,6 +26,7 @@
26#include <stdarg.h> 26#include <stdarg.h>
27#include <stdlib.h> 27#include <stdlib.h>
28#include <string.h> 28#include <string.h>
29#include <time.h>
29 30
30#include "utils.h" 31#include "utils.h"
31 32
@@ -107,6 +108,35 @@ char *string_concat(const char *str, ...)
107 return result; 108 return result;
108} 109}
109 110
111static int get_rand(int min, int max)
112{
113 int retval = (rand() % (max - min)) + min;
114 return retval;
115}
116
117char *generate_uuid()
118{
119 const char *chars = "ABCDEF0123456789";
120 int i = 0;
121 char *uuid = (char *) malloc(sizeof(char) * 37);
122
123 srand(time(NULL));
124
125 for (i = 0; i < 36; i++) {
126 if (i == 8 || i == 13 || i == 18 || i == 23) {
127 uuid[i] = '-';
128 continue;
129 } else {
130 uuid[i] = chars[get_rand(0, 16)];
131 }
132 }
133
134 /* make it a real string */
135 uuid[36] = '\0';
136
137 return uuid;
138}
139
110void buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length) 140void buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length)
111{ 141{
112 FILE *f; 142 FILE *f;
diff --git a/common/utils.h b/common/utils.h
index 0e78b3c..c1b6c32 100644
--- a/common/utils.h
+++ b/common/utils.h
@@ -37,6 +37,7 @@
37char *stpcpy(char * s1, const char * s2); 37char *stpcpy(char * s1, const char * s2);
38#endif 38#endif
39char *string_concat(const char *str, ...); 39char *string_concat(const char *str, ...);
40char *generate_uuid();
40 41
41void buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length); 42void buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length);
42void buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length); 43void buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length);
diff --git a/src/idevice.c b/src/idevice.c
index d01aa8f..c656517 100644
--- a/src/idevice.c
+++ b/src/idevice.c
@@ -511,7 +511,7 @@ static ssize_t internal_ssl_read(gnutls_transport_ptr_t transport, char *buffer,
511 511
512 debug_info("pre-read client wants %zi bytes", length); 512 debug_info("pre-read client wants %zi bytes", length);
513 513
514 recv_buffer = (char *) malloc(sizeof(char) * this_len); 514 recv_buffer = (char *)malloc(sizeof(char) * this_len);
515 515
516 /* repeat until we have the full data or an error occurs */ 516 /* repeat until we have the full data or an error occurs */
517 do { 517 do {
@@ -637,12 +637,12 @@ static const char *errorstring(int e)
637/** 637/**
638 * Internally used gnutls callback function that gets called during handshake. 638 * Internally used gnutls callback function that gets called during handshake.
639 */ 639 */
640static int internal_cert_callback (gnutls_session_t session, const gnutls_datum_t * req_ca_rdn, int nreqs, const gnutls_pk_algorithm_t * sign_algos, int sign_algos_length, gnutls_retr_st * st) 640static int internal_cert_callback(gnutls_session_t session, const gnutls_datum_t * req_ca_rdn, int nreqs, const gnutls_pk_algorithm_t * sign_algos, int sign_algos_length, gnutls_retr_st * st)
641{ 641{
642 int res = -1; 642 int res = -1;
643 gnutls_certificate_type_t type = gnutls_certificate_type_get (session); 643 gnutls_certificate_type_t type = gnutls_certificate_type_get(session);
644 if (type == GNUTLS_CRT_X509) { 644 if (type == GNUTLS_CRT_X509) {
645 ssl_data_t ssl_data = (ssl_data_t)gnutls_session_get_ptr (session); 645 ssl_data_t ssl_data = (ssl_data_t)gnutls_session_get_ptr(session);
646 if (ssl_data && ssl_data->host_privkey && ssl_data->host_cert) { 646 if (ssl_data && ssl_data->host_privkey && ssl_data->host_cert) {
647 debug_info("Passing certificate"); 647 debug_info("Passing certificate");
648 st->type = type; 648 st->type = type;
@@ -673,15 +673,20 @@ idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection)
673 673
674 idevice_error_t ret = IDEVICE_E_SSL_ERROR; 674 idevice_error_t ret = IDEVICE_E_SSL_ERROR;
675 uint32_t return_me = 0; 675 uint32_t return_me = 0;
676 plist_t pair_record = NULL;
677
678 userpref_read_pair_record(connection->udid, &pair_record);
679 if (!pair_record) {
680 debug_info("ERROR: Failed enabling SSL. Unable to read pair record for udid %s.", connection->udid);
681 return ret;
682 }
676 683
677#ifdef HAVE_OPENSSL 684#ifdef HAVE_OPENSSL
678 key_data_t root_cert = { NULL, 0 }; 685 key_data_t root_cert = { NULL, 0 };
679 key_data_t root_privkey = { NULL, 0 }; 686 key_data_t root_privkey = { NULL, 0 };
680 687
681 userpref_error_t uerr = userpref_device_record_get_keys_and_certs(connection->udid, &root_privkey, &root_cert, NULL, NULL); 688 pair_record_import_key_with_name(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, &root_cert);
682 if (uerr != USERPREF_E_SUCCESS) { 689 pair_record_import_key_with_name(pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY, &root_privkey);
683 debug_info("Error %d when loading keys and certificates! %d", uerr);
684 }
685 690
686 /* Set up OpenSSL */ 691 /* Set up OpenSSL */
687 if (openssl_init_done == 0) { 692 if (openssl_init_done == 0) {
@@ -756,7 +761,7 @@ idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection)
756 errno = 0; 761 errno = 0;
757 gnutls_global_init(); 762 gnutls_global_init();
758 gnutls_certificate_allocate_credentials(&ssl_data_loc->certificate); 763 gnutls_certificate_allocate_credentials(&ssl_data_loc->certificate);
759 gnutls_certificate_client_set_retrieve_function (ssl_data_loc->certificate, internal_cert_callback); 764 gnutls_certificate_client_set_retrieve_function(ssl_data_loc->certificate, internal_cert_callback);
760 gnutls_init(&ssl_data_loc->session, GNUTLS_CLIENT); 765 gnutls_init(&ssl_data_loc->session, GNUTLS_CLIENT);
761 gnutls_priority_set_direct(ssl_data_loc->session, "NONE:+VERS-SSL3.0:+ANON-DH:+RSA:+AES-128-CBC:+AES-256-CBC:+SHA1:+MD5:+COMP-NULL", NULL); 766 gnutls_priority_set_direct(ssl_data_loc->session, "NONE:+VERS-SSL3.0:+ANON-DH:+RSA:+AES-128-CBC:+AES-256-CBC:+SHA1:+MD5:+COMP-NULL", NULL);
762 gnutls_credentials_set(ssl_data_loc->session, GNUTLS_CRD_CERTIFICATE, ssl_data_loc->certificate); 767 gnutls_credentials_set(ssl_data_loc->session, GNUTLS_CRD_CERTIFICATE, ssl_data_loc->certificate);
@@ -767,10 +772,10 @@ idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection)
767 gnutls_x509_privkey_init(&ssl_data_loc->root_privkey); 772 gnutls_x509_privkey_init(&ssl_data_loc->root_privkey);
768 gnutls_x509_privkey_init(&ssl_data_loc->host_privkey); 773 gnutls_x509_privkey_init(&ssl_data_loc->host_privkey);
769 774
770 userpref_error_t uerr = userpref_device_record_get_keys_and_certs(connection->udid, ssl_data_loc->root_privkey, ssl_data_loc->root_cert, ssl_data_loc->host_privkey, ssl_data_loc->host_cert); 775 pair_record_import_key_with_name(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, ssl_data_loc->root_cert);
771 if (uerr != USERPREF_E_SUCCESS) { 776 pair_record_import_key_with_name(pair_record, USERPREF_HOST_CERTIFICATE_KEY, ssl_data_loc->host_cert);
772 debug_info("Error %d when loading keys and certificates! %d", uerr); 777 pair_record_import_key_with_name(pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY, ssl_data_loc->root_privkey);
773 } 778 pair_record_import_key_with_name(pair_record, USERPREF_HOST_PRIVATE_KEY_KEY, ssl_data_loc->host_privkey);
774 779
775 debug_info("GnuTLS step 1..."); 780 debug_info("GnuTLS step 1...");
776 gnutls_transport_set_ptr(ssl_data_loc->session, (gnutls_transport_ptr_t)connection); 781 gnutls_transport_set_ptr(ssl_data_loc->session, (gnutls_transport_ptr_t)connection);
diff --git a/src/lockdown.c b/src/lockdown.c
index e21db30..6ea747f 100644
--- a/src/lockdown.c
+++ b/src/lockdown.c
@@ -47,6 +47,7 @@
47#include "idevice.h" 47#include "idevice.h"
48#include "common/debug.h" 48#include "common/debug.h"
49#include "common/userpref.h" 49#include "common/userpref.h"
50#include "common/utils.h"
50#include "asprintf.h" 51#include "asprintf.h"
51 52
52#ifdef WIN32 53#ifdef WIN32
@@ -57,17 +58,6 @@
57#define RESULT_SUCCESS 0 58#define RESULT_SUCCESS 0
58#define RESULT_FAILURE 1 59#define RESULT_FAILURE 1
59 60
60#ifndef HAVE_OPENSSL
61const ASN1_ARRAY_TYPE pkcs1_asn1_tab[] = {
62 {"PKCS1", 536872976, 0},
63 {0, 1073741836, 0},
64 {"RSAPublicKey", 536870917, 0},
65 {"modulus", 1073741827, 0},
66 {"publicExponent", 3, 0},
67 {0, 0, 0}
68};
69#endif
70
71/** 61/**
72 * Internally used function for checking the result from lockdown's answer 62 * Internally used function for checking the result from lockdown's answer
73 * plist to a previously sent request. 63 * plist to a previously sent request.
@@ -618,7 +608,7 @@ lockdownd_error_t lockdownd_get_device_udid(lockdownd_client_t client, char **ud
618 * 608 *
619 * @return LOCKDOWN_E_SUCCESS on success 609 * @return LOCKDOWN_E_SUCCESS on success
620 */ 610 */
621lockdownd_error_t lockdownd_get_device_public_key(lockdownd_client_t client, key_data_t * public_key) 611static lockdownd_error_t lockdownd_get_device_public_key_as_key_data(lockdownd_client_t client, key_data_t *public_key)
622{ 612{
623 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; 613 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
624 plist_t value = NULL; 614 plist_t value = NULL;
@@ -758,16 +748,27 @@ lockdownd_error_t lockdownd_client_new_with_handshake(idevice_t device, lockdown
758 if (type) 748 if (type)
759 free(type); 749 free(type);
760 750
761 userpref_device_record_get_host_id(client_loc->udid, &host_id); 751 debug_info("reading pair record");
752
753 plist_t pair_record = NULL;
754 userpref_read_pair_record(client_loc->udid, &pair_record);
755
756 debug_info("reading HostID");
757
758 pair_record_get_host_id(pair_record, &host_id);
762 if (LOCKDOWN_E_SUCCESS == ret && !host_id) { 759 if (LOCKDOWN_E_SUCCESS == ret && !host_id) {
763 ret = LOCKDOWN_E_INVALID_CONF; 760 ret = LOCKDOWN_E_INVALID_CONF;
764 } 761 }
765 762
766 if (LOCKDOWN_E_SUCCESS == ret && !userpref_has_device_record(client_loc->udid)) { 763 debug_info("HostID: %s", host_id);
764
765 if (LOCKDOWN_E_SUCCESS == ret && !pair_record) {
767 /* attempt pairing */ 766 /* attempt pairing */
768 ret = lockdownd_pair(client_loc, NULL); 767 ret = lockdownd_pair(client_loc, NULL);
769 } 768 }
770 769
770 plist_free(pair_record);
771
771 /* in any case, we need to validate pairing to receive trusted host status */ 772 /* in any case, we need to validate pairing to receive trusted host status */
772 ret = lockdownd_validate_pair(client_loc, NULL); 773 ret = lockdownd_validate_pair(client_loc, NULL);
773 774
@@ -836,67 +837,69 @@ static plist_t lockdownd_pair_record_to_plist(lockdownd_pair_record_t pair_recor
836 * 837 *
837 * @return LOCKDOWN_E_SUCCESS on success 838 * @return LOCKDOWN_E_SUCCESS on success
838 */ 839 */
839static lockdownd_error_t generate_pair_record_plist(lockdownd_client_t client, plist_t *pair_record_plist) 840static lockdownd_error_t pair_record_generate(lockdownd_client_t client, plist_t *pair_record)
840{ 841{
841 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; 842 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
842 843
844 key_data_t public_key = { NULL, 0 };
843 char* host_id = NULL; 845 char* host_id = NULL;
844 char* system_buid = NULL; 846 char* system_buid = NULL;
845 847
846 key_data_t public_key = { NULL, 0 };
847 key_data_t device_cert = { NULL, 0 };
848 key_data_t host_cert = { NULL, 0 };
849 key_data_t root_cert = { NULL, 0 };
850
851 /* load certificates if a pairing exists */
852 userpref_error_t uret = userpref_device_record_get_certs_as_pem(client->udid, &root_cert, &host_cert, &device_cert);
853 if ((uret == USERPREF_E_SUCCESS) && (root_cert.size > 0) && (host_cert.size > 0) && (device_cert.size > 0)) {
854 ret = LOCKDOWN_E_SUCCESS;
855 }
856
857 /* get systembuid and host id */
858 userpref_get_system_buid(&system_buid);
859 userpref_device_record_get_host_id(client->udid, &host_id);
860
861 /* generate new certificates if needed */ 848 /* generate new certificates if needed */
849 ret = lockdownd_get_device_public_key_as_key_data(client, &public_key);
862 if (ret != LOCKDOWN_E_SUCCESS) { 850 if (ret != LOCKDOWN_E_SUCCESS) {
863 ret = lockdownd_get_device_public_key(client, &public_key); 851 debug_info("device refused to send public key.");
864 if (ret != LOCKDOWN_E_SUCCESS) { 852 goto leave;
865 debug_info("device refused to send public key."); 853 }
866 goto leave; 854 debug_info("device public key follows:\n%.*s", public_key.size, public_key.data);
867 }
868 debug_info("device public key follows:\n%.*s", public_key.size, public_key.data);
869 855
870 userpref_device_record_set_value(client->udid, USERPREF_SYSTEM_BUID_KEY, plist_new_string(system_buid)); 856 host_id = generate_uuid();
871 857
872 ret = lockdownd_gen_pair_cert_for_udid(client->udid, public_key, &device_cert, &host_cert, &root_cert); 858 *pair_record = plist_new_dict();
859
860 userpref_error_t uret = USERPREF_E_SUCCESS;
861 uret = pair_record_generate_keys_and_certs(pair_record);
862 switch(uret) {
863 case USERPREF_E_INVALID_ARG:
864 ret = LOCKDOWN_E_INVALID_ARG;
865 break;
866 case USERPREF_E_INVALID_CONF:
867 ret = LOCKDOWN_E_INVALID_CONF;
868 break;
869 case USERPREF_E_SSL_ERROR:
870 ret = LOCKDOWN_E_SSL_ERROR;
871 default:
872 break;
873 }
874
875 uret = pair_record_generate_from_device_public_key(pair_record, public_key);
876 switch(uret) {
877 case USERPREF_E_INVALID_ARG:
878 ret = LOCKDOWN_E_INVALID_ARG;
879 break;
880 case USERPREF_E_INVALID_CONF:
881 ret = LOCKDOWN_E_INVALID_CONF;
882 break;
883 case USERPREF_E_SSL_ERROR:
884 ret = LOCKDOWN_E_SSL_ERROR;
885 default:
886 break;
873 } 887 }
874 888
889 /* get systembuid and host id */
890 userpref_read_system_buid(&system_buid);
891
892 pair_record_set_host_id(pair_record, host_id);
893
875 if (ret != LOCKDOWN_E_SUCCESS) { 894 if (ret != LOCKDOWN_E_SUCCESS) {
876 goto leave; 895 goto leave;
877 } 896 }
878 897
879 /* setup request plist */
880 *pair_record_plist = plist_new_dict();
881 plist_dict_set_item(*pair_record_plist, "DeviceCertificate", plist_new_data((const char*)device_cert.data, device_cert.size));
882 plist_dict_set_item(*pair_record_plist, "HostCertificate", plist_new_data((const char*)host_cert.data, host_cert.size));
883 plist_dict_set_item(*pair_record_plist, "HostID", plist_new_string(host_id));
884 plist_dict_set_item(*pair_record_plist, "RootCertificate", plist_new_data((const char*)root_cert.data, root_cert.size));
885 plist_dict_set_item(*pair_record_plist, "SystemBUID", plist_new_string(system_buid));
886
887leave: 898leave:
888 if (host_id) 899 if (host_id)
889 free(host_id); 900 free(host_id);
890 if (system_buid) 901 if (system_buid)
891 free(system_buid); 902 free(system_buid);
892 if (public_key.data)
893 free(public_key.data);
894 if (device_cert.data)
895 free(device_cert.data);
896 if (host_cert.data)
897 free(host_cert.data);
898 if (root_cert.data)
899 free(root_cert.data);
900 903
901 return ret; 904 return ret;
902} 905}
@@ -923,7 +926,7 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_
923 926
924 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; 927 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
925 plist_t dict = NULL; 928 plist_t dict = NULL;
926 plist_t dict_record = NULL; 929 plist_t pair_record_plist = NULL;
927 int pairing_mode = 0; /* 0 = libimobiledevice, 1 = external */ 930 int pairing_mode = 0; /* 0 = libimobiledevice, 1 = external */
928 931
929 if (pair_record && pair_record->system_buid && pair_record->host_id) { 932 if (pair_record && pair_record->system_buid && pair_record->host_id) {
@@ -933,36 +936,39 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_
933 } 936 }
934 937
935 /* use passed pair_record */ 938 /* use passed pair_record */
936 dict_record = lockdownd_pair_record_to_plist(pair_record); 939 pair_record_plist = lockdownd_pair_record_to_plist(pair_record);
937 940
938 pairing_mode = 1; 941 pairing_mode = 1;
939 } else { 942 } else {
940 ret = generate_pair_record_plist(client, &dict_record); 943 /* generate a new pair record if pairing */
941 944 if (!strcmp("Pair", verb)) {
942 if (ret != LOCKDOWN_E_SUCCESS) { 945 ret = pair_record_generate(client, &pair_record_plist);
943 if (dict_record) 946
944 plist_free(dict_record); 947 if (ret != LOCKDOWN_E_SUCCESS) {
945 return ret; 948 if (pair_record_plist)
949 plist_free(pair_record_plist);
950 return ret;
951 }
952 } else {
953 /* use existing pair record */
954 if (userpref_has_pair_record(client->udid)) {
955 userpref_read_pair_record(client->udid, &pair_record_plist);
956 } else {
957 return LOCKDOWN_E_PAIRING_FAILED;
958 }
946 } 959 }
947 } 960 }
948 961
949 if (!strcmp("Pair", verb)) { 962 plist_t request_pair_record = plist_copy(pair_record_plist);
950 /* get wifi mac */
951 plist_t wifi_mac_node = NULL;
952 lockdownd_get_value(client, NULL, "WiFiAddress", &wifi_mac_node);
953 963
954 /* save wifi mac address in config */ 964 /* remove stuff that is private */
955 if (wifi_mac_node) { 965 plist_dict_remove_item(request_pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY);
956 userpref_device_record_set_value(client->udid, USERPREF_WIFI_MAC_ADDRESS_KEY, plist_copy(wifi_mac_node)); 966 plist_dict_remove_item(request_pair_record, USERPREF_HOST_PRIVATE_KEY_KEY);
957 plist_free(wifi_mac_node);
958 wifi_mac_node = NULL;
959 }
960 }
961 967
962 /* setup pair request plist */ 968 /* setup pair request plist */
963 dict = plist_new_dict(); 969 dict = plist_new_dict();
964 plist_dict_add_label(dict, client->label); 970 plist_dict_add_label(dict, client->label);
965 plist_dict_set_item(dict, "PairRecord", plist_copy(dict_record)); 971 plist_dict_set_item(dict, "PairRecord", request_pair_record);
966 plist_dict_set_item(dict, "Request", plist_new_string(verb)); 972 plist_dict_set_item(dict, "Request", plist_new_string(verb));
967 plist_dict_set_item(dict, "ProtocolVersion", plist_new_string(LOCKDOWN_PROTOCOL_VERSION)); 973 plist_dict_set_item(dict, "ProtocolVersion", plist_new_string(LOCKDOWN_PROTOCOL_VERSION));
968 974
@@ -976,7 +982,7 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_
976 dict = NULL; 982 dict = NULL;
977 983
978 if (ret != LOCKDOWN_E_SUCCESS) { 984 if (ret != LOCKDOWN_E_SUCCESS) {
979 plist_free(dict_record); 985 plist_free(pair_record_plist);
980 return ret; 986 return ret;
981 } 987 }
982 988
@@ -984,7 +990,7 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_
984 ret = lockdownd_receive(client, &dict); 990 ret = lockdownd_receive(client, &dict);
985 991
986 if (ret != LOCKDOWN_E_SUCCESS) { 992 if (ret != LOCKDOWN_E_SUCCESS) {
987 plist_free(dict_record); 993 plist_free(pair_record_plist);
988 return ret; 994 return ret;
989 } 995 }
990 996
@@ -1007,24 +1013,32 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_
1007 debug_info("internal pairing mode"); 1013 debug_info("internal pairing mode");
1008 if (!strcmp("Unpair", verb)) { 1014 if (!strcmp("Unpair", verb)) {
1009 /* remove public key from config */ 1015 /* remove public key from config */
1010 userpref_remove_device_record(client->udid); 1016 userpref_delete_pair_record(client->udid);
1011 } else { 1017 } else {
1012 if (!strcmp("Pair", verb)) { 1018 if (!strcmp("Pair", verb)) {
1013 debug_info("getting EscrowBag from response"); 1019 debug_info("Saving EscrowBag from response in pair record");
1014 1020
1015 /* add returned escrow bag if available */ 1021 /* add returned escrow bag if available */
1016 plist_t escrow_bag = plist_dict_get_item(dict, "EscrowBag"); 1022 plist_t extra_node = plist_dict_get_item(dict, USERPREF_ESCROW_BAG_KEY);
1017 if (escrow_bag && plist_get_node_type(escrow_bag) == PLIST_DATA) { 1023 if (extra_node && plist_get_node_type(extra_node) == PLIST_DATA) {
1018 userpref_device_record_set_value(client->udid, USERPREF_ESCROW_BAG_KEY, plist_copy(escrow_bag)); 1024 plist_dict_set_item(pair_record_plist, USERPREF_ESCROW_BAG_KEY, plist_copy(extra_node));
1019 plist_free(escrow_bag); 1025 plist_free(extra_node);
1020 escrow_bag = NULL; 1026 extra_node = NULL;
1021 } 1027 }
1022 1028
1023 /* store DeviceCertificate upon successful pairing */ 1029 debug_info("Saving WiFiAddress from device in pair record");
1024 plist_t devcrt = plist_dict_get_item(dict_record, USERPREF_DEVICE_CERTIFICATE_KEY); 1030
1025 if (devcrt && plist_get_node_type(devcrt) == PLIST_DATA) { 1031 /* get wifi mac */
1026 userpref_device_record_set_value(client->udid, USERPREF_DEVICE_CERTIFICATE_KEY, plist_copy(devcrt)); 1032 lockdownd_get_value(client, NULL, "WiFiAddress", &extra_node);
1033
1034 /* save wifi mac address in config */
1035 if (extra_node) {
1036 plist_dict_set_item(pair_record_plist, USERPREF_WIFI_MAC_ADDRESS_KEY, plist_copy(extra_node));
1037 plist_free(extra_node);
1038 extra_node = NULL;
1027 } 1039 }
1040
1041 userpref_save_pair_record(client->udid, pair_record_plist);
1028 } 1042 }
1029 } 1043 }
1030 } else { 1044 } else {
@@ -1057,9 +1071,9 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_
1057 } 1071 }
1058 } 1072 }
1059 1073
1060 if (dict_record) { 1074 if (pair_record_plist) {
1061 plist_free(dict_record); 1075 plist_free(pair_record_plist);
1062 dict_record = NULL; 1076 pair_record_plist = NULL;
1063 } 1077 }
1064 1078
1065 plist_free(dict); 1079 plist_free(dict);
@@ -1206,332 +1220,6 @@ lockdownd_error_t lockdownd_goodbye(lockdownd_client_t client)
1206} 1220}
1207 1221
1208/** 1222/**
1209 * Generates the device certificate from the public key as well as the host
1210 * and root certificates.
1211 *
1212 * @param public_key The public key of the device to use for generation.
1213 * @param odevice_cert Holds the generated device certificate.
1214 * @param ohost_cert Holds the generated host certificate.
1215 * @param oroot_cert Holds the generated root certificate.
1216 *
1217 * @return LOCKDOWN_E_SUCCESS on success, LOCKDOWN_E_INVALID_ARG when a
1218 * parameter is NULL, LOCKDOWN_E_INVALID_CONF if the internal configuration
1219 * system failed, LOCKDOWN_E_SSL_ERROR if the certificates could not be
1220 * generated
1221 */
1222lockdownd_error_t lockdownd_gen_pair_cert_for_udid(const char *udid, key_data_t public_key, key_data_t * odevice_cert,
1223 key_data_t * ohost_cert, key_data_t * oroot_cert)
1224{
1225 if (!public_key.data || !odevice_cert || !ohost_cert || !oroot_cert)
1226 return LOCKDOWN_E_INVALID_ARG;
1227
1228 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
1229 userpref_error_t uret = USERPREF_E_UNKNOWN_ERROR;
1230
1231#ifdef HAVE_OPENSSL
1232 BIO *membio = BIO_new_mem_buf(public_key.data, public_key.size);
1233 RSA *pubkey = NULL;
1234 if (!PEM_read_bio_RSAPublicKey(membio, &pubkey, NULL, NULL)) {
1235 debug_info("Could not read public key");
1236 }
1237 BIO_free(membio);
1238
1239 /* now generate certificates */
1240 key_data_t root_privkey, host_privkey;
1241 key_data_t root_cert, host_cert;
1242 X509* dev_cert;
1243
1244 root_cert.data = NULL;
1245 root_cert.size = 0;
1246 host_cert.data = NULL;
1247 host_cert.size = 0;
1248
1249 dev_cert = X509_new();
1250
1251 root_privkey.data = NULL;
1252 root_privkey.size = 0;
1253 host_privkey.data = NULL;
1254 host_privkey.size = 0;
1255
1256 uret = userpref_device_record_get_keys_and_certs(udid, &root_privkey, &root_cert, &host_privkey, &host_cert);
1257 if (USERPREF_E_SUCCESS == uret) {
1258 /* generate device certificate */
1259 ASN1_INTEGER* sn = ASN1_INTEGER_new();
1260 ASN1_INTEGER_set(sn, 0);
1261 X509_set_serialNumber(dev_cert, sn);
1262 ASN1_INTEGER_free(sn);
1263 X509_set_version(dev_cert, 2);
1264
1265 X509_EXTENSION* ext;
1266 if (!(ext = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints, (char*)"critical,CA:FALSE"))) {
1267 debug_info("ERROR: X509V3_EXT_conf_nid failed for Basic Constraints");
1268 }
1269 X509_add_ext(dev_cert, ext, -1);
1270 X509_EXTENSION_free(ext);
1271
1272 ASN1_TIME* asn1time = ASN1_TIME_new();
1273 ASN1_TIME_set(asn1time, time(NULL));
1274 X509_set_notBefore(dev_cert, asn1time);
1275 ASN1_TIME_set(asn1time, time(NULL) + (60 * 60 * 24 * 365 * 10));
1276 X509_set_notAfter(dev_cert, asn1time);
1277 ASN1_TIME_free(asn1time);
1278
1279 BIO* membp;
1280
1281 X509* rootCert = NULL;
1282 membp = BIO_new_mem_buf(root_cert.data, root_cert.size);
1283 PEM_read_bio_X509(membp, &rootCert, NULL, NULL);
1284 BIO_free(membp);
1285 if (!rootCert) {
1286 debug_info("Could not read RootCertificate");
1287 } else {
1288 debug_info("RootCertificate loaded");
1289 EVP_PKEY* pkey = EVP_PKEY_new();
1290 EVP_PKEY_assign_RSA(pkey, pubkey);
1291 X509_set_pubkey(dev_cert, pkey);
1292 EVP_PKEY_free(pkey);
1293 X509_free(rootCert);
1294 }
1295
1296 X509V3_CTX ctx;
1297 X509V3_set_ctx_nodb(&ctx);
1298 X509V3_set_ctx(&ctx, NULL, dev_cert, NULL, NULL, 0);
1299
1300 if (!(ext = X509V3_EXT_conf_nid(NULL, &ctx, NID_subject_key_identifier, (char*)"hash"))) {
1301 debug_info("ERROR: X509V3_EXT_conf_nid failed for Subject Key identifier");
1302 }
1303 X509_add_ext(dev_cert, ext, -1);
1304 X509_EXTENSION_free(ext);
1305
1306 if (!(ext = X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage, (char*)"critical,digitalSignature,keyEncipherment"))) {
1307 debug_info("ERROR: X509V3_EXT_conf_nid failed for Key Usage");
1308 }
1309 X509_add_ext(dev_cert, ext, -1);
1310 X509_EXTENSION_free(ext);
1311
1312 EVP_PKEY* rootPriv = NULL;
1313 membp = BIO_new_mem_buf(root_privkey.data, root_privkey.size);
1314 PEM_read_bio_PrivateKey(membp, &rootPriv, NULL, NULL);
1315 BIO_free(membp);
1316 if (!rootPriv) {
1317 debug_info("Could not read RootPrivateKey");
1318 } else {
1319 debug_info("RootPrivateKey loaded");
1320 if (X509_sign(dev_cert, rootPriv, EVP_sha1())) {
1321 ret = LOCKDOWN_E_SUCCESS;
1322 } else {
1323 debug_info("signing failed");
1324 }
1325 EVP_PKEY_free(rootPriv);
1326 }
1327
1328 if (LOCKDOWN_E_SUCCESS == ret) {
1329 /* if everything went well, export in PEM format */
1330 key_data_t pem_root_cert = { NULL, 0 };
1331 key_data_t pem_host_cert = { NULL, 0 };
1332
1333 uret = userpref_device_record_get_certs_as_pem(udid, &pem_root_cert, &pem_host_cert, NULL);
1334 if (USERPREF_E_SUCCESS == uret) {
1335 /* copy buffer for output */
1336 membp = BIO_new(BIO_s_mem());
1337 if (membp && PEM_write_bio_X509(membp, dev_cert) > 0) {
1338 void *datap;
1339 odevice_cert->size = BIO_get_mem_data(membp, &datap);
1340 odevice_cert->data = malloc(odevice_cert->size);
1341 memcpy(odevice_cert->data, datap, odevice_cert->size);
1342 }
1343 if (membp)
1344 BIO_free(membp);
1345
1346 ohost_cert->data = malloc(pem_host_cert.size);
1347 memcpy(ohost_cert->data, pem_host_cert.data, pem_host_cert.size);
1348 ohost_cert->size = pem_host_cert.size;
1349
1350 oroot_cert->data = malloc(pem_root_cert.size);
1351 memcpy(oroot_cert->data, pem_root_cert.data, pem_root_cert.size);
1352 oroot_cert->size = pem_root_cert.size;
1353
1354 free(pem_root_cert.data);
1355 free(pem_host_cert.data);
1356 }
1357 }
1358 }
1359 X509V3_EXT_cleanup();
1360 X509_free(dev_cert);
1361
1362 switch(uret) {
1363 case USERPREF_E_INVALID_ARG:
1364 ret = LOCKDOWN_E_INVALID_ARG;
1365 break;
1366 case USERPREF_E_INVALID_CONF:
1367 ret = LOCKDOWN_E_INVALID_CONF;
1368 break;
1369 case USERPREF_E_SSL_ERROR:
1370 ret = LOCKDOWN_E_SSL_ERROR;
1371 default:
1372 break;
1373 }
1374
1375 if (root_cert.data)
1376 free(root_cert.data);
1377 if (host_cert.data)
1378 free(host_cert.data);
1379 if (root_privkey.data)
1380 free(root_privkey.data);
1381 if (host_privkey.data)
1382 free(host_privkey.data);
1383#else
1384 gnutls_datum_t modulus = { NULL, 0 };
1385 gnutls_datum_t exponent = { NULL, 0 };
1386
1387 /* now decode the PEM encoded key */
1388 gnutls_datum_t der_pub_key;
1389 if (GNUTLS_E_SUCCESS == gnutls_pem_base64_decode_alloc("RSA PUBLIC KEY", &public_key, &der_pub_key)) {
1390
1391 /* initalize asn.1 parser */
1392 ASN1_TYPE pkcs1 = ASN1_TYPE_EMPTY;
1393 if (ASN1_SUCCESS == asn1_array2tree(pkcs1_asn1_tab, &pkcs1, NULL)) {
1394
1395 ASN1_TYPE asn1_pub_key = ASN1_TYPE_EMPTY;
1396 asn1_create_element(pkcs1, "PKCS1.RSAPublicKey", &asn1_pub_key);
1397
1398 if (ASN1_SUCCESS == asn1_der_decoding(&asn1_pub_key, der_pub_key.data, der_pub_key.size, NULL)) {
1399
1400 /* get size to read */
1401 int ret1 = asn1_read_value(asn1_pub_key, "modulus", NULL, (int*)&modulus.size);
1402 int ret2 = asn1_read_value(asn1_pub_key, "publicExponent", NULL, (int*)&exponent.size);
1403
1404 modulus.data = gnutls_malloc(modulus.size);
1405 exponent.data = gnutls_malloc(exponent.size);
1406
1407 ret1 = asn1_read_value(asn1_pub_key, "modulus", modulus.data, (int*)&modulus.size);
1408 ret2 = asn1_read_value(asn1_pub_key, "publicExponent", exponent.data, (int*)&exponent.size);
1409 if (ASN1_SUCCESS == ret1 && ASN1_SUCCESS == ret2)
1410 ret = LOCKDOWN_E_SUCCESS;
1411 }
1412 if (asn1_pub_key)
1413 asn1_delete_structure(&asn1_pub_key);
1414 }
1415 if (pkcs1)
1416 asn1_delete_structure(&pkcs1);
1417 }
1418
1419 /* now generate certificates */
1420 if (LOCKDOWN_E_SUCCESS == ret && 0 != modulus.size && 0 != exponent.size) {
1421
1422 gnutls_global_init();
1423 gnutls_datum_t essentially_null = { (unsigned char*)strdup("abababababababab"), strlen("abababababababab") };
1424
1425 gnutls_x509_privkey_t fake_privkey, root_privkey, host_privkey;
1426 gnutls_x509_crt_t dev_cert, root_cert, host_cert;
1427
1428 gnutls_x509_privkey_init(&fake_privkey);
1429 gnutls_x509_privkey_init(&root_privkey);
1430 gnutls_x509_privkey_init(&host_privkey);
1431
1432 gnutls_x509_crt_init(&dev_cert);
1433 gnutls_x509_crt_init(&root_cert);
1434 gnutls_x509_crt_init(&host_cert);
1435
1436 if (GNUTLS_E_SUCCESS ==
1437 gnutls_x509_privkey_import_rsa_raw(fake_privkey, &modulus, &exponent, &essentially_null, &essentially_null,
1438 &essentially_null, &essentially_null)) {
1439
1440 uret = userpref_device_record_get_keys_and_certs(udid, root_privkey, root_cert, host_privkey, host_cert);
1441
1442 if (USERPREF_E_SUCCESS == uret) {
1443 /* generate device certificate */
1444 gnutls_x509_crt_set_key(dev_cert, fake_privkey);
1445 gnutls_x509_crt_set_serial(dev_cert, "\x00", 1);
1446 gnutls_x509_crt_set_version(dev_cert, 3);
1447 gnutls_x509_crt_set_ca_status(dev_cert, 0);
1448 gnutls_x509_crt_set_activation_time(dev_cert, time(NULL));
1449 gnutls_x509_crt_set_expiration_time(dev_cert, time(NULL) + (60 * 60 * 24 * 365 * 10));
1450
1451 /* use custom hash generation for compatibility with the "Apple ecosystem" */
1452 const gnutls_digest_algorithm_t dig_sha1 = GNUTLS_DIG_SHA1;
1453 size_t hash_size = gnutls_hash_get_len(dig_sha1);
1454 unsigned char hash[hash_size];
1455 if (gnutls_hash_fast(dig_sha1, der_pub_key.data, der_pub_key.size, (unsigned char*)&hash) < 0) {
1456 debug_info("ERROR: Failed to generate SHA1 for public key");
1457 } else {
1458 gnutls_x509_crt_set_subject_key_id(dev_cert, hash, hash_size);
1459 }
1460
1461 gnutls_x509_crt_set_key_usage(dev_cert, GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT);
1462 gnutls_x509_crt_sign(dev_cert, root_cert, root_privkey);
1463
1464 if (LOCKDOWN_E_SUCCESS == ret) {
1465 /* if everything went well, export in PEM format */
1466 size_t export_size = 0;
1467 gnutls_datum_t dev_pem = { NULL, 0 };
1468 gnutls_x509_crt_export(dev_cert, GNUTLS_X509_FMT_PEM, NULL, &export_size);
1469 dev_pem.data = gnutls_malloc(export_size);
1470 gnutls_x509_crt_export(dev_cert, GNUTLS_X509_FMT_PEM, dev_pem.data, &export_size);
1471 dev_pem.size = export_size;
1472
1473 gnutls_datum_t pem_root_cert = { NULL, 0 };
1474 gnutls_datum_t pem_host_cert = { NULL, 0 };
1475
1476 uret = userpref_device_record_get_certs_as_pem(udid, &pem_root_cert, &pem_host_cert, NULL);
1477
1478 if (USERPREF_E_SUCCESS == uret) {
1479 /* copy buffer for output */
1480 odevice_cert->data = malloc(dev_pem.size);
1481 memcpy(odevice_cert->data, dev_pem.data, dev_pem.size);
1482 odevice_cert->size = dev_pem.size;
1483
1484 ohost_cert->data = malloc(pem_host_cert.size);
1485 memcpy(ohost_cert->data, pem_host_cert.data, pem_host_cert.size);
1486 ohost_cert->size = pem_host_cert.size;
1487
1488 oroot_cert->data = malloc(pem_root_cert.size);
1489 memcpy(oroot_cert->data, pem_root_cert.data, pem_root_cert.size);
1490 oroot_cert->size = pem_root_cert.size;
1491
1492 gnutls_free(pem_root_cert.data);
1493 gnutls_free(pem_host_cert.data);
1494
1495 if (dev_pem.data)
1496 gnutls_free(dev_pem.data);
1497 }
1498 }
1499 }
1500
1501 switch(uret) {
1502 case USERPREF_E_INVALID_ARG:
1503 ret = LOCKDOWN_E_INVALID_ARG;
1504 break;
1505 case USERPREF_E_INVALID_CONF:
1506 ret = LOCKDOWN_E_INVALID_CONF;
1507 break;
1508 case USERPREF_E_SSL_ERROR:
1509 ret = LOCKDOWN_E_SSL_ERROR;
1510 default:
1511 break;
1512 }
1513 }
1514
1515 if (essentially_null.data)
1516 free(essentially_null.data);
1517 gnutls_x509_crt_deinit(dev_cert);
1518 gnutls_x509_crt_deinit(root_cert);
1519 gnutls_x509_crt_deinit(host_cert);
1520 gnutls_x509_privkey_deinit(fake_privkey);
1521 gnutls_x509_privkey_deinit(root_privkey);
1522 gnutls_x509_privkey_deinit(host_privkey);
1523
1524 }
1525
1526 gnutls_free(modulus.data);
1527 gnutls_free(exponent.data);
1528
1529 gnutls_free(der_pub_key.data);
1530#endif
1531 return ret;
1532}
1533
1534/**
1535 * Opens a session with lockdownd and switches to SSL mode if device wants it. 1223 * Opens a session with lockdownd and switches to SSL mode if device wants it.
1536 * 1224 *
1537 * @param client The lockdownd client 1225 * @param client The lockdownd client
@@ -1569,7 +1257,7 @@ lockdownd_error_t lockdownd_start_session(lockdownd_client_t client, const char
1569 1257
1570 /* add system buid */ 1258 /* add system buid */
1571 char *system_buid = NULL; 1259 char *system_buid = NULL;
1572 userpref_get_system_buid(&system_buid); 1260 userpref_read_system_buid(&system_buid);
1573 if (system_buid) { 1261 if (system_buid) {
1574 plist_dict_set_item(dict, "SystemBUID", plist_new_string(system_buid)); 1262 plist_dict_set_item(dict, "SystemBUID", plist_new_string(system_buid));
1575 if (system_buid) { 1263 if (system_buid) {
@@ -1671,8 +1359,14 @@ lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char
1671 (*service)->ssl_enabled = 0; 1359 (*service)->ssl_enabled = 0;
1672 } 1360 }
1673 1361
1362 plist_t pair_record = NULL;
1363 userpref_read_pair_record(client->udid, &pair_record);
1364
1674 char *host_id = NULL; 1365 char *host_id = NULL;
1675 userpref_device_record_get_host_id(client->udid, &host_id); 1366 pair_record_get_host_id(pair_record, &host_id);
1367
1368 plist_free(pair_record);
1369
1676 if (!host_id) 1370 if (!host_id)
1677 return LOCKDOWN_E_INVALID_CONF; 1371 return LOCKDOWN_E_INVALID_CONF;
1678 1372
diff --git a/src/lockdown.h b/src/lockdown.h
index 9c2be44..a09e89b 100644
--- a/src/lockdown.h
+++ b/src/lockdown.h
@@ -22,8 +22,6 @@
22#ifndef __LOCKDOWND_H 22#ifndef __LOCKDOWND_H
23#define __LOCKDOWND_H 23#define __LOCKDOWND_H
24 24
25#include "common/userpref.h"
26
27#include "libimobiledevice/lockdown.h" 25#include "libimobiledevice/lockdown.h"
28#include "property_list_service.h" 26#include "property_list_service.h"
29 27
@@ -37,7 +35,4 @@ struct lockdownd_client_private {
37 char *label; 35 char *label;
38}; 36};
39 37
40lockdownd_error_t lockdownd_get_device_public_key(lockdownd_client_t client, key_data_t * public_key);
41lockdownd_error_t lockdownd_gen_pair_cert_for_udid(const char *udid, key_data_t public_key, key_data_t * device_cert, key_data_t * host_cert, key_data_t * root_cert);
42
43#endif 38#endif
diff --git a/tools/idevicepair.c b/tools/idevicepair.c
index 91ed49b..5af95f0 100644
--- a/tools/idevicepair.c
+++ b/tools/idevicepair.c
@@ -134,7 +134,7 @@ int main(int argc, char **argv)
134 134
135 if (op == OP_SYSTEMBUID) { 135 if (op == OP_SYSTEMBUID) {
136 char *systembuid = NULL; 136 char *systembuid = NULL;
137 userpref_get_system_buid(&systembuid); 137 userpref_read_system_buid(&systembuid);
138 138
139 printf("%s\n", systembuid); 139 printf("%s\n", systembuid);
140 140
@@ -184,14 +184,20 @@ int main(int argc, char **argv)
184 } 184 }
185 185
186 if (op == OP_HOSTID) { 186 if (op == OP_HOSTID) {
187 plist_t pair_record = NULL;
187 char *hostid = NULL; 188 char *hostid = NULL;
188 userpref_device_record_get_host_id(udid, &hostid); 189
190 userpref_read_pair_record(udid, &pair_record);
191 pair_record_get_host_id(pair_record, &hostid);
189 192
190 printf("%s\n", hostid); 193 printf("%s\n", hostid);
191 194
192 if (hostid) 195 if (hostid)
193 free(hostid); 196 free(hostid);
194 197
198 if (pair_record)
199 plist_free(pair_record);
200
195 return EXIT_SUCCESS; 201 return EXIT_SUCCESS;
196 } 202 }
197 203
@@ -254,7 +260,7 @@ int main(int argc, char **argv)
254 lerr = lockdownd_unpair(client, NULL); 260 lerr = lockdownd_unpair(client, NULL);
255 if (lerr == LOCKDOWN_E_SUCCESS) { 261 if (lerr == LOCKDOWN_E_SUCCESS) {
256 /* also remove local device record */ 262 /* also remove local device record */
257 userpref_remove_device_record(udid); 263 userpref_delete_pair_record(udid);
258 printf("SUCCESS: Unpaired with device %s\n", udid); 264 printf("SUCCESS: Unpaired with device %s\n", udid);
259 } else { 265 } else {
260 result = EXIT_FAILURE; 266 result = EXIT_FAILURE;